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