modm API documentation
General Purpose I/O (GPIO)

Classes

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 >
 

Typedefs

using modm::platform::GpioUnused = GpioStatic< detail::DataUnused >
 
using modm::platform::GpioA0 = GpioStatic< detail::DataA0 >
 
using modm::platform::GpioOutputA0 = GpioA0
 
using modm::platform::GpioInputA0 = GpioA0
 
using modm::platform::GpioA1 = GpioStatic< detail::DataA1 >
 
using modm::platform::GpioOutputA1 = GpioA1
 
using modm::platform::GpioInputA1 = GpioA1
 
using modm::platform::GpioA2 = GpioStatic< detail::DataA2 >
 
using modm::platform::GpioOutputA2 = GpioA2
 
using modm::platform::GpioInputA2 = GpioA2
 
using modm::platform::GpioA3 = GpioStatic< detail::DataA3 >
 
using modm::platform::GpioOutputA3 = GpioA3
 
using modm::platform::GpioInputA3 = GpioA3
 
using modm::platform::GpioA4 = GpioStatic< detail::DataA4 >
 
using modm::platform::GpioOutputA4 = GpioA4
 
using modm::platform::GpioInputA4 = GpioA4
 
using modm::platform::GpioA5 = GpioStatic< detail::DataA5 >
 
using modm::platform::GpioOutputA5 = GpioA5
 
using modm::platform::GpioInputA5 = GpioA5
 
using modm::platform::GpioA6 = GpioStatic< detail::DataA6 >
 
using modm::platform::GpioOutputA6 = GpioA6
 
using modm::platform::GpioInputA6 = GpioA6
 
using modm::platform::GpioA7 = GpioStatic< detail::DataA7 >
 
using modm::platform::GpioOutputA7 = GpioA7
 
using modm::platform::GpioInputA7 = GpioA7
 
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
 
using modm::platform::GpioB6 = GpioStatic< detail::DataB6 >
 
using modm::platform::GpioOutputB6 = GpioB6
 
using modm::platform::GpioInputB6 = GpioB6
 
using modm::platform::GpioB7 = GpioStatic< detail::DataB7 >
 
using modm::platform::GpioOutputB7 = GpioB7
 
using modm::platform::GpioInputB7 = GpioB7
 
using modm::platform::GpioC0 = GpioStatic< detail::DataC0 >
 
using modm::platform::GpioOutputC0 = GpioC0
 
using modm::platform::GpioInputC0 = GpioC0
 
using modm::platform::GpioC1 = GpioStatic< detail::DataC1 >
 
using modm::platform::GpioOutputC1 = GpioC1
 
using modm::platform::GpioInputC1 = GpioC1
 
using modm::platform::GpioC2 = GpioStatic< detail::DataC2 >
 
using modm::platform::GpioOutputC2 = GpioC2
 
using modm::platform::GpioInputC2 = GpioC2
 
using modm::platform::GpioC3 = GpioStatic< detail::DataC3 >
 
using modm::platform::GpioOutputC3 = GpioC3
 
using modm::platform::GpioInputC3 = GpioC3
 
using modm::platform::GpioC4 = GpioStatic< detail::DataC4 >
 
using modm::platform::GpioOutputC4 = GpioC4
 
using modm::platform::GpioInputC4 = GpioC4
 
using modm::platform::GpioC5 = GpioStatic< detail::DataC5 >
 
using modm::platform::GpioOutputC5 = GpioC5
 
using modm::platform::GpioInputC5 = GpioC5
 
using modm::platform::GpioC6 = GpioStatic< detail::DataC6 >
 
using modm::platform::GpioOutputC6 = GpioC6
 
using modm::platform::GpioInputC6 = GpioC6
 
using modm::platform::GpioC7 = GpioStatic< detail::DataC7 >
 
using modm::platform::GpioOutputC7 = GpioC7
 
using modm::platform::GpioInputC7 = GpioC7
 
using modm::platform::GpioD0 = GpioStatic< detail::DataD0 >
 
using modm::platform::GpioOutputD0 = GpioD0
 
using modm::platform::GpioInputD0 = GpioD0
 
using modm::platform::GpioD1 = GpioStatic< detail::DataD1 >
 
using modm::platform::GpioOutputD1 = GpioD1
 
using modm::platform::GpioInputD1 = GpioD1
 
using modm::platform::GpioD2 = GpioStatic< detail::DataD2 >
 
using modm::platform::GpioOutputD2 = GpioD2
 
using modm::platform::GpioInputD2 = GpioD2
 
using modm::platform::GpioD3 = GpioStatic< detail::DataD3 >
 
using modm::platform::GpioOutputD3 = GpioD3
 
using modm::platform::GpioInputD3 = GpioD3
 
using modm::platform::GpioD4 = GpioStatic< detail::DataD4 >
 
using modm::platform::GpioOutputD4 = GpioD4
 
using modm::platform::GpioInputD4 = GpioD4
 
using modm::platform::GpioD5 = GpioStatic< detail::DataD5 >
 
using modm::platform::GpioOutputD5 = GpioD5
 
using modm::platform::GpioInputD5 = GpioD5
 
using modm::platform::GpioD6 = GpioStatic< detail::DataD6 >
 
using modm::platform::GpioOutputD6 = GpioD6
 
using modm::platform::GpioInputD6 = GpioD6
 
using modm::platform::GpioD7 = GpioStatic< detail::DataD7 >
 
