1.程序运行过程
- IAP程序运行过程
1、 STM32复位后,从地址为0x8000004处取出复位中断向量的地址,并跳转执行复位中断服务程序,随后跳转至IAP程序的main函数。
2、 执行完IAP过程后(STM32内部多出了新写入的程序,地址始于0x8000004+N)跳转至新写入程序的复位向量表,取出新程序的复位中断向量的地址,并跳转执行新程序的复位中断服务程序,随后跳转至新程序的main函数。新程序的main函数应该也具有永不返回的特性。同时应该注意在STM32的内部存储空间在不同的位置上出现了2个中断向量表。
3、 在新程序main函数执行的过程中,一个中断请求来临,PC指针仍会回转至地址为0x8000004中断向量表处,而并不是新程序的中断向量表,注意到这是由STM32的硬件机制决定的。
4、 根据中断源跳转至对应的中断服务,注意此时是跳转至了新程序的中断服务程序中。
5、 中断服务执行完毕后,返回main函数。
- 关于启动过程的内存关系可看stm32启动过程解析startup启动文件
2.实现
- 程序分为两个部分,一个是平时运行的程序叫做APP,内容和普通程序一样,另一个程序是IAP程序,用于接收新程序并更新写入指定位置。程序下载都是在Flash中,也就是ROM,stm32F103一般为256KB大小,位置在0x08000000,上电运行时,代码被复制到在RAM中,位置0x20000000,因此APP和Bootloader(IAP)的RAM起始地址和大小都是一模一样的,如因为Bootloader的生命周期只有上电的一瞬间,当Bootloader将程序引导进入APP程序的时候,Bootloader就将不会再发挥任何作用。因此APP可以占有全部的RAM
2.1 APP部分
- APP程序内容和普通程序一样,仅仅在编译器中设置它存放的位置
- ROM这里起始地址常规程序是0x0800000,芯片复位后就会从这个向量表地址使用Reset_Handler,最后调用main函数,但是这个地方需要用来放IAP程序向量表,所以将APP程序的向量表地址改为其它,IAP程序留个0x10000(约64KB)或者0x8000字节就够了,0x10000==1x256x256=64KB,根据芯片Flash内存是否有这么大决定。
- 平时使用ISP时通常需要的是elf或者hex文件,IAP中使用的是bin二进制文件格式,因此添加命令生成bin文件
//前面是keil安装路径下的fromelf.exe命令,OBJ是存放axf文件的目录
D:\promgram_exe\keil5\armmdk\ARM\ARMCC\bin\fromelf.exe --bin -o ..\OBJ\RTC.bin ..\OBJ\RTC.axf
- 编译生成bin文件即可,不可烧录
2.2 IAP部分
1. 使用uart串口接收bin文件,并保存在数组中,这个数组定义为:
u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));//接收缓冲,最大USART_REC_LEN个字节,起始地址为0X20001000.位于sram中
2. 主函数main.c如下
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "usmart.h"
#include "gdflash.h"
#include "iap.h"
/************************************************
WKS GD32F427ZGT6核心板 实验37
串口IAP实验Bootloader-HAL库函数版
************************************************/
int main(void)
{
u8 t;
u8 key;
u16 oldcount=0; //老的串口接收数据值
u32 applenth=0; //接收到的app代码长度
u8 clearflag=0;
HAL_Init(); //初始化HAL库
GD32_Clock_Init(336,8,2,7); //设置时钟,168Mhz
delay_init(168); //初始化延时函数
uart_init(256000); //初始化USART
LED_Init(); //初始化LED
KEY_Init(); //初始化KEY
LCD_Init(); //初始化LCD
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(30,50,200,16,16,"GD32F427 Core Board");
LCD_ShowString(30,70,200,16