View Source Circuits.GPIO (circuits_gpio v2.1.2)
Control GPIOs from Elixir
See the Readme for a tutorial and the porting guide if updating from Circuits.GPIO v1.x.
Simple example:
# GPIO 2 is connected to GPIO 3
iex> {:ok, my_output_gpio} = Circuits.GPIO.open({"gpiochip0", 2}, :output)
iex> {:ok, my_input_gpio} = Circuits.GPIO.open({"gpiochip0", 3}, :input)
iex> Circuits.GPIO.write(my_output_gpio, 1)
:ok
iex> Circuits.GPIO.read(my_input_gpio)
1
iex> Circuits.GPIO.close(my_output_gpio)
iex> Circuits.GPIO.close(my_input_gpio)
Summary
Types
Backends specify an implementation of a Circuits.GPIO.Backend behaviour
GPIO controller
The GPIO direction (input or output)
An identifier for a GPIO
Ways of referring to a GPIO
Options for set_interrupt/2
A GPIO controller label or GPIO label
GPIO line offset on a controller
Options for open/3
Pull mode for platforms that support controllable pullups and pulldowns
Dynamic GPIO configuration and status
Trigger edge for pin change notifications
GPIO logic value (low = 0 or high = 1)
Functions
Return info about the low level GPIO interface
Release the resources associated with a GPIO
Return a list of accessible GPIOs
Return if a term looks like a gpio_spec
Return indentifying information about a GPIO
Guard version of gpio_spec?/1
Read a GPIO's value
One line GPIO read
Change the direction of the pin
Enable or disable GPIO value change notifications
Enable or disable an internal pull-up or pull-down resistor
Return dynamic configuration and status information about a GPIO
Set the value of a GPIO
One line GPIO write
Types
Backends specify an implementation of a Circuits.GPIO.Backend behaviour
The second parameter of the Backend 2-tuple is a list of options. These are passed to the behaviour function call implementations.
@type controller() :: String.t()
GPIO controller
GPIO controllers manage one or more GPIO lines. They're referred to by
strings. For example, controllers are named "gpiochip0"
, etc. for the
Linux cdev backend. Other backends may have similar conventions or use
the empty string if there's only one controller.
@type direction() :: :input | :output
The GPIO direction (input or output)
@type gpio_spec() :: non_neg_integer() | {controller(), line_offset()} | label() | {controller(), label()}
An identifier for a GPIO
Call Circuits.GPIO.enumerate/0
to see what GPIOs are available on your
device. Several ways exist to refer to GPIOs due to variations in devices and
programmer preference. Most Raspberry Pi models have labels like "GPIO26"
.
The Raspberry Pi 5 has labels based on physical location (e.g., "PIN37"
for
GPIO 26.)
Options:
index
- Many examples exist where GPIOs are referred to by a GPIO number. There are issues with this strategy since GPIO indices can change. It is so common that it's still supported. Prefer other ways when you're able to change code.{controller_name, line_offset}
- Specify a line on a specific GPIO controller. E.g.,{"gpiochip0", 10}
label
- Specify a GPIO label. The first controller that has a matching GPIO is used. This lets you move the mapping of GPIOs to peripheral connections to a device tree file or other central place. E.g.,"LED_ENABLE"
{controller_name, label}
- Specify both GPIO controller and GPIO labels. E.g.,{"gpiochip4", "PIO4"}
@type identifiers() :: %{ location: {controller(), non_neg_integer()}, controller: controller(), label: label() }
Ways of referring to a GPIO
It's possible to refer to a GPIOs in many ways and this map contains
information for doing that. See enumerate/1
and identifiers/1
for
querying Circuits.GPIO
for these maps.
The information in this map is backend specific. At a minimum, all backends
provide the :location
field which is an unambiguous gpio_spec/0
for use
with open/3
.
When provided, the :label
field is a string name for the GPIO that should
be unique to the system but this isn't guaranteed. A common convention is to
label GPIOs by their pin names in documentation or net names in schematics.
The Linux cdev backend uses labels from the device tree file.
Fields:
:location
- this is the canonical gpio_spec for a GPIO.:label
- an optional label for the GPIO that may indicate what the GPIO is connected to or be more helpful that the:location
. It may be passed toGPIO.open/3
.:controller
- the name or an alias for the GPIO controller. Empty string if unused
Options for set_interrupt/2
@type label() :: String.t()
A GPIO controller label or GPIO label
Labels provide aliases for GPIO lines and controllers. They're system-specific. On Linux, labels are provided in device tree files.
@type line_offset() :: non_neg_integer()
GPIO line offset on a controller
GPIOs are numbered based on how they're connected to a controller. The
details are controller specific, but usually the first one is 0
, then 1
,
etc.
@type open_options() :: [ initial_value: value(), pull_mode: pull_mode(), force_enumeration: boolean() ]
Options for open/3
:initial_value
- the initial value of an output GPIO:pull_mode
- the initial pull mode for an input GPIO:force_enumeration
- Linux cdev-specific option to force a scan of available GPIOs rather than using the cache. This is only for test purposes since the GPIO cache should rescan as needed.
@type pull_mode() :: :not_set | :none | :pullup | :pulldown
Pull mode for platforms that support controllable pullups and pulldowns
Dynamic GPIO configuration and status
Fields:
:consumer
- if this GPIO is in use, this optional string gives a hint as to who is using it.:direction
- whether this GPIO is an input or output:pull_mode
- if this GPIO is an input, then this is the pull mode
@type trigger() :: :rising | :falling | :both | :none
Trigger edge for pin change notifications
@type value() :: 0 | 1
GPIO logic value (low = 0 or high = 1)
Functions
Return info about the low level GPIO interface
This may be helpful when debugging issues.
@spec close(Circuits.GPIO.Handle.t()) :: :ok
Release the resources associated with a GPIO
This is optional. The garbage collector will free GPIO resources that aren't in use, but this will free them sooner.
@spec enumerate(backend() | nil) :: [identifiers()]
Return a list of accessible GPIOs
Each GPIO is described in a identifiers/0
map. Some fields in the map like
:location
and :label
may be passed to open/3
to use the GPIO. The map
itself can also be passed to open/3
and the function will figure out how to
access the GPIO.
Return if a term looks like a gpio_spec
This function only verifies that the term has the right shape to be a
gpio_spec/0
. Whether or not it refers to a usable GPIO is checked by
Circuits.GPIO.open/3
.
@spec identifiers(gpio_spec()) :: {:ok, identifiers()} | {:error, atom()}
Return indentifying information about a GPIO
See gpio_spec/0
for the ways of referring to GPIOs. If the GPIO is found,
this function returns information about the GPIO.
Guard version of gpio_spec?/1
Add require Circuits.GPIO
to your source file to use this guard.
@spec open(gpio_spec() | identifiers(), direction(), open_options()) :: {:ok, Circuits.GPIO.Handle.t()} | {:error, atom()}
Open a GPIO
See gpio_spec/0
for the ways of referring to GPIOs. Set direction
to
either :input
or :output
. If opening as an output, then be sure to set
the :initial_value
option to minimize the time the GPIO is in the default
state.
If you're having trouble, see enumerate/0
for available GPIOs. If you
suspect a hardware or driver issue, see Circuits.GPIO.Diagnostics
.
Options:
- :initial_value - Set to
0
or1
. Only used for outputs. Defaults to0
. - :pull_mode - Set to
:not_set
,:pullup
,:pulldown
, or:none
for an input pin.:not_set
is the default.
Returns {:ok, handle}
on success.
@spec read(Circuits.GPIO.Handle.t()) :: value()
Read a GPIO's value
The value returned for GPIO's that are configured as outputs is undefined. Backends may choose not to support this.
@spec read_one(gpio_spec(), open_options()) :: value() | {:error, atom()}
One line GPIO read
This is a convenience function that opens, reads, and closes a GPIO. It's intended to simplify one-off reads in code and for IEx prompt use.
Prefer using handles in other situations.
@spec set_direction(Circuits.GPIO.Handle.t(), direction()) :: :ok | {:error, atom()}
Change the direction of the pin
@spec set_interrupts(Circuits.GPIO.Handle.t(), trigger(), interrupt_options()) :: :ok | {:error, atom()}
Enable or disable GPIO value change notifications
Notifications are sent based on the trigger:
:none
- No notifications are sent:rising
- Send a notification when the pin changes from 0 to 1:falling
- Send a notification when the pin changes from 1 to 0:both
- Send a notification on all changes
Available Options:
:suppress_glitches
- Not supported in Circuits.GPIO v2:receiver
- Process which should receive the notifications. Defaults to the calling process (self()
)
Notification messages look like:
{:circuits_gpio, gpio_spec, timestamp, value}
Where gpio_spec
is the gpio_spec/0
passed to open/3
, timestamp
is an OS
monotonic timestamp in nanoseconds, and value
is the new value.
Timestamps are not necessarily the same as from System.monotonic_time/0
.
For example, with the cdev backend, they're applied by the Linux kernel or
can be come from a hardware timer. Erlang's monotonic time is adjusted so
it's not the same as OS monotonic time. The result is that these timestamps
can be compared with each other, but not with anything else.
NOTE: You will need to store the Circuits.GPIO
reference somewhere (like
your GenServer
's state) so that it doesn't get garbage collected. Event
messages stop when it gets collected. If you only get one message and you are
expecting more, this is likely the case.
@spec set_pull_mode(Circuits.GPIO.Handle.t(), pull_mode()) :: :ok | {:error, atom()}
Enable or disable an internal pull-up or pull-down resistor
Return dynamic configuration and status information about a GPIO
See gpio_spec/0
for the ways of referring to GPIOs. If the GPIO is found,
this function returns information about the GPIO.
@spec write(Circuits.GPIO.Handle.t(), value()) :: :ok
Set the value of a GPIO
The GPIO must be configured as an output.
@spec write_one(gpio_spec(), value(), open_options()) :: :ok | {:error, atom()}
One line GPIO write
This is a convenience function that opens, writes, and closes a GPIO. It's intended to simplify one-off writes in code and for IEx prompt use.
Prefer using handles in other situations.