Skip to content

General Purpose I/O (GPIO)

lbuild module: modm:platform:gpio

This module provides register access to GPIO and connect their signals to the respective peripherals in a compile-time verified way. This module also enables all GPIO peripheral clocks on startup by default.

Each GPIO is represented as its own class with only static methods, which implement the modm::GpioIO interface and provide additional platform-specific methods.

using namespace modm::platform;

using Button = GpioA0;
Button::setInput(Gpio::InputType::PullUp);
bool input = Button::read();

using Led = GpioInverted<GpioB3>; // inverts the IO logic of the pin

Led::setOutput(Gpio::OutputType::OpenDrain, Gpio::OutputSpeed::MHz2);
Led::set(input);

using Analog = GpioC12;
Analog::setAnalogInput(); // Use pin for ADC/DAC/COMP
Analog::lock(); // this prevents changes until next reboot

using Signal = GpioD9;
Signal::setAlternateFunction(4); // For AF id see datasheet
Signal::setAlternateFunction(); // STM32F1 has no AF id
Signal::disconnect(); // Switch back to floating input

// Some STM32s have remappable pinouts
GpioA11::remap(); // STM32G0: Remap A9 -> A11.

You can also use an unordered set of GPIOs, which is useful when configuring a large number of pins, since the register accesses will be bundled and thus less code is generated.

using Set = GpioSet<GpioA0, GpioB1, GpioC2, GpioD3>;
Set::setInput();

To write and read a set of GPIOs, you need to use an ordered implementation, which defines the pins from MSB to LSB, left-to-right. You can also check the number of ports in case your use-case requires atomic reads/writes.

using Port = SoftwareGpioPort<GpioA10, GpioA2, GpioA6, GpioA14>;
static_assert(Port::number_of_ports == 1, "Read/write needs to be atomic");
Port::setOutput(Gpio::OutputType::OpenDrain);
Port::configure(Gpio::InputType::PullUp);
uint8_t nibble = Port::read();
Port::write(nibble);

For efficient access you can use a strictly-ordered implementation with a start pin and width. Note that you can reverse the data order with a negative width.

using Port = GpioPort<GpioA0, 8>;
Port::setOutput();
Port::write(data);

using ReversePort = GpioPort<GpioB7, -8>;
ReversePort::setInput();
uint8_t data = ReversePort::read();

Finally, you can use an empty GPIO implementation in cases where the API requires a GPIO, but you don't need one, for example, a bit-banged SPI without MISO pin:

// write only SPI
using SPI = modm::platform::BitBangSpiMaster<GpioA0, GpioA1, GpioUnused>;

Alternate Function Signals

To make it easier to connect pins with peripherals, this module implements a compile-time map of (pin, signal, peripheral) to Alternate Function ID (AF). Note that you must provide both peripherals and signals to be unambiguous.

GpioConnector<Peripheral::Usart1, GpioD0::Tx, GpioD1::Rx>::connect();

However, it is recommended to wrap this functionality into a separate function Driver::connect<Signals...>(config), so that additional driver specific pin configuration can be done:

template< class... Signals >
void Uart1::connect()
{
    Connector = GpioConnector<Peripheral::Usart1, Signals...>;
    Connector::disconnect(); // reset to floating input

    // extract pins from signals
    using Rx = Connector::GetSignal<Gpio::Signal::Rx>;
    using Tx = Connector::GetSignal<Gpio::Signal::Tx>;
    // if not found, returns GpioUnused, you can check for this case
    static_assert(not Connector::isValid<Tx>,
                  "This UART driver requires the Tx signal");

    // configure both pins
    Rx::configure(Gpio::InputType::PullUp);
    Tx::configure(Gpio::OutputType::PushPull);

    // connect both pins to alternate functions
    // This will static assert if signals do not make sense
    Connector::connect();
}
// Connect these pin signals to Usart1
Uart1::connect<GpioD0::Tx, GpioD1::Rx>();

Note that you may pass a variable number of signals to this connect function, leaving out signals you don't need and adding signals that are not required.

// Connect only one signal
Uart1::connect<GpioD0::Tx>();
// Connect more signals than required
Uart1::connect<GpioD0::Tx, GpioD2::Cts>();

This module is only available for stm32.

Options

enable_ports

Enable clock for these GPIO ports during startup

