Module gpio_hal

GPIO Hardware Abstraction Layer behavior.

Description

This module defines the behavior that platform-specific GPIO modules must implement. It provides a common interface for basic GPIO operations across all supported platforms (ESP32, RP2, STM32).

There are two APIs for GPIO operations:

NIF-based API

The NIF-based API provides direct access to GPIO pins without requiring a driver process or port. Functions operate directly on pin numbers.

  • init/1 - Initialize a pin for GPIO use (required on RP2, no-op on ESP32 and STM32)

  • deinit/1 - Release a pin from GPIO use

  • set_pin_mode/2 - Configure a pin as input, output, or output with open drain

  • set_pin_pull/2 - Configure internal pull resistors

  • digital_write/2 - Set pin output level

  • digital_read/1 - Read pin input level

Port-based API

The port-based API requires starting a GPIO driver using start/0 or open/0, which returns a handle (a port on ESP32 and STM32, a pid on RP2). This handle is passed to all subsequent operations.

  • start/0 - Start the GPIO driver, or return an existing one if already started

  • open/0 - Start a new GPIO driver instance

  • close/1 - Stop a GPIO driver and release its resources

  • stop/0 - Stop the registered GPIO driver if one is running

  • read/2 - Read pin input level

  • set_direction/3 - Configure a pin as input, output, or output with open drain

  • set_level/3 - Set pin output level

  • set_int/3 - Set a GPIO interrupt on a pin, notifications are sent to the calling process

  • set_int/4 - Set a GPIO interrupt on a pin, notifications are sent to the specified process

  • remove_int/2 - Remove a previously set GPIO interrupt

Pin definitions

Pin definitions vary by platform:

  • ESP32: a non-negative integer (e.g. 2, 15)

  • RP2: a non-negative integer, or {wl, 0..2} for Pico-W wireless pins

  • STM32: a tuple {Bank, PinNum} where Bank is an atom a through k and PinNum is 0..15, a list of pin numbers, or the atom all

Platform differences

  • Interrupt support: ESP32 and STM32 support interrupts. RP2 does not (returns {error, not_supported}).

  • Interrupt message format: on ESP32, {gpio_interrupt, Pin} where Pin is an integer; on STM32, {gpio_interrupt, {Bank, Pin}}.

  • Pull modes: ESP32 and RP2 support up, down, up_down, and floating. STM32 supports up, down, and floating only.

  • init/1 must be called before using a pin on RP2. On ESP32 and STM32 it is a no-op.

  • STM32 supports batch operations: multiple pins on the same bank can be configured or written at once.

Example usage (NIF-based API)

The following example configures pin 2 as an output and sets it high:

  gpio:init(2),
  gpio:set_pin_mode(2, output),
  gpio:digital_write(2, high).

The following example configures pin 4 as an input with a pull-up resistor and reads the level:

  gpio:init(4),
  gpio:set_pin_mode(4, input),
  gpio:set_pin_pull(4, up),
  Level = gpio:digital_read(4).

Example usage (Port-based API)

  GPIO = gpio:start(),
  gpio:set_direction(GPIO, 2, output),
  gpio:set_level(GPIO, 2, high),
  gpio:set_int(GPIO, 4, rising),
  receive
      {gpio_interrupt, 4} -> io:format("Pin 4 triggered!~n")
  end.

Data Types

direction()


direction() = input | output | output_od

The direction is used to set the mode of operation for a GPIO pin, either as an input, an output, or output with open drain.

gpio()


gpio() = port() | pid()

Handle returned by start/0 or open/0. On ESP32 and STM32, this is a port. On RP2, this is a pid.

high_level()


high_level() = high | 1

level()


level() = low_level() | high_level()

Valid pin levels can be atom or integer representation.

low_level()


low_level() = low | 0

pull()


pull() = up | down | up_down | floating

Internal resistor pull mode. Note: STM32 does not support up_down.

trigger()


trigger() = none | rising | falling | both | low | high

Event type that will trigger a gpio_interrupt. Setting trigger to none disables the interrupt.