DEPRECATED - use https://github.com/elixir-circuits/circuits_gpio
This is a special edition of the GPIO part of the fantastic elixir_ale library maintained by Frank Hunleth. It contains some additions that are only available on Raspberry Pi.
gpio_rpi
provides high level abstractions for interfacing to GPIOs on Raspberry PI platforms.
gpio_rpi
works great with LEDs, buttons, many kinds of sensors, and simple
control of motors. In general, if a device requires high speed transactions or
has hard real-time constraints in its interactions, this is not the right
library. For those devices, it is recommended to look at other driver options, such
as using a Linux kernel driver.
If you're natively compiling gpio_rpi, everything should work like any other
Elixir library. Normally, you would include gpio_rpi as a dependency in your
mix.exs
like this:
defp deps do
[{:gpio_rpi, "~> 0.2.2"}]
end
If you just want to try it out, you can do the following:
git clone https://github.com/Hermanverschooten/gpio_rpi.git
cd gpio_rpi
mix deps.get
mix compile
iex -S mix
If you're cross-compiling, you'll need to setup your environment so that the
right C compiler is called. See the Makefile
for the variables that will need
to be overridden. At a minimum, you will need to set CROSSCOMPILE
,
ERL_CFLAGS
, and ERL_EI_LIBDIR
.
If you're trying to compile on a Raspberry Pi and you get errors indicated that Erlang headers are missing
(ie.h
), you may need to install erlang with apt-get install erlang-dev
or build Erlang from source per instructions here.
A GPIO is just a wire that you can use as an input or an output. It can only be one of two values, 0 or 1. A 1 corresponds to a logic high voltage like 3.3 V and a 0 corresponds to 0 V. The actual voltage depends on the hardware.
Here's an example setup:
To turn on the LED that's connected to the net labelled
PI_GPIO18
, you can run the following:
iex> {:ok, pid} = GpioRpi.start_link(18, :output)
{:ok, #PID<0.96.0>}
iex> GpioRpi.write(pid, 1)
:ok
Input works similarly:
iex> {:ok, pid} = GpioRpi.start_link(17, :input)
{:ok, #PID<0.97.0>}
iex> GpioRpi.read(pid)
0
# Push the button down
iex> GpioRpi.read(pid)
1
If you'd like to get a message when the button is pressed or released, call the
set_int
function. You can trigger on the :rising
edge, :falling
edge or
:both
.
iex> GpioRpi.set_int(pid, :both)
:ok
iex> flush
{:gpio_interrupt, 17, :rising}
{:gpio_interrupt, 17, :falling}
:ok
Note that after calling set_int
, the calling process will receive an initial message with the state of the pin.
This prevents the race condition between getting the initial state of the pin and turning on interrupts. Without it, you could get the state of the pin, it could change states, and then you could start waiting on it for interrupts. If that happened, you would be out of sync.
If you need to change the pull-up register on your RPI, you can use set_mode
, it takes either :up, :down or :none.
iex> GpioRpi.set_mode(pid, :up)
:ok
Most issues people have are on how to communicate with hardware for the first
time. Since gpio_rpi
is a thin wrapper on the Linux sys class interface, you
may find help by searching for similar issues when using Python or C.
For help specifically with gpio_rpi
, you may also find help on the
nerves channel on the elixir-lang Slack.
Many Nerves users also use gpio_rpi
.
While gpio_rpi
should never crash, it's hard to guarantee that weird
conditions, wouldn't hang the Erlang VM. gpio_rpi
errors on the side of safety of the VM.
Please don't do that - there are so many better ways of addressing whatever you're trying to do:
- If you're trying to drive a servo or dim an LED, look into PWM. Many platforms have PWM hardware and you won't tax your CPU at all. If your platform is missing a PWM, several chips are available that take I2C commands to drive a PWM output.
- If you need to implement a wire level protocol to talk to a device, look for a Linux kernel driver. It may just be a matter of loading the right kernel module.
- If you want a blinking LED to indicate status,
gpio_rpi
really should be fast enough to do that, but check out Linux's LED class interface. Linux can flash LEDs, trigger off events and more. See nerves_leds.
If you're still intent on optimizing GPIO access, you may be interested in gpio_twiddler.
Somewhere in the future.
Yes, I provided a dummy library that should be code-compatible. In your code, you can replace alias the dummy lib in dev
defmodule SomeGpioUser do
if Mix.env == :dev do
alias DummyGpioRpi, as: GpioRpi
end
...
The most common issue is getting connected to a part the first time. If you're
having trouble, check that the device files exist in /sys/class/gpio
.
Yes! If your life has been improved by gpio_rpi
and you want to give back,
it would be great to have new energy put into this project. Please email me.
The easiest way is to add it to your mix file, and subsequently alias it in your code.
defmodule SomeGpioUser do
alias GpioRpi, as: Gpio
...
Or you can just find/replace all Gpio with GpioRpi.
There is much confusion in the Raspberry PI world concerning the numbering of the GPIO pins. I use the Broadcom (BCM) numbering schema, as this is the closest thing to the machine. You can find more info on the numbering at https://pinout.xyz
This library draws much of its design and code from the elixir_ale project which is licensed under the Apache License, Version 2.0. As such, it is licensed similarly.