如何理解stm32中的#define RCC ((RCC_TypeDef *) RCC_BASE)
#define RCC ((RCC_TypeDef *) RCC_BASE)
在stm32寄存器开发中,经常看到下面的写法:
#define RCC ((RCC_TypeDef *) RCC_BASE),笔者第一次看到颇感困惑,最终也算搞懂了一点。
其中,RCC_TypeDef是一个定义的结构体,具体代码如下:
typedef struct
{
__IO uint32_t CR;
__IO uint32_t CFGR;
__IO uint32_t CIR;
__IO uint32_t APB2RSTR;
__IO uint32_t APB1RSTR;
__IO uint32_t AHBENR;
__IO uint32_t APB2ENR;
__IO uint32_t APB1ENR;
__IO uint32_t BDCR;
__IO uint32_t CSR;
#ifdef STM32F10X_CL
__IO uint32_t AHBRSTR;
__IO uint32_t CFGR2;
#endif /* STM32F10X_CL */
#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
uint32_t RESERVED0;
__IO uint32_t CFGR2;
#endif /* STM32F10X_LD_VL || STM32F10X_MD_VL || STM32F10X_HD_VL */
} RCC_TypeDef;
其次是RCC_BASE来源:
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define PERIPH_BASE ((uint32_t)0x40000000)
typedef unsigned int uint32_t;
可以看到,RCC_BASE实际上是一个字节长度为4的无符号整形变量,经过各种宏定义,相加,最终RCC_BASE的值为 0x40000000+0x20000+0x1000=0x40021000
;
下面详细分析 #define RCC ((RCC_TypeDef *) RCC_BASE)
我们知道了RCC_BASE是一个无符号整型变量,为了将变量与地址0x40021000所指向的存储单元对应起来,我们通过( *)RCC_BASE强制类型转换,使得RCC_BASE变成我们所需要的地址,也就是寄存器的基地址。
而(RCC_TypeDef *) 的意思是类型长度为RCC_TypeDef,也就是该地址指向的存储单元占据多少个字节,通常我们采用(int *)RCC_BASE来说明,但是使用RCC_Typede可以方便知道此组寄存器需要多少字节。
(RCC_TypeDef *) RCC_BASE,也就是在RCC_BASE基地址申请了一个结构体,结构体RCC_TypeDef包含10个4字节成员,他们在基地址上开辟了连续的10个32变量的存储空间,
最后再由宏定义,将((RCC_TypeDef *) RCC_BASE)由RCC代替,这样可以直接通过RCC访问结构体的成员地址。
硬件联系
那么此写法是如何与寄存器建立联系的,通过查阅stm32官方参考手册,不难发现,RCC_BASE的值刚好代表RCC寄存器组起始地址。
通过查看RCC寄存器组的地址偏移,发现一个寄存器偏移4个字节,刚好对应结构体中uint32_t 。
下面做一个简单的实验,为了方便,直接把RCC_BASE赋值为0x10000000:
#include <stdio.h>
typedef unsigned int uint32_t;
typedef struct {
volatile uint32_t CR;
volatile uint32_t CFGR;
volatile uint32_t CIR;
volatile uint32_t CSR;
}RCC_Typedef;
#define RCC ((RCC_Typedef *)0x10000000)
int main() {
printf("%x\n",&(RCC->CR));
printf("%x\n",&(RCC->CFGR));
printf("%x\n",&(RCC->CIR));
printf("%x\n",&(RCC->CSR));
printf("%d\n",sizeof (RCC_Typedef));
}
return 0;
}
输出结果为:
由此可见,RCC_TypeDef的长度为4*4=16。RCC->CR的地址为10000000。因为uint32_t字节长度为4,所以结构体内的成员变量地址4字节的累加。
参考来源:
[1]:https://www.cnblogs.com/caolinsummer/p/5643942.html
[2]:https://blog.csdn.net/childbor/article/details/86770360#:~:text=%23define%20RCC%20%28%28RCC_TypeDef%20%2A%29%20RCC_BASE%29%20RCC_TypeDef%E6%98%AF%E4%B8%80%E4%B8%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E7%BB%93%E6%9E%84%E4%BD%93,RCC_BASE%E6%98%AF%E4%B8%80%E4%B8%AAunsigned%20long%EF%BC%8832%E4%BD%8D%E6%95%B0%E5%80%BC%EF%BC%89%20%E7%AE%80%E5%8C%96%E5%90%8E%E6%98%AF%EF%BC%9A%20%28int%20%2A%29%200xb8000000.