kevinc

主攻ZYNQ及RTOS开发,关注Flash存储

stm32的寄存器映射方法

0
阅读(1157) 评论(1)

小目标是对几个io口延时翻转,即实现闪灯。

最终控制:GPIOA端口的ODR寄存器,对应基地址0x4001 0800 - 0x4001 0BFF,偏移地址0x0C。


如何把类似的几百个寄存器映射成方便操作的指针或变量?


下面从顶部向下逐步分解。

直接用cube产生代码如下,调用HAL_GPIO_TogglePin函数

 /* USER CODE BEGIN WHILE */

  while (1)

  {

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

                   HAL_GPIO_TogglePin(GPIOA,user_led_1_Pin);

                   HAL_GPIO_TogglePin(GPIOA,user_led_2_Pin);

                   HAL_GPIO_TogglePin(GPIOA,user_led_3_Pin);

                   HAL_GPIO_TogglePin(GPIOA,user_led_4_Pin);

                   HAL_Delay(1000);

  }

  /* USER CODE END 3 */


Toggle函数把指定bit逐次异或(bit=0与1异或=1,bit=1与1异或=0,即实现翻转)

void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

{

  /* Check the parameters */

  assert_param(IS_GPIO_PIN(GPIO_Pin));

  GPIOx->ODR ^= GPIO_Pin;

}


参数user_led_1_Pin,根据如下宏定义,把io对应位标为1

#define user_led_1_Pin GPIO_PIN_0

#define user_led_1_GPIO_Port GPIOA

#define user_led_2_Pin GPIO_PIN_1

#define user_led_2_GPIO_Port GPIOA

#define user_led_3_Pin GPIO_PIN_2

#define user_led_3_GPIO_Port GPIOA

#define user_led_4_Pin GPIO_PIN_3

#define user_led_4_GPIO_Port GPIOA


#define GPIO_PIN_0                 ((uint16_t)0x0001)

#define GPIO_PIN_1                 ((uint16_t)0x0002)

#define GPIO_PIN_2                 ((uint16_t)0x0004)

#define GPIO_PIN_3                 ((uint16_t)0x0008)

#define GPIO_PIN_4                 ((uint16_t)0x0010)

#define GPIO_PIN_5                 ((uint16_t)0x0020)

#define GPIO_PIN_6                 ((uint16_t)0x0040)

#define GPIO_PIN_7                 ((uint16_t)0x0080)

#define GPIO_PIN_8                 ((uint16_t)0x0100)

#define GPIO_PIN_9                 ((uint16_t)0x0200)

#define GPIO_PIN_10                ((uint16_t)0x0400)

#define GPIO_PIN_11                ((uint16_t)0x0800)

#define GPIO_PIN_12                ((uint16_t)0x1000)

#define GPIO_PIN_13                ((uint16_t)0x2000)

#define GPIO_PIN_14                ((uint16_t)0x4000)

#define GPIO_PIN_15                ((uint16_t)0x8000)

#define GPIO_PIN_All                ((uint16_t)0xFFFF)



参数GPIOA,是个struct型指针,指向GPIOA_BASE表示的地址。

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)

#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)

#define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)

#define GPIOE               ((GPIO_TypeDef *) GPIOE_BASE)


 GPIOA_BASE的地址如下表示(查手册 RM0008 Reference manual)

#define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)

#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)

#define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)

#define GPIOD_BASE            (APB2PERIPH_BASE + 0x1400)

#define GPIOE_BASE            (APB2PERIPH_BASE + 0x1800)


#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)


#define PERIPH_BASE           ((uint32_t)0x40000000)



st的工程师合理运用结构体的特点,将寄存器的偏移地址与结构体变量对应。

Port configuration register low (GPIOx_CRL) (x=A..G)
Address offset: 0x00
Port configuration register high (GPIOx_CRH) (x=A..G)
Address offset: 0x04
Port input data register (GPIOx_IDR) (x=A..G)
Address offset: 0x08h
Port output data register (GPIOx_ODR) (x=A..G)
Address offset: 0x0C


typedef struct

{

  __IO uint32_t CRL;

  __IO uint32_t CRH;

  __IO uint32_t IDR;

  __IO uint32_t ODR;

  __IO uint32_t BSRR;

  __IO uint32_t BRR;

  __IO uint32_t LCKR;

} GPIO_TypeDef;


定义一个struct就会对应一个存储地址,内部的变量依次占用存储空间。

如果#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE),则定义的GPIOA是一个结构体指针,指向基地址。

内部的变量依次对应有其偏移地址,uint32_t 占32bit即4Byte,那么CRL偏移0x00,CRH偏移0x04,IDR偏移0x08,ODR偏移0x0C 。(结构体有默认的对齐方式,分配空间一定是最大变量的整数倍)

用struct的方式很好地将端口以及其寄存器匹配起来,层次分明。



对REG内单个bit位的处理


1、将bit7位置0,其他位不变。

    GPIOx->CRL &= ~ (uint32_t)(1<<7);

分析: (1<<7)即0000_0000_0000_0000_0000_0000_1000_0000,

取反后变成1111_1111_1111_1111_1111_1111_0111_1111,跟原reg值与,即实现置0

2、将bit7位置1,其他位不变。

    GPIOx->CRL |= (uint32_t)(1<<7);

3、将bit7位取反,其他位不变。

    GPIOx->CRL ^= (uint32_t)(1<<7);


继续把移位值define成常量,#define CNF1_1  7 ,这样每个bit位都实现了定义。


\Drivers\CMSIS\Device\ST\STM32F1xx\Include\stm32f103xb.h

可以参考这个文件里面position和mask的做法。

/*******************  Bit definition for GPIO_CRL register  *******************/

#define GPIO_CRL_MODE_Pos                 (0U)                             

#define GPIO_CRL_MODE_Msk                (0x33333333U << GPIO_CRL_MODE_Pos)

#define GPIO_CRL_MODE                        GPIO_CRL_MODE_Msk


  1. ***此内容已被管理员屏蔽***