Skip to main content
QNGUY.1
Associate
September 10, 2020
Solved

Can STM32 GPIOx Register parse to each bit?

  • September 10, 2020
  • 3 replies
  • 1448 views

Hello,

I am a new STM32 member. In many previous projects from PIC, we often #define GPIOx as a bit. So we can manipulate some operator directly and easily as example below.

Example:

#define LED_AL1 LATBbits.LATB6

#define LED_AL2 LATBbits.LATB7

LED_A1 ^= 1;

LED_A2 = ~LED_A2;

So I think STM32 MCU will also parse to each bit such as other MCUs.

If we want to parse a GPIOx to each bit, how can we do it ?

If you have an idea, please share us your comment.

Thanks in advance !

This topic has been closed for replies.
Best answer by QNGUY.1

Thanks Nikita who had given me a new idea !

Finally, we also parsed GPIOx.ODR to bits successfully

#include "main.h"
#include "stm32l073xx.h"
#include "stm32l0xx_hal.h"
 
#define GPIOA_ODR ((BITMODE_TypeDef *) (GPIOA_BASE + 0x14U))
#define GPIOB_ODR ((BITMODE_TypeDef *) (GPIOB_BASE + 0x14U))
#define GPIOC_ODR ((BITMODE_TypeDef *) (GPIOC_BASE + 0x14U))
 
 
typedef struct
{
 __IO uint8_t Bit0		:	1 ; /*!< GPIO bit 0, 							Address offset: 0x00 */
 __IO uint8_t Bit1		:	1 ; /*!< GPIO bit 1, 							Address offset: 0x01 */
 __IO uint8_t Bit2		:	1 ; /*!< GPIO bit 2, 							Address offset: 0x02 */
 __IO uint8_t Bit3		:	1 ; /*!< GPIO bit 3, 							Address offset: 0x03 */
 
	__IO uint8_t Bit4		:	1 ; /*!< GPIO bit 4, 							Address offset: 0x04 */
 __IO uint8_t Bit5		:	1 ; /*!< GPIO bit 5, 							Address offset: 0x05 */
 __IO uint8_t Bit6		:	1 ; /*!< GPIO bit 6, 							Address offset: 0x06 */
 __IO uint8_t Bit7		:	1 ; /*!< GPIO bit 7, 							Address offset: 0x07 */
 
	__IO uint8_t Bit8		:	1 ; /*!< GPIO bit 8, 							Address offset: 0x08 */
 __IO uint8_t Bit9		:	1 ; /*!< GPIO bit 9, 							Address offset: 0x09 */
 __IO uint8_t Bit10	:	1 ; /*!< GPIO bit 10, 	 						Address offset: 0x0A */
 __IO uint8_t Bit11	:	1 ; /*!< GPIO bit 11, 							Address offset: 0x0B */
 
	__IO uint8_t Bit12	:	1 ; /*!< GPIO bit 12, 						Address offset: 0x0C */
 __IO uint8_t Bit13	:	1 ; /*!< GPIO bit 13, 						Address offset: 0x0D */
 __IO uint8_t Bit14	:	1 ; /*!< GPIO bit 14, 						Address offset: 0x0E */
 __IO uint8_t Bit15	:	1 ; /*!< GPIO bit 15, 						Address offset: 0x0F */
 
 __IO uint8_t Bit16	:	1 ; /*!< GPIO bit 16, 						Address offset: 0x10 */
 __IO uint8_t Bit17	:	1 ; /*!< GPIO bit 17, 						Address offset: 0x11 */
 __IO uint8_t Bit18	:	1 ; /*!< GPIO bit 18, 						Address offset: 0x12 */
 __IO uint8_t Bit19	:	1 ; /*!< GPIO bit 19, 						Address offset: 0x13 */
 
	__IO uint8_t Bit20	:	1 ; /*!< GPIO bit 20, 						Address offset: 0x14 */
 __IO uint8_t Bit21	:	1 ; /*!< GPIO bit 21, 						Address offset: 0x15 */
 __IO uint8_t Bit22	:	1 ; /*!< GPIO bit 22, 						Address offset: 0x16 */
 __IO uint8_t Bit23	:	1 ; /*!< GPIO bit 23, 						Address offset: 0x17 */
 
	__IO uint8_t Bit24	:	1 ; /*!< GPIO bit 24, 						Address offset: 0x18 */
 __IO uint8_t Bit25	:	1 ; /*!< GPIO bit 25, 						Address offset: 0x19 */
 __IO uint8_t Bit26	:	1 ; /*!< GPIO bit 26, 	 						Address offset: 0x1A */
 __IO uint8_t Bit27	:	1 ; /*!< GPIO bit 27, 						Address offset: 0x1B */
 
	__IO uint8_t Bit28	:	1 ; /*!< GPIO bit 28, 						Address offset: 0x1C */
 __IO uint8_t Bit29	:	1 ; /*!< GPIO bit 29, 						Address offset: 0x1D */
 __IO uint8_t Bit30	:	1 ; /*!< GPIO bit 30, 						Address offset: 0x1E */
 __IO uint8_t Bit31	:	1 ; /*!< GPIO bit 31, 						Address offset: 0x1F */
}BITMODE_TypeDef;
#include "main.h"
#include "stm32l073xx.h"
#include "stm32l0xx_hal.h"
#include "UserSystemDefine.h"
 
