The following line of code sets(to logic 1) pin 12 of port D in an STM32 microcontroller:

enter image description here

The middle argument of the above HAL function is GPIO_PIN_12 and when I hover on it shows:


It seems the above line sets bit 12 as one. But how does the above line do that? what does uint16_t do over 0x1000 so that we can relate it to bit 12?

  • 2
    \$\begingroup\$ The uint16_t is a type-cast. It doesn't do anything to the constant except provide semantics that the compiler may need elsewhere. There will be a typedef somewhere that specifies (declares) exactly what type is meant by that symbol. It's compiler-specific, though. On some compiler+target combos, it will be 'unsigned long int' semantics. On others, just 'unsigned int'. On still others 'unsigned short int'. Etc. If you go look at the source code for that function, you can unravel what that parameter does in intimate detail. Probably just specifies a port mask. \$\endgroup\$
    – jonk
    Dec 14, 2021 at 0:02

2 Answers 2


0x1000 is 0001000000000000 in binary, which looks a lot like bit 12 to me.

I would guess (without actually reading it) that HAL_GPIO_Write_Pin does something that amounts to

void HAL_GPIO_Write_Pin (volatile uint32_t * port, uint16_t bit, uint32_t value){
  if (value) 
    *port |= bit
    *port &= ~bit;

Or something like that, maybe combined with a load of fluff to make sure the port is configured for output. It might for example be taking an index into a table rather then a raw pointer for the port address, but whatever, the essential bit twiddling will likely be something like this.

  • \$\begingroup\$ What does 1u stand for in your code? \$\endgroup\$
    – GNZ
    Dec 13, 2021 at 23:49
  • \$\begingroup\$ It's the same as 1 << bit but the u specifies unsigned. Whether the unsigned is explicitly needed or not is, I think, part of the heart of the OP question. \$\endgroup\$
    – JYelton
    Dec 13, 2021 at 23:55
  • \$\begingroup\$ It makes the integer literal 1 unsigned, always a good idea to be explicit about this when using the shift operator in C as it avoids some un or implementation defined behaviours (particularly with shift right where sign extension is waiting to screw you). Note however that I have updated my answer, that would have been right for passing in 12 for bit 12... \$\endgroup\$
    – Dan Mills
    Dec 13, 2021 at 23:56
  • \$\begingroup\$ For clarity, I would suggest that you delete the part of your answer that you later realized was incorrect. \$\endgroup\$ Dec 14, 2021 at 0:18

uint16_t declares the ‘type’ as in a value that is represented as an unsigned 16 bit value. As for bit 12 being set, then the hexadecimal value 0x1000 is binary 0001000000000000 (Count those bits!) . Or we could wrjte (1<<12) that the compiler will evaluate for us. - ‘get the 1 bit and shift it left 12 times’.

  • \$\begingroup\$ What happens if uint16_t were omitted? Is that done to explicitly say we are dealing with 16 bit register? \$\endgroup\$
    – GNZ
    Dec 13, 2021 at 23:42
  • \$\begingroup\$ Does ST define the first pin as 0 (instead of 1)? I would have expected GPIO_PIN_12 to be 0x0800. \$\endgroup\$
    – JYelton
    Dec 13, 2021 at 23:44
  • 1
    \$\begingroup\$ @JYelton If I write GPIO_PIN_0 then when I hover it shows ((uint16_t)0x1001) \$\endgroup\$
    – GNZ
    Dec 13, 2021 at 23:46
  • \$\begingroup\$ @GNZ Thanks - I was having a memory lapse thinking the first pin should be 1 instead of 0, but it's typically 0 even on the MCUs I use. Doh! \$\endgroup\$
    – JYelton
    Dec 14, 2021 at 0:06
  • \$\begingroup\$ @GNZ Without the uint16_t, a literal like 0x1000 would be of type signed int. Bitwise operations on signed values can be problematic \$\endgroup\$ Dec 14, 2021 at 0:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.