My Page


Google Sites test ground. You might see many weird things !


Eagle


മലയാളം ട്രൈ ചെയ്തു നോക്കട്ടെ. കൊള്ളാം. Noto Sans Malayalam ആണ് ഫോണ്ട്. ഞാന്‍ കണ്ടിട്ടുള്ളതില്‍ വെച്ച് ഏറ്റവും നല്ല മലയാളം ഫോണ്ട് ആണ് ഇത്. Google ആണ് ഡെവലപ്പ് ചെയ്തത്. ഇപ്പോള്‍ ടൈപ്പ് ചെയ്യുന്നത് Google Input Tools ഉപയോഗിച്ചാണ്. മലയാളത്തില്‍, അതായത് Manglish ല്‍ ടൈപ്പ് ചെയ്‌താല്‍ തനിയെ മലയാളം ആയിക്കോളും. 


Understanding the STM32 GPIOs


In STM32, GPIOs need to be initialized before being used in the application program. The GPIO peripheral is configured and controlled using registers. Multiple registers are allocated to each ports available in an STM32 MCU. These registers can be directly accessed and programmed but it's a tedious task. To make it easier, we can use the HAL driver provided by ST. This code is also generated by STM32CubeMX application as per user configuration and makes it easy to generate initialization codes. Let's see how to initialize GPIO directly using registers.

Following are the registers associated each GPIO port. Each port on STM32 can have up to 16 GPIO pins. A particular MCU can have multiple such ports.
  • GPIO port mode register (GPIOx_MODER) - 32 bits, dual bit configuration
  • GPIO port output type register (GPIOx_OTYPER) - 16 bits, single bit configuration
  • GPIO port output speed register (GPIOx_OSPEEDR) - 32 bits, dual bit
  • GPIO port pull-up/pull-down register (GPIOx_PUPDR) - 32 bits, dual bit
  • GPIO port input data register (GPIOx _IDR) - 16 bits, single bit
  • GPIO port output data register (GPIOx_ODR) - 16 bits, single bit
  • GPIO port bit set/reset register (GPIOx _BSRR) - 32 bits, single bit
  • GPIO port configuration lock register (GPIOx_LCKR) - 16 bits, single bit
  • GPIO alternate function low register (GPI Ox_AFRL) - 32 bits, four bit configuration
  • GPIO alternate function high register (GPIOx_AFRH) - 32 bits, four bit
  • GPIO Port bit reset register (GPIOx_BRR) - 16 bits, single bit (not available in all MCUs)

In software, you can access these registers as
  • GPIOx->MODER
  • GPIOx->OTYPER
  • GPIOx->OSPEEDR
  • GPIOx->PUPDR
  • GPIOx->IDR
  • GPIOx->ODR
  • GPIOx->BSRR
  • GPIOx->BRR
  • GPIOx->LCKR
  • GPIOx->AFRL
  • GPIOx->AFRH

For example if you want to set pin 5 of port A, ie PA5, as output, you can do so by,

GPIOA->MODER |= (1U << 5);

(1U << 5) simply means "shift unsigned integer 1 to 5 positions left". This has the effect of writing binary 01 to configuration bit pair of 5th pin of port A. 01 means the pin will be set as an output. The |= means it's a "Read Modify Write" access to the register. Means we need to first read the register, then use the value to determine a new value and write that result back to the same register. There's a better way to do this which will be discussed in a while.

As a programmer, you'll most likely add multiple definitions to a header file to make such operations easier, which is already done by STM developers. For example GPIOx->MODER can accept the following values,

  • GPIO_MODER_MODER5_Pos   -  the relative position of the register
  • GPIO_MODER_MODER5_Msk  -  a 11 binary mask pair
  • GPIO_MODER_MODER5           -  a 11 binary mask pair
  • GPIO_MODER_MODER5_0       -  a 01 binary set mask
  • GPIO_MODER_MODER5_1       -  a 10 binary set mask

and the definitions of those values are