Default: {A, B, C, D, E, F, G, H, I, J, K} stm32{f4,f7,h7}
Default: {A, B, C, D, E, F, G, H, I, J} stm32{h7,u5}
Default: {A, B, C, D, E, F, G, H, I} stm32{f2,f4,f7,h7,l4,u5}
Default: {A, B, C, D, E, F, G, H} stm32{f2,f3,f4,f7,h7,l1,l4,l5,u5}
Default: {A, B, C, D, E, F, G} stm32{f1,g4}
Default: {A, B, C, D, E, F} stm32{f0,f3,g0}
Default: {A, B, C, D, E, G, H} stm32{l4,l5,u5}
Default: {A, B, C, D, E, H, I} stm32{f4,u5}
Default: {A, B, C, D, E, H} stm32{f2,f4,f7,h7,l0,l1,l4,l5,u5}
Default: {A, B, C, D, E} stm32f1
Default: {A, B, C, D, F, G} stm32g4
Default: {A, B, C, D, F} stm32{c0,f0,f3,g0}
Default: {A, B, C, D, G, H} stm32{l4,l5}
Default: {A, B, C, D, H} stm32{f2,f4,f7,h7,l0,l1,l4,l5,u5}
Default: {A, B, C, D} stm32f1
Default: {A, B, C, E, H} stm32u5
Default: {A, B, C, F, G} stm32g4
Default: {A, B, C, F} stm32{c0,f0,f3,g0}
Default: {A, B, C, G, H} stm32u5
Default: {A, B, C, H} stm32{f4,l0,l1,l4,l5,u5}
Default: {A, B, C} stm32{g0,l0}
Default: {A, B, D} stm32f1
Default: {A, B, F, G} stm32g4
Default: {A, B, F} stm32{f0,f3}
Default: {A, F} stm32f038f6p6
Inputs: [A, B, C] stm32{g0,l0}
Inputs: [A, B, C, D] stm32f1
Inputs: [A, B, C, D, E] stm32f1
Inputs: [A, B, C, D, E, F] stm32{f0,f3,g0}
Inputs: [A, B, C, D, E, F, G] stm32{f1,g4}
Inputs: [A, B, C, D, E, F, G, H] stm32{f2,f3,f4,f7,h7,l1,l4,l5,u5}
Inputs: [A, B, C, D, E, F, G, H, I] stm32{f2,f4,f7,h7,l4,u5}
Inputs: [A, B, C, D, E, F, G, H, I, J] stm32{h7,u5}
Inputs: [A, B, C, D, E, F, G, H, I, J, K] stm32{f4,f7,h7}
Inputs: [A, B, C, D, E, G, H] stm32{l4,l5,u5}
Inputs: [A, B, C, D, E, H] stm32{f2,f4,f7,h7,l0,l1,l4,l5,u5}
Inputs: [A, B, C, D, E, H, I] stm32{f4,u5}
Inputs: [A, B, C, D, F] stm32{c0,f0,f3,g0}
Inputs: [A, B, C, D, F, G] stm32g4
Inputs: [A, B, C, D, G, H] stm32{l4,l5}
Inputs: [A, B, C, D, H] stm32{f2,f4,f7,h7,l0,l1,l4,l5,u5}
Inputs: [A, B, C, E, H] stm32u5
Inputs: [A, B, C, F] stm32{c0,f0,f3,g0}
Inputs: [A, B, C, F, G] stm32g4
Inputs: [A, B, C, G, H] stm32u5
Inputs: [A, B, C, H] stm32{f4,l0,l1,l4,l5,u5}
Inputs: [A, B, D] stm32f1
Inputs: [A, B, F] stm32{f0,f3}
Inputs: [A, B, F, G] stm32g4
Inputs: [A, F] stm32f038f6p6

Queries

all_signals

Dependencies

modm:platform:gpio modm_platform_gpio modm: platform: gpio modm_architecture_gpio modm: architecture: gpio modm_platform_gpio->modm_architecture_gpio modm_cmsis_device modm: cmsis: device modm_platform_gpio->modm_cmsis_device modm_math_utils modm: math: utils modm_platform_gpio->modm_math_utils modm_platform_rcc modm: platform: rcc modm_platform_gpio->modm_platform_rcc

Limited availability: Check with 'lbuild discover' if this module is available for your target!