Some background:
I have an i2c device (MCP23017), which has 6 switches connected to its GPIO ports. The MCP23017 is connected to a Raspberry Pi via i2c.
I'm able to read the state of each of the switches as required.
My issue is in regards to interrupts. I'm using the WiringPi2 library for Python, which allows me to interface with the MCP23017 under Python. From the research I've done, the WiringPiISR library allows for i2c interrupt protocols to be run, although it only seems to work (properly) under C.
My question is this: is there a simple solution for implementing i2c interrupts under Python?
I'm considering dropping Python for C for this particular project, but the GUI interface has already been written (in Python), so I'd like to keep that as a last option.
Any guidance/input/comments would be greatly appreciated!
Thanks!
As far as I understand, WiringPiISR library only allows you to configure a Pin to be an interrupt and define its type (ie, edge based or level based). Since you're talking about I2c interrupt, there is no way you can have I2C interrupt as in this case, Your Rpi works as a master device and other connected device(s) as slave(s). Since in I2C, communication is always initiated by the master, slaves can not interrupt you. (at least not via I2C channel)
Hope it helps.
There are devices that have an interrupt line in addition to I2C lines. For example I have a rotary encoder I2C interface board from duppa.net which has 5 pins - SDA, SCL, +, - and interrupt.
The python library that comes with it configures the Raspberry Pi GPIO 4 line as an input edge triggered interrupt and sets up callbacks. On a change (the rotary encoder is rotated for instance) the interrupt line wiggles, the interrupt handler reads the status register over I2C and calls the appropriate callback.
So this is completely conventional interrupt usage in the context of I2C doing to usual task of freeing the master from having to poll the bus.
Related
I'm trying to get a raspberry scanning for Bluetooth devices using Bluez 5.61.
I need this raspberry to be able to detect when a Bluetooth device (here, another Raspberry also using Bluez) cannot be detected anymore.
I was thinking using InterfacesRemoved signal from dbus but I guess I don't understand properly how it works as it's never called.
My questions:
I'm not sure I understand properly what interfacesAdded and interfacesRemoved are used for as they are rarely called when expected (propertiesChanged works fine)
Is it possible to get a signal for each advertisement message received even if the content has not changed since the last one? That would allow me to set up a timer to trigger the "non detectable anymore" event.
Here is the code I use to register my signals:
self.bus.add_signal_receiver(
self._interfaces_added,
dbus_interface=common.OBJECT_MANAGER,
signal_name="InterfacesAdded")
self.bus.add_signal_receiver(
self._interfaces_removed,
dbus_interface=common.OBJECT_MANAGER,
signal_name="InterfacesRemoved")
self.bus.add_signal_receiver(
self._properties_changed,
dbus_interface=common.DBUS_PROP_IFACE,
signal_name="PropertiesChanged",
arg0=common.DEVICE_INTERFACE,
path_keyword="path")
I am controlling the GPIO pins of a Raspberry Pi over a WiFi network from a control device (in this case a Linux laptop), which is running a Python programme that uses the gpiozero library's Remote GPIO feature to control the pins.
In the event that the WiFi connection between the control device and the Raspberry Pi is severed, I want to be able to detect that this has happened so that I can take measures to ensure that the programme on the control device does not lock up.
To give an example of the most likely scenario, let's say that the robot the Raspberry Pi is installed in drives out of WiFi range.
The function that I am using to quit the control device programme is set up to automatically tell tell the robot to stop moving before quitting the programme. This is done by setting the values on the GPIO pins that connect to the motor driver.
Problem is, when I simulate a connection break by turning off the WiFi on the Raspberry Pi, if I then click on the quit button on the control device programme, the code execution just seems to stop at the point where it is trying to set the relevant GPIO pins to stop the robot's motors.
My suspicion is that the control device programme is just waiting forever for a socket response that will never come.
In order to address this problem, can anyone give me advice on doing any of the following:
Detecting when the connection between the control device is cut, and running a function in response.
Setting a timeout on the Remote GPIO connection, which I can then catch with a try statement.
Any other fix you think might work (please give details).
Thanks.
So I am working on a project that has a Raspberry Pi connected to a Serial Device via a USB to Serial Connector. I am trying to use PySerial to track the data being sent over the connected Serial device, however there is a problem.
Currently, I have my project set up so that every 5 seconds it calls a custom port.open() method I have created, which returns True if the port is actually open. This is so that I don't have to have the Serial Device plugged in when I initially go to start the program.
However I'd also like to set it up so that the program can also detect when my serial device is disconnected, and then reconnected. But I am not sure how to accomplish this.
If I attempt to use the PySerial method isOpen() to check if the device is there, I am always having it return true as long as the USB to Serial connector is plugged in, even if I have no Serial device hooked up to the connector itself.
You might be able to tell whether the device is physically plugged in by checking the status of one of the RS232 control lines - CTS, DSR, RI, or CD (all of which are exposed as properties in PySerial). Not all USB-serial adapters support any of these.
If the only connection to the device is the TX/RX lines, your choices are extremely limited:
Send a command to the device and see if it responds. Hopefully its protocol includes a do-nothing command for this purpose.
If the device sends data periodically without needing an explicit command, save a timestamp whenever data is received, and return False if it's been significantly longer than the period since the last reception.
Using the ADAFRUIT_DHT python library from https://github.com/adafruit/Adafruit_Python_DHT and a DHT22 temp/humidity sensor (https://www.adafruit.com/products/393) I'm able to easily read temperature and humidity values.
The problem is, that I need to run my script as root, in order to interact with the GPIO pins. This is simply not possible, when running my script through a website, via wsgi, as apache will not let me (for good reason) set the WSGIDaemonProcess's user to root.
I've got pigpiod running which allows me to interact with the GPIO through it, as a non-root user, however, the ADAFRUIT_DHT doesn't go through the daemon, and interacts directly with the GPIO. I'm not 100% sure the pigpio daemon would be fast enough for the bit-banging, required to decode the response from the DHT22 unit, but, perhaps.
So, is there a way for me to coerce the ADAFRUIT_DHT library to not require being run as root, or, are there alternatives to the library available that might accomplish what I'm looking for?
Create a small server that runs as root and listens on a local Unix or TCP socket. When another process connects, your server reads the data from sensor and returns it.
Now your WSGI process only needs permissions to connect to the listening socket, which can be easily managed either via permissions on a Unix socket, or simply throwing access control to the wind and opening a TCP socket bound to the localhost address (so that only processes on the local machine can connect).
There are several advantages to doing this...for example, you can now have multiple programs consuming the temperature data at the same time, and not need to worry about device contention (because only the temperature server is actually reading the data). You can even implement short-term caching to provide faster responses.
Also, note that there is a raspberry pi specific stackexchange.
pigpio can certainly read the DHT11/22 etc. sensors.
There are two examples using the daemon (which means root privileges are not required).
DHT11/21/22/33/44 Sensor written in C which auto detects the model.
DHT22 written in Python which only handles the DHT22 (the github has a DHT11 example).
Both examples are likely to give reliable results (read error rates of better than 1 in 10 thousand rather than worse than 1 in 10).
I am looking for a simple means of triggering my data acquisition software using an external TTL pulse. I need to sample data from multiple sources synchronously with a 5 Hz reference clock. The acquisition does not need real-time priority but I want to ensure that my software is triggered as soon as possible and exactly once per external clock cycle. I would prefer to do this by somehow getting an interrupt from the external trigger without needing to use a fast polling loop. As far as I can tell, you can't just use a parallel port pin for an interrupt in a modern OS like Linux. Any ideas?
I am also thinking of generating broadcast packets on my network to notify other machines on the network that a trigger event has occurred. Due to network latency however there may not be enough time available in the 200ms period between triggers to do the acquisition.
Rather than use the parallel port, have you considered using a serial device? Since you have a TTL signal, you'll possibly need a level converter to convert TTL to RS232 +/- 12V levels. Once you're using a serial device, you can use the standard serial ioctl() calls to detect a change in control signal status.
Specifically, you could use the TIOCMIWAIT ioctl on the connected serial device to wait for a change on say the DCD line, which you would connect to your clock source.
Your user space application would be blocked waiting in the TIOCMIWAIT ioctl system call until there is a change of status on your clock line, at which point your app would become runnable and return from the ioctl. You might have to take care to ensure that you handle the case where you get a change of status interrupt on both rising and falling edges of your serial control signals. On some UART hardware (eg TL16C554A UART) it's possible that you'll only get an interrupt for a signal transitioning in a single direction. For the TL16C554A for example, the TIOCMIWAIT would only fall through on the rising edge of any Ring Indicate signal change.
Using the serial ioctls in this manner also has the advantage that you could use a USB-Serial dongle that supports TIOCMIWAIT if required (eg PL2303), and still retain user level software compatibility, albeit at the expense of increased latency due to USB.
If you require lower latency than can be achieved through user space, you'd be best to write a kernel driver module which can handle the timing and sampling, but I wouldn't suggest this route unless absolutely needed. It's easier to develop user space code.
Here's some incomplete sample C code snippets for using the TIOCMIWAIT ioctl.
int serial_fd = open(cmdline.device_name, O_RDWR | O_NONBLOCK | O_NOCTTY);
static const unsigned int ri_flag = TIOCM_RNG;
/* Set up serial port here using tcsetattr. Set CRTSCTS | CLOCAL to ensure status interrupts
* are generated.
*/
while (1) {
/* Wait for positive RI transition. TIOCMIWAIT takes a mask
* as argument, only returning when the appropriate signal has changed.
*/
if (ioctl(serial_fd, TIOCMIWAIT, ri_flag)) {
fprintf(stderr, "ioctl() failed waiting for RI edge [%s]\n", strerror(errno));
break;
}
/* Do sensor sampling here. You could use TIOCMGET to first verify that
* the clock line is in the expected state, eg high, before continuing.
*/
}
Polling is a fine method for such a slow data rate. Poll at 1 ms. That should be fine. Trying to use a hardware interrupt is going to cause much pain.
Google for "Interrupt Linux GPIO" if you want to do it the hard way. :)
https://developer.ridgerun.com/wiki/index.php/How_to_use_GPIO_signals
Consider connecting the external pulse source to the 'CD' ping of a real (! not a USB to RS232 converter) serial port. Then you can use the "PPS api" to get an as exact timestamp from which the pin "went high" as possible.
You might need a TTL signal shifter; not all serial ports work correctly with TTL signal levels.
The PPS api is normally used for time keeping. E.g. connect the PPS pin of a GPS module to your pc and let NTP sync with that. This gives you microsecond accuracy.
This PPS api is supposed to be more accurate than any other userspace solution (e.g. the TIOCMIWAIT ioctl) as it is completely handled in the kernel, immediately when the interrupt (as triggered by the CD signal change) comes in. With the ioctl solution you have at least a context switch. I did some testing on a raspberry pi and a userspace solution gives at least 6us jitter.
The PPS api gives you a timestamp from when the pulse was detected.
Why not use a USB to RS232 converter: I read somewhere (in relation to timekeeping) that USB devices are polled once every +/- 1ms. This polling frequency also depends on how busy the system is with other USB devices and I think the internal clock of the USB device may also influence things. I've never measured this though.
Relevant URLS:
https://www.rfc-editor.org/rfc/rfc2783 RFC describing the PPS API
http://linuxpps.org/ Linux implementation the PPS API (it is in the standard kernel)
http://comments.gmane.org/gmane.comp.hardware.gps.gpsd.user/3747 a thread which mentions why not to use USB for timekeeping
Regarding the network functionality: use UDP broadcasts, do not use TCP.
I ended up using the serial port CTS line for the trigger using the TIOCMIWAIT ioctl per Austin Phillips answer. Since RS232 requires +/-12V levels I was able to get the necessary power for this level shifter from the other serial control lines.
The Python code to implement this solution can be found in question: Python monitor serial port (RS-232) handshake signals