using modm::platform::GpioOutputD7 = GpioD7
 
using modm::platform::GpioInputD7 = GpioD7
 
using modm::platform::GpioE0 = GpioStatic< detail::DataE0 >
 
using modm::platform::GpioOutputE0 = GpioE0
 
using modm::platform::GpioInputE0 = GpioE0
 
using modm::platform::GpioE1 = GpioStatic< detail::DataE1 >
 
using modm::platform::GpioOutputE1 = GpioE1
 
using modm::platform::GpioInputE1 = GpioE1
 
using modm::platform::GpioE2 = GpioStatic< detail::DataE2 >
 
using modm::platform::GpioOutputE2 = GpioE2
 
using modm::platform::GpioInputE2 = GpioE2
 
using modm::platform::GpioE3 = GpioStatic< detail::DataE3 >
 
using modm::platform::GpioOutputE3 = GpioE3
 
using modm::platform::GpioInputE3 = GpioE3
 
using modm::platform::GpioE4 = GpioStatic< detail::DataE4 >
 
using modm::platform::GpioOutputE4 = GpioE4
 
using modm::platform::GpioInputE4 = GpioE4
 
using modm::platform::GpioE5 = GpioStatic< detail::DataE5 >
 
using modm::platform::GpioOutputE5 = GpioE5
 
using modm::platform::GpioInputE5 = GpioE5
 
using modm::platform::GpioE6 = GpioStatic< detail::DataE6 >
 
using modm::platform::GpioOutputE6 = GpioE6
 
using modm::platform::GpioInputE6 = GpioE6
 
using modm::platform::GpioE7 = GpioStatic< detail::DataE7 >
 
using modm::platform::GpioOutputE7 = GpioE7
 
using modm::platform::GpioInputE7 = GpioE7
 
using modm::platform::GpioF0 = GpioStatic< detail::DataF0 >
 
using modm::platform::GpioOutputF0 = GpioF0
 
using modm::platform::GpioInputF0 = GpioF0
 
using modm::platform::GpioF1 = GpioStatic< detail::DataF1 >
 
using modm::platform::GpioOutputF1 = GpioF1
 
using modm::platform::GpioInputF1 = GpioF1
 
using modm::platform::GpioF2 = GpioStatic< detail::DataF2 >
 
using modm::platform::GpioOutputF2 = GpioF2
 
using modm::platform::GpioInputF2 = GpioF2
 
using modm::platform::GpioF3 = GpioStatic< detail::DataF3 >
 
using modm::platform::GpioOutputF3 = GpioF3
 
using modm::platform::GpioInputF3 = GpioF3
 
using modm::platform::GpioF4 = GpioStatic< detail::DataF4 >
 
using modm::platform::GpioOutputF4 = GpioF4
 
using modm::platform::GpioInputF4 = GpioF4
 
using modm::platform::GpioF5 = GpioStatic< detail::DataF5 >
 
using modm::platform::GpioOutputF5 = GpioF5
 
using modm::platform::GpioInputF5 = GpioF5
 
using modm::platform::GpioF6 = GpioStatic< detail::DataF6 >
 
using modm::platform::GpioOutputF6 = GpioF6
 
using modm::platform::GpioInputF6 = GpioF6
 
using modm::platform::GpioF7 = GpioStatic< detail::DataF7 >
 
using modm::platform::GpioOutputF7 = GpioF7
 
using modm::platform::GpioInputF7 = GpioF7
 
using modm::platform::GpioG0 = GpioStatic< detail::DataG0 >
 
using modm::platform::GpioOutputG0 = GpioG0
 
using modm::platform::GpioInputG0 = GpioG0
 
using modm::platform::GpioG1 = GpioStatic< detail::DataG1 >
 
using modm::platform::GpioOutputG1 = GpioG1
 
using modm::platform::GpioInputG1 = GpioG1
 
using modm::platform::GpioG2 = GpioStatic< detail::DataG2 >
 
using modm::platform::GpioOutputG2 = GpioG2
 
using modm::platform::GpioInputG2 = GpioG2
 
using modm::platform::GpioG3 = GpioStatic< detail::DataG3 >
 
using modm::platform::GpioOutputG3 = GpioG3
 
using modm::platform::GpioInputG3 = GpioG3
 
using modm::platform::GpioG4 = GpioStatic< detail::DataG4 >
 
using modm::platform::GpioOutputG4 = GpioG4
 
using modm::platform::GpioInputG4 = GpioG4
 

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

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

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
Rxd::configure(Gpio::InputType::PullUp);
Txd::setOutput();
// connect both pins to alternate functions
// This will static assert if signals do not make sense
Connector::connect();
}
// 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
Uart1::connect<GpioD0::Txd>();
// 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.

GpioD2::setInputTrigger(Gpio::InputTrigger::RisingEdge);
GpioD2::enableExternalInterrupt();
MODM_ISR(INT0)
{
// your code
GpioD2::acknowledgeInterruptFlag();
}
GpioD2::disableExternalInterrupt();

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

GpioB1::enablePcInterrupt();
GpioB2::enablePcInterrupt();
MODM_ISR(PCINT0)
{
if (GpioB1::getPcInterruptFlag()) {
bool state = GpioB1::read();
// your code
GpioB1::acknowledgePcInterruptFlag();
}
if (GpioB2::getPcInterruptFlag()) {
bool state = GpioB2::read();
// your code
GpioB2::acknowledgePcInterruptFlag();
}
}