STM32从入门到RTOS
ARM处理器
ARM(Advanced RISC Machine)是一个32位精简指令集(RISC)处理器架构,应用于许多嵌入式系统设计中。自从ARMv7系列架构开始,ARM公司推出了Cortex系列,并根据不同的应用场景推出了Cortex-M,Cortex-A和Cortex-R三款不同方向的产品。

Cortex-M3与STM32
ARM代表了一种芯片标准,体现了芯片的架构设计,而具体涉及到存储器容量,片上外设,IO引脚数等实现,则是由不同的芯片厂商进行设计的,比如当前最主流的STM32芯片,它是由ARM公司提供内核,意法半导体公司(ST)基于此内核进行设计的。

Cortex-M3是一个32位处理器内核,属于ARMv7架构,哈佛体系结构,其内部数据存取路径、寄存器、存储器接口均是32位,如STM32F1系列。
Cortex-M4是在Cortex-M3的基础上强化了运算能力,新加了浮点、DSP、并行计算等,用以满足需要有效且易于使用的控制和信号处理功能混合的数字信号控制市场,如STM32F4系列。
STM32产品命名规则
以常见搭载最小系统设计的STM32F103C8T6为例:
STM32:表示32位MCU
F103:表示基础型
C:表示芯片上含48个引脚
8:表示闪存容量为64K字节
T:表示QFP封装
6:表示工作温度范围在-40°C到85°C

STM32F103x系列
内核:ARM Cortex-M3 32位的RISC内核。
工作频率:72MHz。
内置高速存储器,具有丰富的增强I/O端口和连接到两条APB总线的外设,所有型号的器件都包含2个12位的ADC、7个定时器,还包含标准的通信接口。
根据内存大小进行分类
小容量产品(16K至32K字节):STM32F103x4和STM32F103x6
中等容量产品(64K至128K字节):STM32F103x8和STM32F103xB
大容量产品(256K至512K字节):STM32F103xC、STM32F103xD和STM32F103xE
Cortex-M3总线接口
Cortex-M3总线接口基于AHB-Lite(Advanced High Performance Bus 高级高性能总线)和APB(Advanced Peripheral Bus 高级外围总线)协议。
I-Code:指令总线,AHB‐Lite 总线协议的 32 位总线,负责取址操作。
D-Code:数据总线,AHB‐Lite 总线协议的 32 位总线,负责数据访问操作。
System:系统总线(AHB),AHB‐Lite 总线协议的 32 位总线,负责所有数据的传送。
AHB to APB:在AHB和2个APB总线间提供同步连接,APB1操作速度限于36MHz,APB2操作于全速(最高72MHz)。
外设总线(外部私有):外设总线(APB),基于APB总线协议的 32 位总线,挂载着片上外设。

硬件准备
开发板 STM32F103C8T6 核心板,也称STM32 Blue Pill

下载器/调试器 推荐STLink(意法半导体公司出品)或 JLink(Segger公司出品)
有一种U盘形状的STLink V2调试器,容易丢失固件后无法识别使用,不推荐


以上两种调试器均支持如下接口协议
JTAG:Joint Test Action Group,联合测试工作组规定的一种仿真协议,它是一种国际标准测试协议。
SWD:Serial Wire Debugging,串行调试接口。

由于最小板只支持4针的SWD接口,这里连线方式如下。

串口通信 可选,用于查看日志,USB转TTL芯片类型任选一种 CH340或PL2303。Windows10可通过Microsoft Store搜索安装串口调试助手观察串口数据。
内存结构
Cortext-M3缺少内存管理单元(MMU),所有端口设备、存储空间通过绝对地址访问。32位对应的4G大小的空间分成8大块:代码、SRAM、外设、外部RAM、外部设备、专用外设总线-内部、专用外设总线-外部、特定厂商。具体细节请参考《The Definitive Guide To ARM Cortex M3》2.5 THE MEMORY MAP,其中
RAM 地址从 0x2000 0000 开始,用于运行时堆栈
Flash地址从 0x0800 0000 开始,用于存放程序代码

启动过程
STM32可通过设置BOOT(核心板上两个黄色跳线)选择不同的启动方式,当选用Flash启动时,0x0800 0000 将映射到 0x0000 0000,通电后从Flash读取第一条指令。请参考《The Definitive Guide To ARM Cortex M3》3.7 RESET SEQUENCE

芯片上电复位后,将会将从0x0000 0000 读取栈顶指针,从0x0000 0004 读取复位中断程序(ResetHandler)地址。

Cortext-M3栈向下增长(先压栈后存储)所以SP的初始值应该是栈顶上的第一个地址,比如使用0x20007C00到0x20007FFF(1 KB)作为栈区,SP的值应该为0x20008000

代码原理
在使用IDE开发之前,先使用最基本的代码描述程序的执行原理。
核心板上有2个LED,红色为电源指示、蓝色对应PC13,可通过设置GPIOC_13的高低电位控制蓝色LED的闪烁。
STM32F103C8T6仅有64K的Flash和20K的SRAM,所以MSP初始值不能超过0x20005000。通过__asm__指令设置栈顶为0x20001000,复位后从main函数开始执行。

STM32端口均为通用IO接口GPIO(General-purpose input/output Port),通过设置是否启用、输入输出模式达到节能、端口复用的目的。使用前需要进行一些基础设置。通过查找手册找到GPIOC的控制寄存器地址。

设置RCC_APB2ENR 外设时钟使能寄存器 的IOPCEN位为1,使GPIO_C有效

设置GPIOx_CRH高位配置寄存器,配置推挽输出模式,直接给LED供电

通过BSRR 端口位设置/清除寄存器 的BR13/BS13位,使PC13输出高低电位

