View Source Circuits.GPIO (circuits_gpio v2.1.0)

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

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

Types

@type backend() :: {module(), keyword()}

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:

  1. 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.
  2. {controller_name, line_offset} - Specify a line on a specific GPIO controller. E.g., {"gpiochip0", 10}
  3. 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"
  4. {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 to GPIO.open/3.
  • :controller - the name or an alias for the GPIO controller. Empty string if unused
@type interrupt_options() :: [suppress_glitches: boolean(), receiver: pid() | atom()]

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

@type status() :: %{
  consumer: String.t(),
  direction: direction(),
  pull_mode: pull_mode()
}

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

Link to this function

backend_info(backend \\ nil)

View Source
@spec backend_info(backend() | nil) :: map()

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.

Link to this function

enumerate(backend \\ nil)

View Source
@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.

@spec gpio_spec?(any()) :: boolean()

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.

Link to this macro

is_gpio_spec(x)

View Source (macro)

Guard version of gpio_spec?/1

Add require Circuits.GPIO to your source file to use this guard.

Link to this function

open(gpio_spec_or_line_info, direction, options \\ [])

View Source
@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 or 1. Only used for outputs. Defaults to 0.
  • :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.

Link to this function

read_one(gpio_spec, options \\ [])

View Source
@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.

Link to this function

set_direction(handle, direction)

View Source
@spec set_direction(Circuits.GPIO.Handle.t(), direction()) :: :ok | {:error, atom()}

Change the direction of the pin

Link to this function

set_interrupts(handle, trigger, options \\ [])

View Source
@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.

Link to this function

set_pull_mode(gpio, pull_mode)

View Source
@spec set_pull_mode(Circuits.GPIO.Handle.t(), pull_mode()) :: :ok | {:error, atom()}

Enable or disable an internal pull-up or pull-down resistor

@spec status(gpio_spec()) :: {:ok, status()} | {:error, atom()}

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.

Link to this function

write_one(gpio_spec, value, options \\ [])

View Source
@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.