#define GPIO_MODER_MODER5_Pos    (10U)                                 
#define GPIO_MODER_MODER5_Msk    (0x3U << GPIO_MODER_MODER5_Pos)  //0x00000C00
#define GPIO_MODER_MODER5        GPIO_MODER_MODER5_Msk
#define GPIO_MODER_MODER5_0      (0x1U << GPIO_MODER_MODER5_Pos)  //0x00000400
#define GPIO_MODER_MODER5_1      (0x2U << GPIO_MODER_MODER5_Pos)  //0x00000800

If you've ever used bit manipulation in your programs, things would be clear by now on using those definitions accordingly. GPIO_MODER_MODER5_Pos is the relative position of bit pair assigned to 5th pin of port A. For the first pair, the relative position would be zero. So we're cleverly using the shift operator to set the binary values in a register for each pin. Notice the relative position is defined as an unsigned int 10U while the rest of the numbers as hex values. This is just arbitrary.

Now let's see how we can configure the register using these definitions.

To set a bit pair to 11 simultaneously,

GPIOA->MODER |= GPIO_MODER_MODER5;


To clear a bit pair to 00 simultaneously,

GPIOA->MODER &= ~(GPIO_MODER_MODER5);


To set only the first bit to 1 while the second bit is unchanged,

GPIOA->MODER |= GPIO_MODER_MODER5_0;


To clear the first bit to 0 while the second bit is unchanged,

GPIOA->MODER &= ~(GPIO_MODER_MODER5_0);


To set the second bit to 1 while the first bit is unchanged,

GPIOA->MODER |= GPIO_MODER_MODER5_1;


To clear the second bit to 0 while the first bit is unchanged,

GPIOA->MODER |= ~(GPIO_MODER_MODER5_1);


To set the bit pair to 01 simultaneously,

GPIOA->MODER |= GPIO_MODER_MODER5_0; //set first bit
GPIOA->MODER &= ~(GPIO_MODER_MODER5_1); //clear second bit


To set the bit pair to 10 simultaneously,

GPIOA->MODER &= ~(GPIO_MODER_MODER5_0); //clear first bit
GPIOA->MODER |= GPIO_MODER_MODER5_1; //set second bit


For single 16 bits, single bit configuration registers such as OTYPER, we get only a position and a mask in the form of,

GPIO_OTYPER_OT0_Pos     (0U)
GPIO_OTYPER_OT0_Msk     (0x1U << GPIO_OTYPER_OT0_Pos)
GPIO_OTYPER_OT0  


Did you see the overhead of setting a binary pair to either 01 or 10 at the same time ? We needed two statements to do that. This is because we can not do simultaneous AND or OR operations on a single register. Also those two statements constitutes of two RMW sequences, so in total 6 single instructions at least. We are also not guaranteed that these six instructions will be executed in order in case an interrupt occurs or a thread or processor has access to the same memory locations we're manipulating. That's a problem and that's why we have "atomic" operations. It simplifies the RMW operations from the programmer's perspective and also ensures the instructions will be executed in the order they're written together.

There's no In case of GPIO configuration registers of STM32, we can perform atomic write operations using the BSRR register. It's a 32-bit register where the lower 16-bits are used to set any of the 16 pins and the higher 16-bits to clear any of the 16 pins of a specific IO port.

To set PA5 (5th pin of port A), we can do,

GPIOA->BSRR = (1U << 5);   //set the 5th bit or PA5

or 

GPIOA->BSRR = GPIO_BSRR_BS5;   //set the 5th bit or PA5


To clear PA5,

GPIOA->BSRR = (1U << 21);   //clear the 5th bit or PA5

or

GPIOA->BSRR = GPIO_BSRR_BR5;   //clear the 5th bit or PA5

where GPIO_BSRR_BS5 a macro that sets the 5th bit of lower 16-bits and GPIO_BSRR_BR5 clears the 5th bit of higher 16-bits.

Similar macro definitions are available for all of the GPIO registers.