STM32(CM3内核) 内存映射
一.CM3内核简介
《CM3权威指南》摘抄一段简介 STM32是一个拥有32位总线的MCU,它每次可以访问32 bit 的数据,由于内核是地址总线是32 bit 的,所以CPU可以向外部访问2^32 = 4GB 的地址,每个地址都可以有32 bit的数据,通过指令总线和数据总线传输指令或者数据。
看到这里,你可能有点蒙,文字我都懂,组合起来怎么不理解,没关系,当年我也和你一样,其实有一方面是你阅读的书籍太少。 我给你推荐几本神书,传递我毕生功力。让你对计算机体系结构有大概的了解:《计算机组成原理》,《汇编语言》,《微机原理与接口技术》,《操作系统》,在你接触完这几本书之后,相信你对处理器或者控制器会有不一样的理解。 接下来我给你画个图 CPU通过指令总线取指,然后译码器译码,最后再执行指令,这当然只是简单的描述,具体细节还得由你去看看《微机原理与接口技术》。看到这里,我不知道你有没有一个想法,在STM32中,程序存储器在哪里,起始地址是多少,内存有多大。 数据存储器在哪里,起始地址是多少,内存有多大。 处理器只有内存和CPU及内核寄存器就能工作了吗? 别急,等我一一道来。
二.CM3内核地址映射
实际上,如果MCU只有内存和CPU是可以工作的,但是这样没有意义,要有IO(外设),我们才能实现很多东西。 接下来我们看一下CM3如何规定地址映射 再来看一个更详细的 前面说过,CM3可以访问4GB的地址空间,刚好这块内存就是4GB,为什么我要说刚好?而不是一定?CM3可以访问4GB,所以内存就得4GB?有点意思了,所以我要给你讲两个公司:
ARM公司:ARM 应该不陌生把,CM3内核便是由他设计的,内核是什么?包不包括内存?是不包括的,内核就是CPU以及一些片上寄存器和片上外设,ARM只设计内核,不生产处理器,同时也规定了地址必须怎么映射,比如0x0800 0000~0x0808 0000是flash内存映射,你能把这段映射到GPIO吗?这是不行的,因为如果ARM 不把内存映射规定好,那每个芯片厂商用CM3内核来设计处理器就会让开发者很头疼,1000家处理器就有1000种映射,那你还愿意学单片机?
ST公司:STM32F103便是ST设计的,采用CM3内核,将外设以及内存集成到片上,内存映射也遵循了CM3。 所以我们可以理清一下内核,内存,IO(外设)的关系,从存储器映射可以知道,内核通过指令总线和数据总线对内存进行访问,通过地址读写数据实现对GPIO等外设操作。
三.搭建代码,实现映射
说了这么多,我们实际上手操作,代码对照着存储器映射来。 这个例子是让GPIOB pin0 输出高低电平来控制灯的状态。
下面展示一些 内联代码片 。
#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE + 0x18)
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef struct
{
uint32_t CRL;
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint32_t LCKR;
}GPIO_TypeDef;
typedef struct
{
uint32_t CR;
uint32_t CFGR;
uint32_t CIR;
uint32_t APB2RSTR;
uint32_t APB1RSTR;
uint32_t AHBENR;
uint32_t APB2ENR;
uint32_t APB1ENR;
uint32_t BDCR;
uint32_t CSR;
}RCC_TypeDef;
#define GPIOB ((GPIO_TypeDef*)GPIOB_BASE)
#define RCC ((RCC_TypeDef*)RCC_BASE)
#define GPIOB ((GPIO_TypeDef*)GPIOB_BASE) 这句可以算出 GPIO 指向的结构体地址 是0x4001 0C00 是不是跟映射表PORT B起始地址是一样的? GPIO_TypeDef 结构体成员地址就是从GPIOB 起始地址开始算的,每个结构体顺序也遵从GPIO的寄存器的偏移地址,所以可以通过结构体实现对GPIO的控制。
int main (void)
{
//使能APB2的GPIOB时钟
RCC->APB2ENR |= ( (1) << 3 );
// 配置IO口为输出
GPIOB->CRL &= ~( (0x0f) << (4*0) );
GPIOB->CRL |= ( (1) << (4*0) );
// 控制 ODR 寄存器
GPIOB->ODR &= ~(1<<0);
GPIOB->ODR |= (1<<0);
while(1);
}
主函数是让GPIOB输出高电平,其实也就是直接控制地址内存,实现外设的操作。
|