I am using STM32F103, CUBE IDE with HAL library. I am trying to write the outport as giving a 4 bit value to the entire port (16 bit) by using a shift bit operator. Can I directly apply that data to the port as follows. GPIO_PORTA |= 0x0ff; Like wise Or how to write it?
3 Answers
If you want the whole port (all 16 pins) get the value, then you simply write it to the ODR register:
GPIOB->ODR = 0xFFFF; //writing 1/0 in a bit position,
sets/resets that bit. ALL BITS ARE AFFECTED no matter the value your write in.
If you want to set some pins, but not altering the other pins, with one instruction:
GPIOB->BSRR = 0x00F; //writing 1 in a bit position,
sets that bit leaves the others as they are
If you want to reset some pins, but not altering the other pins, with one instruction:
GPIOB->BRR = 0x00F; //writing 1 in a bit position,
clears that bit and leaves the others as they are
If you want a "portion" of a GPIO port to get an specific value, this method is 2 instructions instead of "read-change-write":
GPIOB->BRR = 0x00F; //clear the first 4 bits
GPIOB->BSRR = 0x00A; //set the desired bits in that 4-bit field
-
\$\begingroup\$ BRR and BSRR may not be two separate members of GPIO struct any more. That would at least not compile on my latest STM32 project which uses a single 32-bit struct member to access the 32-bit IO port directly - because you may want to atomically set and clear things on a single 32-bit write. \$\endgroup\$– JustmeCommented Sep 30, 2023 at 17:46
-
\$\begingroup\$ According to my copy of the reference manual, BRR and BSRR do both exist. However, it's not necessary to use the BRR register. As the name implies, the BSRR register (bit set/reset register) can be used both for setting bits and resetting bits; you can turn some outputs on and others off in a single operation. For example, if you want to turn outputs 0 and 2 off, and turn outputs 1 and 3 on, then you can write 0x0005000A to the BSRR register. \$\endgroup\$ Commented Sep 30, 2023 at 20:01
-
\$\begingroup\$ @CassieSwett The BSRR high 16 bits work the same as BRR. However the BRR still provides the same functionality without using a right shift. \$\endgroup\$ Commented Oct 1, 2023 at 9:20
You can directly write to whole 16bit "port" (GPIO). There are few ways, "bare metal", for example
GPIOA->ODR = x;
using LL API:
LL_GPIO_WriteOutputPort(GPIOA,x);
But if you need to modify only few bits (for example lower 8) from all 16. Then you have two posibilities.
a) Do read-modify-write on whole port, like:
tmp = LL_GPIO_ReadOutputPort(GPIOA); // read
tmp = tmp & 0x00FF; // clear (modify)
tmp |= x; // write (modify)
LL_GPIO_WriteOutputPort(GPIOA,x); // write
In this case you have to consider to force "atomicity" if needed (search what that mean if you do not know).
b) Use Bit Set/Reset register. For example in STM32G0 you have 32bit GPIOx->BSSR register. High part is used to reseting selected bits in ODR ("port" output"), Lower part serve to setting selected bits. Writing into this register can atomicaly change any selected bits to any combination without affecting others. But written value have to be "prepared" in advance (you cannot write directly your "x" value). This is atomic process and you have not solve atomicity problems (if there are).