Is it possible to handle hardware interrupts from Elixir?
I ask because I need to respond to a button press. If I was coding to bare metal I would write an ISR, but of course there is BEAM sitting on Debian. If I can’t do an ISR can I have a process block until the hardware changes?
Short: No you can’t.
Longer: you might be able to achieve your goal using ports and cports. External programs that can be written in any language and communicate with the BEAM. You can read these messages as if they were from another process using a receive block.
I do not think that you can use NIFs properly here.
Also, since I’m on a mobile I can’t search appropriate links right now.
Thanks for the reply and info @NobbZ. What is an NIF?
Natively implemented function.
When sitting in user-space on a Linux system, I think GPIO sysfs is the way to go about it.
elixir_ale provides a nice Elixir abstraction on top of GPIO sysfs. I haven’t had time to play around with it yet, but from its documentation and the example it looks fairly straight forward.
The elixir_ale solution seems to be exactly what I need. It’s a soft real time system so I don’t need to process the interrupt the microsecond it is triggered. As long as I get it within say 100 or 200 ms that will do very well.
I really miss Node,js events
In the latest ElixirALE.I2C is it possible (at all) to set up an async. message on a hardware interrupt ?
 My platform is RaspberryPi 3 B+ with Nerves package
nerves_system_rpi3 providing Linux 4.14.71
Oh, did you mean specifically send an async message when you receive a certain I2C message? For that, I think you’d want to set up your own worker that polls for I2C data and sends them as messages on whatever conditions you need.
I think that John is connecting his Pi to a chip that has an I2C interface and a separate interrupt signal that notifies the Pi when data is ready. Lots of chips do that since I2C doesn’t support async notifications. The pattern is to use
ElixirALE.GPIO to detect the interrupt and send a message. Then in the message handler function, call into
ElixirALE.I2C to read the new data.
Just as an aside, it would be cool if
ElixirALE.I2C could do this for you. The problem is that the command you send to read the chip on interrupt depends on the chip. The updated I2C protocol, I3C, lets devices send interrupts w/o a separate GPIO, so it should be possible to do something nicer when it becomes available.
Thanks for those helpful comments. I did think about my situation more thoroughly last night and I realized that the ElixirALE.GPIO port converts pin state changes to messages, and my I2C chip (LPS25HB sensor) could be wired to a dedicated GPIO pin for that purpose.
Under the hood, on the RPi3B+, how do GPIO interrupts reach the ALE GPIO Port process ? Signals or OS Events ?
Regarding how GPIO interrupts get to ElixirALE, ElixirALE blocks on the poll(2) system call on a special file under the /sysfs directory. When the GPIO pin changes, the poll call unblocks. That’s documented here: https://github.com/raspberrypi/linux/blob/rpi-4.14.y/Documentation/gpio/sysfs.txt#L75-L83.
As for how Linux knows to update that file, that’s documented in the GPIO section of the processor’s datasheet here: https://github.com/raspberrypi/documentation/blob/master/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf. It looks like the code of interest is here: https://github.com/raspberrypi/linux/blob/rpi-4.14.y/drivers/pinctrl/bcm/pinctrl-bcm2835.c#L387. At the very least, you can see how all GPIO pins share 2 or 3 interrupt lines inside the processor, so Linux has to figure out what happened whenever one changes.
I think that your barometer should fine since it doesn’t sound like it has a high interrupt rate. I’m not sure what the real threshold is, but if I were looking at a >100Hz interrupt rate, I’d look at alternatives to handling the interrupts with ElixirALE.
Wow ! (-: That’s one generous and useful reply, Thank you Frank !
You’re correct, too . . the output data rate of that pressure and temperature sensor is 25 Hz max.