Home > OS >  A good way to pack GPIO_pin and GPIO_port in STM32
A good way to pack GPIO_pin and GPIO_port in STM32

Time:03-07

In my STM32 C project, I want to define a struct (or class or macro) to pack the port and pin information

LED_PIN = Something{GPIOA, GPIO_PIN_5}

So, I can write something like this

while(true){
  HAL_GPIO_TogglePin(LED_PIN.port, LED_PIN.pin); //or using member method or anything similar
  HAL_Delay(500);
}

Here, I want LED_PIN.pin and LED_PIN.port to be const during compilation so that they can be used as case labels and it also will save space.

It is worth noting that GPIO_A is defined as ((GPIO_TypeDef *) GPIOA_BASE) in the HAL header, so it cannot directly be used to initialize a constexpr due to that reinterpret_cast.

CodePudding user response:

The following works for me:

struct IOPin
{
    GPIO_TypeDef *port;
    uint16_t pin;
};

constexpr IOPin PA0{GPIOA, GPIO_PIN_0};

Compiler Explorer

CodePudding user response:

I've seen hundreds of attempts to abstract away simple GPIO and written a fair amount of such attempts myself. It never ends well, we always end up with something which is unintuitive or bloated or hard to read for other programmers.

Bluntly, the clearest and most readable way is simply this:

#define LED_PORT GPIOA 
#define LED_PIN  GPIO_PIN_5

LED_PORT |= LED_PIN;  // set pin
LED_PORT &= ~LED_PIN; // clear pin
LED_PORT ^= LED_PIN;  // toggle pin

This is as fast, readable and portable as it gets - it cannot be improved further. This code is easily understood by 100% of all C and C programmers and compiles portably on 100% of all tool chains. It does not lead to questionable pointer conversions or potential overhead.

Yes you can write a GPIO HAL in case there are more non-trivial things it needs to handle, such as interrupts or port routing. But just for plain bit-banging I/O, there is no reason to invent some HAL.

  • Related