使用arm-none-eabi-gcc编译上述代码。

链接文件内容如下,只是将程序放置到代码段0x0起始位置。

将输出bin文件通过STLinkUtility 或 STM32CubeProgrammer 工具烧录即可。由于没有引用任何外部库代码,生成的文件只有108Bytes。

如果出现Can not connect to target错误,杜邦线可能断了或接触不良
STMCubeIDE
STMCubeIDE是意法半导体基于Eclipse构建的开发工具,可以快速生成项目框架。 https://www.st.com/en/development-tools/stm32cubeide.html

GPIO / PC13为GPIO_Output模式
RCC / High Speed Clock 高速时钟源为Crystal/Ceramic Resonator 晶振/ 外部陶瓷振荡器
SYS / Debug调试模式为Serial Wire



保存设置后,提示自动生成代码。只要在指定区域编写用户代码,后续修改ioc的配置可重新生成代码。这里通过HAL库函数修改GPIOC的状态,跟踪这些库函数可以看到,GPIOC、GPIOC_BASE等均是对应寄存器的地址定义。
编写时可通过 Alt+/ 激活代码提示

点击Run按钮IDE将自动构建并下载文件到芯片,Debug模式也可以在代码中设置断点调试。Memory Regions窗口会展示空间使用状况,由于使用HAL库,Flash的空间占用了增长到4.59KB。

中断和异常
Cortex-M3内核支持256个中断,其中包含了16个内核中断(异常)和240个外部中断,并且具有256级的可编程中断设置。

其中SysTick是一个24位的系统节拍定时器,具有自动重载和溢出中断功能,可以由这个定时器获得一定的时间间隔。如果在SysTick位置放置一个函数,定时检查任务状态并进行上下文切换(将寄存器状态写入当前任务的控制块TCB中,找到下一个可执行的任务并恢复寄存器状态),就达到分时调度的效果,比如同等优先级任务进行轮询调度。

PendSV是一个可挂起的系统服务,配置为最低优先级,它会在其他异常执行完毕后再执行,而且任何异常都可以中断它。用户代码可直接请求一个PendSV,让出CPU进行任务切换如果某个IRQ正在活动并且被 SysTick抢占,它将悬起一个 PendSV异常,等SysTick、ISR执行完毕后缓期执行上下文切换。这样可以避免中断对上下文切换的干扰。

SysTick、PendSV异常是所有RTOS实现的核心。
µC/OS IIII移植
开源、商业化收费,是Micrium公司开发的一款嵌入式实时操作系统,代码规范符合ANSI-C标准,简洁干净非常适合学习。最早出自于1992 年美国嵌入式系统专家Jean J.Labrosse 在《嵌入式系统编程》杂志的文章连载。1998年发布的第二代,通过严格的测试,2000年获得DO-178BA级认证,得到美国联邦航空管理局FAA的认证,可以用在飞行器上。2009年发行第三代,经过了全新的设计,具有高度可移植性,没有任务数目的限制。
官网提供了系统移植例程,这里可以参考STM32F107的
链接:https://pan.baidu.com/s/14qwunKCyeArTFGCYIIizbw 提取码:hadl
创建RTOS,将解压后的uC-CPU, uC-LIB, uCOS-III 拷贝进去
创建uC-Config,将EvalBoards中uCOS-III、BSP下的文件拷贝进去

添加RTOS到Source Location

IDE使用gcc编译器进行构建,所以uC-CPU、uC-LIB、uCOS-III目录中ARM-Cortext-M3只保留GNU(RealView对应Keil公司的MDK编译器)。其余的可直接删掉,或者右键Resource Configurations / Exclude from Build..

将所有包含代码的目录添加到Include Paths

清除bsp.h仅保留cpu.h的引用

清除bsp.c的无效内容

使用Ctrl+B进行尝试编译,此时剩下BSP_CPU_ClkFreq报错。引用stm32f1xx_hal.h后重写该方法,使用HAL_RCC_GetHCLKFreq获取HCLK时钟频率

修改Core/Src/stm32f1xx_it.c

修改uCOS-III/Ports/ARM-Cortex-M3/Generic/GNU/os_cpu_a.s,使ucOS的PendSV替换掉默认的函数功能


使用uCOS提供的函数重写main方法

重新编译后下载,uCOS可以正常运行。
FreeRTOS移植
开源、免费,2003年由Richard Barry创建,是除Linux以外最受欢迎的嵌入式操作系统。2017年作者加入亚马逊担任首席工程师,FreeRTOS也由亚马逊管理,商业化版本为OpenRTOS。

从https://github.com/FreeRTOS/FreeRTOS-Kernel获取系统源码;
将FreeRTOS下的文件、include、portable下的GCC/ARM_CM3和MemMang拷贝到新建的RTOS源码目录;MemMang下每个文件代表不同的内存管理方式,这里选用heap_2方式。
将FreeRTOS\Demo\CORTEX_STM32F103_GCC_Rowley\FreeRTOSConfig.h拷贝到include目录。

添加到构建路径中

使用FreeRTOS的xPortPendSVHandler、vPortSVCHandler并替换默认的异常Handler。
此处configTOTAL_HEAP_SIZE代表堆可用RAM总量,无需大内存时可调小。

注释掉默认的PendSV_Handler、SVC_Handler,并在SysTick_Handler中启动RTOS心跳

编写测试程序以验证是否移植成功。

串口通信
在项目配置中可以通过启用USART1进行串口通信,对应PA9、PA10管脚生效,并生成usart.h和usart.c文件

重定义底层实现,将printf函数的数据内容通过husart1串口发送出去。

效果如下
