写在前面:参考野火Hal库教学<第4讲-STM32介绍_哔哩哔哩_bilibili>
以及野火的Hal库学习手册(官网可找到)
初识STM32
1 名字解读
ST是指ST意法半导体,M是Microelectronics的首字母M,也即是微电子的意思,32是32位寄存器。
2 分类
32有很多系列,市场上主流的内核有Cortex-M0 M3 M4 M7,像我们常听到的F103也即F1系列用的便是M3内核的芯片,而我们打rm的时候很多队伍会选择官方的F407开发板,那个是M4内核的芯片,那么问题来了,这些不同内核的芯片的性能差别在哪里呢?下面给大家列举一下主要区别:
- M4内核比M3多了DSP数据处理的指令,简单理解为可以处理浮点数数据,在需要用到大量浮点数运算的时候是要选择M4内核的,如四轴飞行器及平衡车
- M7内核多了缓存cache TCM
3 命名方式
举个例子STM32f103c8t6
F代表基础型,103也代表基础性,C代表48pin,8代表FLASH大小也64kb,T代表QFP封装,6代表温度等级
4. IO
IO指的是芯片引出来的这些脚,具体可以查询数据手册
5. 芯片内部
内核以外的部分统称片上外设
系统框图
驱动单元:内核部分
**总线 **:
- ICode总线:我们写好的程序经过编译之后都是一条条指令,存放在FLASH 中,内核要读取这些指令来执行程序就必须通过 ICode 总线,他是专门读取指令的。
- DCode总线:我们在写程序的时候,数据有
常量和变量两种,常量就是固定不变的,用 C 语言中的 const 关键字修饰,是放到内部的 FLASH当中的,变量是可变的,不管是全局变量还是局部变量都放在内部的 SRAM。 - 系统总线:系统总线主要是访问外设的寄存器
- DMA总线:DMA 总线也主要是用来传输数据,这个数据可以是在某个外设的数据寄存器,可以在 SRAM,
可以在内部的 FLASH。
被动单元:
- 闪存:FLASH,我们编好的程序就放这里,内核通过Icode来读取。
- SRAM:内部的 SRAM,即我们通常说的 RAM,程序的变量,堆栈等的开销都是基于内部的 SRAM。内核通过 DCode 总线来访问它。
- FSMC:FSMC 的英文全称是 Flexible static memory controller,FSMC 只能扩展静态的内存,即名称里面的S:static,不能是动态的内存,比如 SDRAM 就不能扩展
- AHB 到 APB 的桥:从 AHB 总线延伸出来的两条 APB2 和 APB1 总线,上面挂载着 STM32 各种各样的特色外设
存储器映射
简单来讲就是给存储器分配地址;
在这 4GB 的地址空间中,ARM 已经粗线条的平均分成了 8 个块,每块 512MB。
Block0 用来设计成内部FLASH,Block1 用来设计成内部 RAM,Block2 用来设计成片上的外设
Block0
Block2
寄存器映射
在存储器 Block2 这块区域,设计的是片上外设,它们以四个字节为一个单元,共 32bit(1个字节等于8bit),当我们控制这些单元时就可以驱动外设工作,而操作地址这一行为我们很容易想到指针,在C里面我们的确可以用指针来访问这些单元,也就是寻址的方式。这个在后面再做详细讲解。
外设地址映射
片上外设区分为三条总线,根据外设速度的不同,不同总线挂载着不同的外设,APB1 挂载低速外设,APB2 和 AHB 挂载高速外设。相应总线的最低地址我们称为该总线的基地址
外设基地址
总线上挂载着各种外设,这些外设也有自己的地址范围,特定外设的首个地址称为“XX 外设基地址”
外设寄存器
在 XX 外设的地址范围内,分布着的就是该外设的寄存器。以 GPIO 外设为例,GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚,基本功能是控制引脚输出高电平或者低电平
如何操作寄存器
封装:以下是对于寄存器的封装,uint32_t是typedef unsigned int,因为我们不需要使用到负数。而且结构体变量的内存空间是连续的,这样我们结构体内的每一个变量便可以当作与之相对应的寄存器,同时没个变量又是32位的,那正好对应32位的寄存器。
typedef struct
{ uint32_t CRL;/*GPIO 端口配置低寄存器地址偏移: 0x00 */ uint32_t CRH;/*GPIO 端口配置高寄存器地址偏移: 0x04 */ uint32_t IDR;/*GPIO 数据输入寄存器地址偏移: 0x08 */ uint32_t ODR;/*GPIO 数据输出寄存器地址偏移: 0x0C */ uint32_t BSRR;/*GPIO 位设置/清除寄存器地址偏移: 0x10 */ uint32_t BRR;/*GPIO 端口位清除寄存器地址偏移: 0x14 */
uint16_t LCKR;/*GPIO 端口配置锁定寄存器地址偏移: 0x18 */ } GPIO_TypeDef;
位操作修改寄存器
基本问题是我们可能只需要改变寄存器的某个位,而其他位保持不变,那么就需要我们用到C的位操作,这里直接引用野火书内的一个例子,这里涉及较多是C的内容,便不做具体展开。
基本问题是我们可能只需要改变寄存器的某个位,而其他位保持不变,那么就需要我们用到C的位操作,这里直接引用野火书内的一个例子,这里涉及较多是C的内容,便不做具体展开。
[外链图片转存中…(img-kHTOjud0-1672067565942)]