STM32F103C8T6通过串口加载固件
之前写了简单的Bootloader,只实现了程序跳转的功能。但是作为一个Bootloader,只能完成程序跳转感觉缺了点啥。那就继续添加可以加载固件的功能吧。
加载固件的途径有很多,常见的就有串口、可移动存储设备、网络等等。这里就从最简单的开始吧,先做串口的。
整个程序的思路如下:
- 上位机与单片机进行握手,并传输一些必要的信息。
- 上位机发送固件的一部分到单片机(这里描述为一个块数据)。
- 单片机接收到一块数据后,将其保存到RAM中。然后向上位机返回这块数据的校验和。
- 上位机检查单片机返回的校验和是否正确,正确则重复步骤2和步骤3,直到整个固件发送完成。不正确则结束传输。
要完成整个加载的过程,起码要有几个方面的工作要做:
- 串口接收程序。
- Flash写入程序。
- 解析二进制文件并发送到串口的上位机程序。
串口接收程序需要和上位机程序一起说明,留到后面再说。现在先看下如何操作Flash。
1 Flash写入程序
1.0 目标
将一块RAM中的数据写入到Flash。
1.1 准备硬件
依然是淘宝上随处可见的STM32F103C8T6核心板,以及烧录和调试需要用到的STLINK。
1.2 理论基础
Flash简介之类的东西就不写了,上网查一下都有。这里主要写这款硬件相关的吧。这里主要参考ST的PM0075文档《STM32F10xxx Flash memory microcontrollers》,感兴趣的可以去看原文。
F103C8属于STMF1系列中的中等容量单片机,Flash容量为64KB,占用地址为:0x08000000~0x0800FFFF。这块64KB的Flash被分为64个1KB的页。这就意味着擦除的最小单位为1KB。
了解完Flash的组织结构后,再来了解一下Flash的读写操作。
读操作相对简单,直接声明一个指向要读取数据的指针就可以直接读取数据了。
写操作相对繁琐,ST官方PM0075文档中有如下流程图:
对照着流程图,这里稍作一点解释。
- STM32F103内部有一组寄存器(FPEC)是实现Flash控制的。上电后,FPEC寄存器组处于锁定状态,不可操作。因此在操作Flash之前,需要读取锁定状态位,如果FPEC锁定了,则需要解锁。
- 解锁Flash的方法很简单,就是依次先后将KEY1 = 0x45670123、KEY2 = 0xCDEF89AB 写入FLASH_KEYR寄存器即可。
- 解锁后,将FLASH_CR寄存器的PG位置为1。然后向目标地址写入一个半字(16bit)。
- 检查FLASH_SR寄存器的BSY位。等待BSY位变为0,从目标地址中读取一个半字,与写入的数据进行比较,检查是否真正写入。
实际上,HAL库会提供操作Flash的API函数,上述步骤只是了解就行,实际使用起来还是直接使用HAL库。
还有一点需要注意的。Flash操作的带宽为16位(16bit)。这意味着我们每次写入的时候都只能是16位的倍数。但是HAL库会提供写8位的函数,实际上这个函数是把高八位设定为0而已,本质上还是写入16位。
1.3 创建工程
创建工程就比较简单了。由于HAL库的工程会带有Flash操作的函数库,所以我们正常创建一个LED闪烁的工程即可。如下图所示:
1.3.1 简单测试
首先简单测试一下上面提到的读写操作是否有问题。
读操作:
/*
*
* 从Flash的某个地址中读取一个半字(16bit)
*
*/
uint16_t FLASH_ReadHalfWord(uint32_t addr)
{
return *(volatile uint16_t *)addr;
}
由于写入是半字写入,那读取也写成一致的半字读取。需要字读取的可以在半字读取的基础上进行改写。
写操作函数不需要自己写,Hal库有提供。但是需要注意,执行的操作还是要按照上述流程图的顺序来执行的。
下面是Hal库提供的函数。
HAL_StatusTypeDef HAL_FLASH_Unlock(void); //解锁
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data); //编程
HAL_StatusTypeDef HAL_FLASH_Lock(void); //上锁
使用上述的函数,可以完成写入半字的操作,如下:
/*
*
* 按照官方文档的写入序列,向Flash的某个地址写入半字(16bit)
*
*/
uint8_t Flash_WriteHalfWord(uint32_t addr, uint16_t data)
{
HAL_StatusTypeDef ret; //操作返回值
/* 1、解锁 */
ret = HAL_FLASH_Unlock<