一、STM32的开发方式:标准库,HAL库,寄存器开发
1、寄存器开发:通过直接操作寄存器进行开发,但是由于STM32的寄存器数量众多,逐个查询比较繁琐。
2、标准库:ST公司为每一款芯片都编写了一份库文件,也就是工程文件里的stm32F1XX…之类的,这些.c .h文件中包含了一些常用量的宏定义,一些外设也通过结构体进行包装起来,例如GPIO口时钟等,只需要配置结构体变量的成员就可以修改外置的配置寄存器。
3、HAL(Hardware Abstraction Layer)库:硬件抽象层。是ST公司为了更好的移植性推出的一个软件库。相对于标准库来说更为简洁。只要使用相通的外设,程序可以通用。ST公司研发的STMcube软件,可以通过图形化的配置功能,直接生成整个使用HAL库的工程文件
4、_weak修饰符:弱修饰符,这是存在于HAL库之中的,加上了__weak 修饰符的函数,用户可以在用户文件中重新定义一个同名函数,最终编译器编译的时候,会选择用户定义的函数,如果用户没有重新定义这个函数,那么编译器就会执行__weak 声明的函数,并且编译器不会报错。(详见STM32F1开发指南-HAL版本中的P84)。
二、STM32的启动方式(图1):
1、用户闪存存储器启动模式(Main Flash memory)
正常的用户工作模式,通过jtag和swd模式进行下载程序,重启后也直接从这启动程序。
2、系统存储器启动模式(system memory)
从系统存储器启动,这种模式启动的程序功能是由厂家设置的。
3、SRAM启动(Embedded Memory)
SRAM,没有程序存储的能力,这个模式一般用于程序调试。
图1 BOOT0、BOOT1 启动模式表
三、STM32芯片架构
图2 STM32系统架构
1、四个驱动单元:
Cortex™-M3内核DCode总线
Cortex™-M3内核系统总线System
通用DMA1
通用DMA2
2、四个被动单元(外设)
内部闪存存储器FLASH
内部SRAM
FSMC
AHB(Advanced High performance Bus,高级高性能总线)到APB(Advanced Peripheral Bus,高级外围总线)的桥,连接所有的外设
主要由内核(ARM提供)和片上外设(ST设计生产,)组成。若与电脑类比,内核与外设就如同电脑上的 CPU 与主板、内存、显卡、硬盘的关系。STM32F103 采用的是 Cortex-M3 内核,内核即 CPU,由 ARM 公司设计。芯片生产厂商(SOC)如 ST、 TI、 Freescale,负责在内核之外设计部件并生产整个芯片,这些内核之外的部件被称为核外外设或片上外设(外部设备的简称,是指集成电路芯片外部的设备,集成电路芯片与外部设备的连接一般需要专门的接口电路和总线的连接(包括控制总线I-CODE、地址总线D-CODE和数据总线S-CODE等)),由于集成在芯片上的,所以叫做片上外设:如GPIO、 USART(串口)、 I2C、 SPI 等都叫做片上外设。
驱动单元:
I-Code 总线是一条基于AHB-Lite 总线协议的 32 位总线,负责在 0x0000_0000 – 0x1FFF_FFFF 之间的取指操作。取指以字的长度执行。
D-Code 总线也是一条基于 AHB-Lite 总线协议的 32 位总线,负责在0x0000_0000 – 0x1FFF_FFFF之间的数据访问操作。因为数据可以被 Dcode 总线和 DMA 总线访问(向flash,SRAM,或外设数据寄存器里面取数据),所以为了避免访问冲突,在取数的时候需要经过一个总线矩阵来仲裁,决定哪个总线在取数,取到的数据可以暂存在Cortex™-M3内核里面的寄存器在进行处理。
System系统总线也是一条基于 AHB-Lite 总线协议的 32 位总线,负责在0x2000_0000 – 0xDFFF_FFFF 和0xE010_0000– 0xFFFF_FFFF 之间的所有数据传送,取指和数据访问都算上。系统总线主要是访问外设的寄存器,我们通常说的寄存器编程,即读写寄存器都是通过这根系统总线来完成的。
DMA(也算外设)是直接存储器访问,DMA在DMA控制器(有7个通道,每个通道专门用来管理一个或多个外设对存储器访问的请求,还有一个仲裁器来协调各个DMA请求的优先权)的控制下,实现让存储器与外设、外设与外设之间独立直接交换数据,中间不需要经过CPU的累加器中转,并且内存地址的修改、传送完毕的结束报告都是由硬件电路(DMA控制器)实现的,CUP除了在数据传输开始和结束时进行中断处理外,在整个传输过程中CPU都可以和输入输出处于并行操作状态,一个DMA传送只需要执行一个DMA周期,相当于一个总线读写周期。
总线矩阵:主要负责协调内核总线与DMA主控总线之间的访问仲裁,因为系统内核总线和DMA主控总线都能访问数据(来自FLASH、SRAM或者某个外设),避免冲突,需要总线矩阵来仲裁决定在哪个总线进行访问。
被动单元:
内部FLASH:一般程序编译后的二进制代码存储的地方,常量或者const修饰的也放在这里。
内部SRAM:程序函数内部的局部变量和全局变量,堆(malloc分配)栈(局部变量)等,内核通过DCODE总线访问SRAM
FSMC(Flexible static memory controller):灵活静态存储控制器,是 STM32F10xx 中一个很有特色的外设通过FSMC我们可以扩展内存,如外部的SRAM,NANDFLASH 和 NORFLASH。但有一点我们要注意的是,FSMC 只能扩展静态的内存,即名称里面的 S:static,不能是动态的内存,比如 SDRAM 就不能扩展。
AHB总线:是Advanced High performance Bus的缩写,译作高级高性能总线,这是一种“系统总线”。AHB主要用于高性能模块(如CPU、DMA和DSP等)之间的连接。AHB 系统由主模块、从模块和基础结构(Infrastructure)3部分组成,整个AHB总线上的传输都由主模块发出,由从模块负责回应
APB1总线:连接的是低速外设,包括电源接口、备份接口、CAN、USB、I2C1、I2C2、USART2、USART3、UART4、UART5、SPI2、SP3等。操作速度限制于36MHZ
APB2总线:连接的是高速外设,包括UART1、SPI1、Timer1、ADC1、ADC2、ADC3、所有的普通I/O口(PA-PE)、第二功能I/O(AFIO)口等。操作速度限制于72MHZ,如下图3
图3 MX中的时钟树
STM32外设:
1.MISC:把NVIC的外设驱动放在了misc.c中(NVIC提供中断控制器,用于总体管理异常,称之为“内嵌向量中断控制器)
2.ADC:模数转换
3.BKP:备份数据
4.CAN:CAN总线是一种通信方式。STM32主要负责程序的运行,而CAN总线只是一种通信协议。STM32之间的通信可以通过CAN总线进行数据交换。
5.CEC:网络模块
6.DAC:数模转换
7.DBGMCU:调试支持
8.DMA:直接内存存取控制器(传输数据)
9.EXTI:外部中断事件控制器
10.FLASH:闪存存储器
11.FSMC:灵活的静态存储器控制器
12.GPIO:通用输入输出
13.I2C:I2C接口
14.IWDG:独立看门狗
15.PWR:电源/功耗控制
16.RCC:复位与时钟控制器
17.RTC:实时时钟
18.SDIO:SDIO接口
19.SPI:串行外设接口
20.TIM:定时器
21.USART:通用同步/异步接收器
22.WWDG:窗口看门狗
四、存储器的映射
存储器:物理存在的:像单片机里面的FLASH RAM等,一般用来保存程序代码,程序运行中产生的数据等。存储器本身不具有地址,它的地址由厂商或者用户分配,给存储器分配地址的过程就称为存储器的映射,如果给存储器再分配一个地址就叫做存储器的重映射。程序存储器,数据存储器,寄存器和输入输出端口被组织在同一个4GB的线性空间内,数据字节以小端格式存放在存储器中。一个字里的最低地址字节被认为是该字的最低有效字节,而最高地址字节是最高有效字节。
1、STM32的地址空间
4G的地址空间就是地址编码的范围。编码就是对每一个程序存储器、数据存储器、寄存器和输入输出端口(一个字节)分配一个唯一的地址号码,这个过程又叫做“编址”或者“地址映射”。地址空间的大小是由芯片内cpu的总线数量来决定的,STM32的总线有32根,而内存空间被划分成一个个的内存单元,一个内存单元为一个字节,给内存单元进行编号,这个编号就叫做内存地址,所以一共32条线,每条线有可以输出0或1,则那么一共有232个地址,对应232个单元,就是232Bytes,就是4GB,4GB被分成了8个块,一个块大小为512MB
拓展:在C语言中的指针是一种数据类型,指针类型的变量存放的是地址,但是指针不等同于地址。定义指针变量的时候要带有*
Block0的内部区域划分:
Block1的内部区域功能划分:
Block2的内部区域功能划分:
2、STM32的物理空间和地址空间
①物理存储器是指实际存在的具体存储器芯片,存储地址空间是指对存储器的编码的范围,地址空间也叫做寻址空间。
②有的物理存储器被看作一个由若干存储单元组成的逻辑存储器,每个物理存储器在这个逻辑存储器中占有一个地址段,即一段地址空间。
③CPU在这段地址空间中读写数据,实际上就是在相对应的物理存储器中读写数据。STM32将外设等都映射为地址的形式,对地址的操作就是对外设的操作。
④stm32的外设地址从0x4000 0000开始,可以看到在库文件中,是通过基于0x4000 0000地址的偏移量来操作寄存器以及外设的
⑤地址空间的大小和物理存储器的大小并不一样。STM32有4GB的地址空间(寻址空间),但一般的物理存储器只有1MB左右(F103ZE的FLASH为512KB)
3、STM32的内存管理
STM32中的SRAM起始地址是0x2000 0000 终止地址是0x2000 0000 +固定容量的大小。
STM32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小。
在一个STM32程序中,从内存高地址到低地址依次分布着栈区,堆区,全局区(静态区),常量区,代码区
一、栈区(stack):存放在RAM中,程序运行才会有大小。
临时创建的局部变量存放在栈区。
函数调用时,其入口参数存放在栈区。
函数返回时,其返回值存放在栈区。
const定义的局部变量存放在栈区。
2、堆区(heap):存放在RAM中,程序运行才会有大小。
堆区用于存放程序运行中被动态分布的内存段,可增可减。
可以有malloc等函数实现动态分布内存。
有malloc函数分布的内存,必须用free进行内存释放,否则会造成内存泄漏。
3、全局区(静态区)
全局区有.bss段和.data段组成,可读可写。
.bss段:
未初始化的全局变量存放在.bss段。
初始化为0的全局变量和初始化为0的静态变量存放在.bss段。
.bss段不占用可执行文件空间,其内容有操作系统初始化。
.data段
已经初始化的全局变量存放在.data段。
静态变量存放在.data段。
.data段占用可执行文件空间,其内容有程序初始化。
const定义的全局变量存放在.rodata段。
6、常量区
字符串存放在常量区。
常量区的内容不可以被修改。
7、代码区
程序执行代码存放在代码区。
字符串常量也有可能存放在代码区。
下图中Code是代码占用的大小,RO-data是只读常量,RW-data是已初始化的可读可写变量,ZI-data是未初始化的可读可写变量。单位都是字节。
RAM = RW-data + ZI-data
ROM = Code + RO-data + RW-data
Code + RO data + RW data 的大小也是生成的 bin 文件的大小
五、寄存器:
1、寄存器定义
给特定功能的的单元取的别名这个别名就叫做寄存器
2、寄存器映射
Block2这块区域,设计的是片上外设,它们以4个字节为一个单元,共32bits,每个单元对应不同的功能,当控制这些单元时就可以驱动外设工作,可以找到每个单元的起始地址,通过C语言指针操作(一个单元4个字节,就可以用int *来操作这些功能单元),以功能为名为每个内存单元取一个别名,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射
六、FLASH、RAM、ROM的区别:
首先看一下计算机的硬件组成:
CPU:中央处理器包括控制器、运算器、寄存器。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和位址。在中央处理器的控制部件中,包含的寄存器有指令寄存器(IR)和程序计数器(PC)。在中央处理器的算术及逻辑部件中,包含的寄存器有累加器(ACC)
缓存(CACHE):数据交换的缓冲区(称作Cache),当某一硬件要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从内存中找。由于缓存的运行速度比内存快得多,故缓存的作用就是帮助硬件更快地运行
易失性存储器(Volatile Memory,VM):电源开启时资料存在,电源关闭则资料立刻流失(资料挥发掉),例如:SRAM、DRAM、SDRAM、DDR-SDRAM 等。
1、RAM(Random Acesss Memory):随机存取存储器,与CPU直接交换的内部存储器,随时读写,而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储媒介, 当电源关闭时RAM不能保留数据。分为SRAM(静态)和DRAM(动态)
①SRAM:当数据被存入其中后不会消失。SRAM速度非常快,是目前读写最快的存储设备了,当这个SRAM 单元被赋予0 或者1 的状态之后,它会保持这个状态直到下次被赋予新的状态或者断电之后才会更改或者消失。
②DRAM: DRAM 必须在一定的时间内不停的刷新才能保持其中存储的数据。DRAM中又有一个DDR(Double Data Rate) SDRAM(Synchronous Dynamic random access memory)
同步动态随机存取存储器,SDRAM仅在时钟信号的上升沿读取数据,而DDR在时钟信号的上升沿和下降沿都读取数据,因此,它的速度是标准SDRAM的2倍。
非易失性存储器(Non-Volatile Memory,NVM):电源开启时资料存在,电源关闭资料仍然可以保留,例如:ROM、PROM、EPROM、EEPROM、Flash ROM、FRAM、MRAM、RRAM、PCRAM 等。
1、 FLASH闪存:结合了RAM和ROM的优点,具有EEPROM的特性,而且断电不会丢失数据,近年来嵌入式用FLASH代替了ROM,用作存储Bootloader以及操作系统或者程序代码或者直接当硬盘使用.FLASH属于广义上的ROM,和EEPROM的最大区别是FLASH按扇区操作,相对于EEPROM的改进就是擦除时不再以字节为单位,而是以块为单位.常用的SSD固态硬盘多再用FLASH芯片作为存储介质。
2、 ROM只读存储器:ROM在系统停止供电的时候仍然可以保持数据
存储器层次结构:
1、寄存器:在CPU内,用来设定处理器的功能,主要是“暂时储存”设定值的地方。
2、快取存储器(Cache memory,翻译版本有缓存,快取缓存区,快取存储器:在处理器内,执行程序时“暂时储存”程序与资料的地方,通常以 SRAM 制作。
3、主存储器(Main memory):在处理器外,“暂时储存”程序与资料的地方,通常以 DRAM 制作,目前已经改良成 SDRAM 或 DDR。
4、辅助存储器(Assistant memory):在处理器外,“永久储存”程序与资料的地方,包括:快闪存储器、磁盘机、光盘机、磁带机等。
七、程序流程图
首先startup_stm32f103xe.s是启动文件,主要进行RAM中堆、栈的分配和初始化。然后system_stm32f1xx.c是系统初始化函数,主要用来:1、设置外部存储器2、重定向中断向量表,接着是main函数的入口处理,到HAL_init初始化函数,在main函数的开头被调用,然后是数字宏函数的初始化,如果需要用到片上外设的话,会调用HAL_ppp_init函数进行初始化。
八、STM32的IO口
可实现与外部通讯、控制外部硬件或采集外部硬件数据的功能配置,可以由软件配置成以下8种模式:
1、 输入浮空,不使能上拉电阻,不使能下拉电阻
2、 输入上拉,使能上拉电阻
3、 输入下拉,使能下拉电阻
4、 模拟输入,不使能上拉电阻,不使能下拉电阻
5、 开漏输出,输出寄存器是 0 时,激活 N-MOS, 而输出寄存器是 1 时,端口保持高阻态(P-MOS 不会被使能)
6、 推挽输出,输出寄存器是 0 时,激活 N-MOS, 而输出寄存器是 1 时,激活 P-MO
7、 推挽式复用功能,上拉电阻和下拉电阻使能,可以进行配置
8、 开漏复用功能
GPIO框图剖析
在使用GPIO口前需要进行时钟使能,不管是通用IO还是复用为其他功能
九、RCC(Reset and clock control)时钟控制
时钟是单片机的基础,时钟信号推动单片机内各个部分执行相应的指令。而且STM32任何外设的启动都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费,所以需要STM32的时钟系统和时钟树。
系统时钟SYSCLK 的左边 系统时钟有很多种选择,而左边的部分就是设置系统时钟使用那个时钟源,
系统时钟SYSCLK 的右边,则是系统时钟通过AHB预分频器,给相对应的外设设置相对应的 时钟频率
从左到右可以简单理解为 各个时钟源--->系统时钟来源的设置-->AHB分频-->各个外设分频倍频器--->各个外设时钟的设置
时钟系统
1各个时钟源 (左边的部分)
STM32 有4个独立时钟源:HSI、HSE、LSI、LSE。
①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。
②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。
④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体
其中LSI是作为IWDGCLK(独立看门狗)时钟源和RTC时钟源 而独立使用
而HSI高速内部时钟 HSE高速外部时钟 PLL锁相环时钟 这三个经过分频或者倍频 作为系统时钟来使用
CSS是时钟监视系统,用于监视高速外部时钟(HSE)的工作状态,倘若HSE失效,会自动切换HIS为系统时钟输入,保证系统正常运行。
Keil编写程序是默认的时钟为72Mhz,其实是这么来的:外部晶振(HSE)提供的8MHz(与电路板上的晶振的相关)通过PLLXTPRE分频器后,进入PLLSRC选择开关,进而通过PLLMUL锁相环进行倍频(x9)后,为系统提供72MHz的系统时钟(SYSCLK)。之后是AHB预分频器对时钟信号进行分频,然后为低速外设提供时钟。
RCC的主要作用:
设置系统时钟 SYSCLK、设置 AHB 分频因子(决定 HCLK 等于多少) 、 设置 APB2 分
频因子(决定 PCLK2 等于多少)、设置 APB1 分频因子(决定 PCLK1 等于多少)、设置各个外设的分频因子;控制 AHB、 APB2 和 APB1 这三条总线时钟的开启、控制每个外设的时钟的开启。对于 SYSCLK、 HCLK、 PCLK2、 PCLK1 这四个时钟的配置一般是: PCLK2 =
HCLK = SYSCLK=PLLCLK = 72M, PCLK1=HCLK/2 = 36M。这个时钟配置也是库函数的标准配置,我们用的最多的就是这个