Skip to main content
waclawek.jan
Super User
June 11, 2025
Question

Can LL_GPIO_Init() initialize multiple pins at once?

  • June 11, 2025
  • 2 replies
  • 506 views

In an inherited code I see LL_GPIO_Init() being called with pin definitions (LL_GPIO_PIN_xx) OR-ed together, presumably to define multiple pins of the same port to the same settings, in one call of the function.

The documentation (doxygen header) to LL_GPIO_Init() does not say this is allowed; neither says so the description of the init struct. Is there any authoritative documentation which allows this?

Thanks,

JW

 

2 replies

Andrew Neil
Super User
June 11, 2025

I've always found this to be unclear in both HAL and LL documentation.

It's never clear whether a "pin" parameter represents a pin number (so can only be a single pin), or a bitmask (so could represent multiple pins) - and both are used in various places.

 

PS:

See: https://community.st.com/t5/stm32-mcus-embedded-software/array-for-gpio-pins/m-p/654354/highlight/true#M46755

But the documentation:

AndrewNeil_0-1749633364422.png

Is not at all clear that GPIO_Pin is a bitmask.

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
waclawek.jan
Super User
June 11, 2025

In this case, neither of them, LL_GPIO_PIN_xx definitions contain multiple (three?) fields, neither of them is pin number and only one of them is the pin mask.

Nonetheless, LL_GPIO_Init() as it is now *is* written with the multiple-pins-at-once in mind; however, I am hesitant to rely on that once there's not a single iota hinting toward this option in the documentation I know of.

JW

Andrew Neil
Super User
June 11, 2025

I think those definitions do boil down to a bitmask for each pin:

/** @defgroup GPIO_LL_EC_PIN PIN
 * @{
 */
#define LL_GPIO_PIN_0 ((GPIO_BSRR_BS0 << GPIO_PIN_MASK_POS) | 0x00000001U) /*!< Select pin 0 */
#define LL_GPIO_PIN_1 ((GPIO_BSRR_BS1 << GPIO_PIN_MASK_POS) | 0x00000002U) /*!< Select pin 1 */
#define LL_GPIO_PIN_2 ((GPIO_BSRR_BS2 << GPIO_PIN_MASK_POS) | 0x00000004U) /*!< Select pin 2 */
#define LL_GPIO_PIN_3 ((GPIO_BSRR_BS3 << GPIO_PIN_MASK_POS) | 0x00000008U) /*!< Select pin 3 */

 

Especially given the final "ALL" definition:

#define LL_GPIO_PIN_ALL (LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_2 | \
 LL_GPIO_PIN_3 | LL_GPIO_PIN_4 | LL_GPIO_PIN_5 | \
 LL_GPIO_PIN_6 | LL_GPIO_PIN_7 | LL_GPIO_PIN_8 | \
 LL_GPIO_PIN_9 | LL_GPIO_PIN_10 | LL_GPIO_PIN_11 | \
 LL_GPIO_PIN_12 | LL_GPIO_PIN_13 | LL_GPIO_PIN_14 | \
 LL_GPIO_PIN_15) /*!< Select all pins */

 

But, indeed, this still doesn't guarantee that any particular function/macro taking them as a parameter will actually work with a multi-pin pattern.

 

So, indeed, this documentation needs to be clarified.

Throughout.

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
waclawek.jan
Super User
June 11, 2025

> I think those definitions do boil down to a bitmask for each pin

Only bits 8..24 are the actual pin mask, filled by (GPIO_BSRR_BSx << GPIO_PIN_MASK_POS)

Bits 0..7 (which in itself wouldn't be sufficient for a mask for all 16 pins) is something like "(half of) shift within one of the CRL/CRH registers" (this is 'F1, very different from other STM32; but in other STM32 that 8-bit mask is "shift wihin one of the ARL/ARH registers).

Then there's a flag somewhere at 26th bit which probably is "index" distinguishing between CRL/CRH. I am not going to dig deeper.

> Especially given the final "ALL" definition

The only purpose of the "ALL" is to be used in the "checker" macro, where it verifies that at least one of those 3 fields is nonzero and all other bits not occupied by those fileds are zero.

 

The HAL_GPIO_WritePin() you've quoted above *is* different from the initialization and it may indeed require only one pin at a time (not going to dig into that either).

JW