Circuits.GPIO.Chip (circuits_cdev v0.1.0) View Source

Control GPIOs using the GPIO chip interface

With the character device driver for GPIOs there three concepts to learn.

First, the API is made up of chips and lines that are grouped together for that chip. A chip is more of a grouping identifier than anything physical property about the board.

Secondly, the API requires us to request lines from a GPIO chip. The reason for this is the kernel can provide control over who "owns" that line and prevent multiple programs from trying to control the same GPIO pin.

Lastly, you can listen for events on a line. These events report if the line is high or low.

Generally speaking the character device driver allows more fine grain control and more reliability than the sysfs API.

Link to this section Summary

Types

The direction of the line

The offset of the pin

The value of the offset

t()

Functions

Getting information about a line

Listen to line events on the line offset

Open a GPIO Chip

Read value from a line handle

Read values for a line handle

Request a line handle for a single GPIO offset

Request a line handle for multiple GPIO offsets

Set the value of the GPIO

Set values of the GPIOs

Link to this section Types

Specs

line_direction() :: :input | :output

The direction of the line

With the character device you drive a line with configured offsets. These offsets all share a direction, either :output or :input, which is called the line direction.

The :output direction means you control the GPIOs by setting the value of the GPIOs to 1 or 0. See Circuits.GPIO.Chip.set_value/2 for more information.

The :input direction means you can only read the current value of the GPIOs on the line. See Circuits.GPIO.Chip.read_value/1 for more information.

Specs

offset() :: non_neg_integer()

The offset of the pin

An offset is the pin number provided. Normally these are labeled GPIO N or GPIO_N where N is the pin number. For example, if you wanted to use to use GPIO 17 on a Raspberry PI the offset value would be 17.

More resources:

Raspberry PI: https://pinout.xyz/ Beaglebone: https://beagleboard.org/Support/bone101

Specs

offset_value() :: 0 | 1

The value of the offset

This is either 0 for low or off, or 1 for high or on.

Specs

t() :: %Circuits.GPIO.Chip{
  label: String.t(),
  name: String.t(),
  number_of_lines: non_neg_integer(),
  reference: reference()
}

Link to this section Functions

Link to this function

get_line_info(chip, offset)

View Source

Specs

get_line_info(t(), offset()) ::
  {:ok, Circuits.GPIO.Chip.LineInfo.t()} | {:error, atom()}

Getting information about a line

Link to this function

listen_event(chip, offset)

View Source

Specs

listen_event(t() | String.t(), offset()) :: :ok

Listen to line events on the line offset

Circuits.GPIO.Chip.listen_event(mygpio_chip, 24)
# cause the offset to change value
flush
{:circuits_cdev, 24, timestamp, new_value}

The timestamp will be in nanoseconds so as you do time calculations and conversions be sure to take that into account.

The new_value will be the value the offset value changed to either 1 or 0.

Specs

open(String.t()) :: {:ok, t()}

Open a GPIO Chip

{:ok, chip} = Circuits.GPIO.Chip.open(gpiochip_device)

Specs

read_value(Circuits.GPIO.Chip.LineHandle.t()) ::
  {:ok, offset_value()} | {:error, atom()}

Read value from a line handle

This is useful when you have a line handle that contains only one GPIO offset.

If you want to read multiple GPIOs at once see Circuits.GPIO.Chip.read_values/1.

{:ok, line_handle} = Circuits.GPIO.Chip.request_line("gpiochip0", 17)
{:ok, 0} = Circuits.GPIO.Chip.read_value(line_handle)
Link to this function

read_values(line_handle)

View Source

Specs

read_values(Circuits.GPIO.Chip.LineHandle.t()) ::
  {:ok, [offset_value()]} | {:error, atom()}

Read values for a line handle

This is useful when you a line handle that contains multiple GPIO offsets.

{:ok, line_handle} = Circuits.GPIO.Chip.request_lines("gpiochip0", [17, 22, 23, 24])
{:ok, [0, 0, 0, 0]} = Circuits.GPIO.Chip.read_values(line_handle)

Note that the values in the list match the index order of how the offsets were requested.

Note that the order of the values returned return the order that the offsets were requested.

Link to this function

request_line(chip, offset, direction)

View Source

Specs

request_line(t() | String.t(), offset(), line_direction()) ::
  {:ok, Circuits.GPIO.Chip.LineHandle.t()}

Request a line handle for a single GPIO offset

{:ok, line_handle} = Circuits.GPIO.Chip.request_line(my_gpio_chip, 17, :output)

See Circuits.GPIO.Chip.request_lines/3 and Circuits.GPIO.LineHandle for more details about line handles.

Link to this function

request_lines(chip, offsets, direction)

View Source

Specs

request_lines(t() | String.t(), [offset()], line_direction()) ::
  {:ok, Circuits.GPIO.Chip.LineHandle.t()}

Request a line handle for multiple GPIO offsets

{:ok, line_handle} = Circuits.GPIO.Chip.request_lines(my_gpio_chip, [17, 24], :output)

For the GPIO character device driver you drive GPIOs by requesting for a line handle what contains one or more GPIO offsets. The line handle is mechanism by which you can read and set the values of the GPIO(s). The line handle is attached to the calling process and kernel will not allow others to control the GPIO(s) that are part of that the line handle. Moreover, one the process that requested the line handle goes away the kernel will be able to automatically free the system resources that were tied to that line handle.

Link to this function

set_value(handle, value)

View Source

Specs

set_value(Circuits.GPIO.Chip.LineHandle.t(), offset_value()) ::
  :ok | {:error, atom()}

Set the value of the GPIO

{:ok, line_handle} = Circuits.GPIO.Chip.request_lines(my_gpio_chip, 17)
{:ok, 0} = Circuits.GPIO.Chip.read_value(line_handle)
:ok = Circuits.GPIO.Chip.set_value(line_handle, 1)
{:ok, 1} = Circuits.GPIO.Chip.read_value(line_handle)
Link to this function

set_values(line_handle, values)

View Source

Specs

set_values(Circuits.GPIO.Chip.LineHandle.t(), [offset_value()]) ::
  :ok | {:error, atom()}

Set values of the GPIOs

{:ok, line_handle} = Circuits.GPIO.Chip.request_lines(my_gpio_chip, [17, 24, 22])
{:ok, [0, 0, 0]} = Circuits.GPIO.Chip.read_value(line_handle)
:ok = Circuits.GPIO.Chip.set_value(line_handle, [1, 0, 1])
{:ok, [1, 0, 1]} = Circuits.GPIO.Chip.read_value(line_handle)

Note that the order of the values that were sent matches the order by which the GPIO offsets where requested. In the example above offset 17 was set to 1, offset 24 was stayed at 0, offset 22 was set to 1.