#define		ALED1			GPIOA_ODR->Bit9					// ALARM LED 1
#define		ALED2			GPIOA_ODR->Bit10				// ALARM LED 2
#define		PLED			GPIOB_ODR->Bit2					// POWER LED
 
if(htim->Instance==TIM2)
{
	//HAL_GPIO_TogglePin(GPIOA, ALED1_Pin);
	//GPIOA_ODR->Bit9 ^= 1;
	//GPIOA_ODR->Bit10 = ~GPIOA_ODR->Bit9;
	ALED1 ^= 1;
	ALED2 = ~ALED1;
	
}else if(htim->Instance==TIM3)
{
	//GPIOB_ODR->Bit2 ^= 1;
	PLED ^= 1;
}

Have a good time !

3 replies

Nikita91
Lead II
September 10, 2020

There is no such facility with the GCC compiler for ARM.

The STM32 GPIO architecture use a register (GPIOx->BSRR) to set and reset bits individually, so no read-modify-write to use. This is thread safe, while ^= is not.

A tip to toggle a pin (The optimization is based on this text in reference manuals: "Note: If both BSx and BRx are set, BSx has priority."): 

// Toggle multi pins on the port GPIOx
__STATIC_INLINE void bspTogglePins (GPIO_TypeDef * GPIOx, uint32_t pinMask)
{
	uint32_t odr = GPIOx->ODR ;
	
	GPIOx->BSRR = ((odr & pinMask) << 16u) | (~odr & pinMask) ;
}

QNGUY.1
QNGUY.1AuthorBest answer
Associate
September 14, 2020

Thanks Nikita who had given me a new idea !

Finally, we also parsed GPIOx.ODR to bits successfully

#include "main.h"
#include "stm32l073xx.h"
#include "stm32l0xx_hal.h"
 
