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¶
Limited availability: Check with 'lbuild discover' if this module is available for your target!