modm API documentation
General Purpose I/O (GPIO)


struct  modm::platform::Gpio
struct  modm::platform::GpioConnector< peripheral, Signals >
class  modm::platform::GpioInverted< Pin >
class  modm::platform::GpioOpenDrain< Pin >
class  modm::platform::GpioSet< Gpios >
class  modm::platform::GpioStatic< GpioData >
class  modm::platform::GpioStatic< detail::DataUnused >
class  modm::platform::SoftwareGpioPort< Gpios >


using modm::platform::GpioUnused = GpioStatic< detail::DataUnused >
using modm::platform::GpioB0 = GpioStatic< detail::DataB0 >
using modm::platform::GpioOutputB0 = GpioB0
using modm::platform::GpioInputB0 = GpioB0
using modm::platform::GpioB1 = GpioStatic< detail::DataB1 >
using modm::platform::GpioOutputB1 = GpioB1
using modm::platform::GpioInputB1 = GpioB1
using modm::platform::GpioB2 = GpioStatic< detail::DataB2 >
using modm::platform::GpioOutputB2 = GpioB2
using modm::platform::GpioInputB2 = GpioB2
using modm::platform::GpioB3 = GpioStatic< detail::DataB3 >
using modm::platform::GpioOutputB3 = GpioB3
using modm::platform::GpioInputB3 = GpioB3
using modm::platform::GpioB4 = GpioStatic< detail::DataB4 >
using modm::platform::GpioOutputB4 = GpioB4
using modm::platform::GpioInputB4 = GpioB4
using modm::platform::GpioB5 = GpioStatic< detail::DataB5 >
using modm::platform::GpioOutputB5 = GpioB5
using modm::platform::GpioInputB5 = GpioB5

Detailed Description

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.

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;
bool input = Button::read();
using Led = GpioInverted<GpioB3>; // inverts the IO logic of the pin

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>;

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<GpioA7, GpioA2, GpioA6, GpioA0>;
static_assert(Port::number_of_ports == 1, "Read/write needs to be atomic");
uint8_t nibble = Port::read();

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>;
using ReversePort = GpioPort<GpioB7, -8>;
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:

Peripheral Signals

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

GpioConnector<Peripheral::Uart0, GpioD0::Txd, GpioD1::Rxd>::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 Uart0::connect()
Connector = GpioConnector<Peripheral::Uart0, Signals...>;
Connector::disconnect(); // reset to floating input
// extract pins from signals
using Rxd = Connector::GetSignal<Gpio::Signal::Rxd>;
using Txd = Connector::GetSignal<Gpio::Signal::Txd>;
// if not found, returns GpioUnused, you can check for this case
static_assert(not Connector::isValid<Txd>,
"This UART driver requires the Txd signal");
// configure both pins
// connect both pins to alternate functions
// This will static assert if signals do not make sense
// Connect these pin signals to Uart0
Uart0::connect<GpioD0::Txd, GpioD1::Rxd>();

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
// Connect more signals than required
Uart1::connect<GpioD0::Txd, GpioD2::Xck>();

External Interrupts

You can also configure the external interrupts, however, you must provide the interrupt yourself.

// your code

When using multiple Pin-Change interrupts you need to first check the corresponding flag to determine which pin triggered the collective interrupt.

if (GpioB1::getPcInterruptFlag()) {
bool state = GpioB2::read();
// your code
if (GpioB2::getPcInterruptFlag()) {
bool state = GpioB2::read();
// your code