#define GPIOA_ODR ((BITMODE_TypeDef *) (GPIOA_BASE + 0x14U))
#define GPIOB_ODR ((BITMODE_TypeDef *) (GPIOB_BASE + 0x14U))
#define GPIOC_ODR ((BITMODE_TypeDef *) (GPIOC_BASE + 0x14U))
 
 
typedef struct
{
 __IO uint8_t Bit0		:	1 ; /*!< GPIO bit 0, 							Address offset: 0x00 */
 __IO uint8_t Bit1		:	1 ; /*!< GPIO bit 1, 							Address offset: 0x01 */
 __IO uint8_t Bit2		:	1 ; /*!< GPIO bit 2, 							Address offset: 0x02 */
 __IO uint8_t Bit3		:	1 ; /*!< GPIO bit 3, 							Address offset: 0x03 */
 
	__IO uint8_t Bit4		:	1 ; /*!< GPIO bit 4, 							Address offset: 0x04 */
 __IO uint8_t Bit5		:	1 ; /*!< GPIO bit 5, 							Address offset: 0x05 */
 __IO uint8_t Bit6		:	1 ; /*!< GPIO bit 6, 							Address offset: 0x06 */
 __IO uint8_t Bit7		:	1 ; /*!< GPIO bit 7, 							Address offset: 0x07 */
 
	__IO uint8_t Bit8		:	1 ; /*!< GPIO bit 8, 							Address offset: 0x08 */
 __IO uint8_t Bit9		:	1 ; /*!< GPIO bit 9, 							Address offset: 0x09 */
 __IO uint8_t Bit10	:	1 ; /*!< GPIO bit 10, 	 						Address offset: 0x0A */
 __IO uint8_t Bit11	:	1 ; /*!< GPIO bit 11, 							Address offset: 0x0B */
 
	__IO uint8_t Bit12	:	1 ; /*!< GPIO bit 12, 						Address offset: 0x0C */
 __IO uint8_t Bit13	:	1 ; /*!< GPIO bit 13, 						Address offset: 0x0D */
 __IO uint8_t Bit14	:	1 ; /*!< GPIO bit 14, 						Address offset: 0x0E */
 __IO uint8_t Bit15	:	1 ; /*!< GPIO bit 15, 						Address offset: 0x0F */
 
 __IO uint8_t Bit16	:	1 ; /*!< GPIO bit 16, 						Address offset: 0x10 */
 __IO uint8_t Bit17	:	1 ; /*!< GPIO bit 17, 						Address offset: 0x11 */
 __IO uint8_t Bit18	:	1 ; /*!< GPIO bit 18, 						Address offset: 0x12 */
 __IO uint8_t Bit19	:	1 ; /*!< GPIO bit 19, 						Address offset: 0x13 */
 
	__IO uint8_t Bit20	:	1 ; /*!< GPIO bit 20, 						Address offset: 0x14 */
 __IO uint8_t Bit21	:	1 ; /*!< GPIO bit 21, 						Address offset: 0x15 */
 __IO uint8_t Bit22	:	1 ; /*!< GPIO bit 22, 						Address offset: 0x16 */
 __IO uint8_t Bit23	:	1 ; /*!< GPIO bit 23, 						Address offset: 0x17 */
 
	__IO uint8_t Bit24	:	1 ; /*!< GPIO bit 24, 						Address offset: 0x18 */
 __IO uint8_t Bit25	:	1 ; /*!< GPIO bit 25, 						Address offset: 0x19 */
 __IO uint8_t Bit26	:	1 ; /*!< GPIO bit 26, 	 						Address offset: 0x1A */
 __IO uint8_t Bit27	:	1 ; /*!< GPIO bit 27, 						Address offset: 0x1B */
 
	__IO uint8_t Bit28	:	1 ; /*!< GPIO bit 28, 						Address offset: 0x1C */
 __IO uint8_t Bit29	:	1 ; /*!< GPIO bit 29, 						Address offset: 0x1D */
 __IO uint8_t Bit30	:	1 ; /*!< GPIO bit 30, 						Address offset: 0x1E */
 __IO uint8_t Bit31	:	1 ; /*!< GPIO bit 31, 						Address offset: 0x1F */
}BITMODE_TypeDef;
#include "main.h"
#include "stm32l073xx.h"
#include "stm32l0xx_hal.h"
#include "UserSystemDefine.h"
 
#define		ALED1			GPIOA_ODR->Bit9					// ALARM LED 1
#define		ALED2			GPIOA_ODR->Bit10				// ALARM LED 2
#define		PLED			GPIOB_ODR->Bit2					// POWER LED
 
if(htim->Instance==TIM2)
{
	//HAL_GPIO_TogglePin(GPIOA, ALED1_Pin);
	//GPIOA_ODR->Bit9 ^= 1;
	//GPIOA_ODR->Bit10 = ~GPIOA_ODR->Bit9;
	ALED1 ^= 1;
	ALED2 = ~ALED1;
	
}else if(htim->Instance==TIM3)
{
	//GPIOB_ODR->Bit2 ^= 1;
	PLED ^= 1;
}

Have a good time !

Nikita91
Lead II
September 14, 2020

I am curious to see the code generated for such operations. It is undoubtedly far from optimal.

Also it uses read-modify-write so not thred safe: Another thread must not use another IO from the same port at the same time ...