STM32F103C8T6在线升级 IAP

stm32程序每次执行都会从基地址0x800 0000开始执行。IAP程序升级的执行是在bootloader引导文件执行后,进行加载、跳转APP程序。所以每次上电后进入BootLoader判断是否需要升级,如果升级则接受bin文件,如果不升级则直接跳转app程序。

BootLoader和app程序的FLASH大小需要根据自己的程序情况自由的分配大小就可以了。

代码:根据正点原子的例程进行修改的

1、由于BootLoader引导程序比较小,我设置的flash大小为0x1800



2、iap函数:由于STM32F103C8T6程序存储容量是64KB,每页的大小为1K字节即1024,所以iapbuf数组设置为512。

代码如下:

#include "stmflash.h"
#include "iap.h"
iapfun jump2app; 
u16 iapbuf[512];   
//appxaddr:应用程序的起始地址
//appbuf:应用程序CODE.
//appsize:应用程序大小(字节).
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
{
u16 t;
u16 i=0;
u16 temp;
u32 fwaddr=appxaddr;//当前写入的地址
u8 *dfu=appbuf;
for(t=0;t<appsize;t+=2)
{    
temp=(u16)dfu[1]<<8;
temp+=(u16)dfu[0];  
dfu+=2;//偏移2个字节
iapbuf[i++]=temp;    
if(i==512)
{
i=0;
STMFLASH_Write(fwaddr,iapbuf,512);
fwaddr+=1024;//偏移1024  
}
}
if(i)
STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去.  
}
//跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(u32 appxaddr)
{
if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法.

jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址)
MSR_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
jump2app(); //跳转到APP.
}

}

3、BootLoader函数 :

    首先判断app代码的首地址是否为0x0800 000,是则进入app,否的话进行引导区。

    判断app代码栈顶是否为0x2000 000,不是则进入升级模式,代码如下,其中FLASH_APP1_ADDR=0x8001800

while(1)
{
if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
{
iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
}
if((((*(vu32*)FLASH_APP1_ADDR)&0x2FFE0000)!=0x20000000))
{
printf("/***** No APP! *****/ \r\n");
printf("stm32f103c8t6在线升级  \r\n");
printf("选择对应的app  bin文件 \r\n");
printf("输入 A  发送bin文件 \r\n");
printf("输入 E  进入app \r\n");
while(1)
{
if(USART_RX_CNT)
{
if(oldcount==USART_RX_CNT)//新周期内,没有收到任何数据,认为本次数据接收完成.
{
applenth=USART_RX_CNT;
oldcount=0;
USART_RX_CNT=0;
if(applenth > 100)
{
printf("用户程序接收完成!\r\n");
printf("代码长度:%dBytes\r\n",applenth);
}

}
else 
oldcount=USART_RX_CNT;
}
delay_ms(10);

if(USART_RX_BUF[0] == 'A')
{
if(applenth)
printf("\r\n 请发送bin文件 \r\n");
app_bin = 1;
applenth=0;
}
else if(app_bin)
{

if(applenth)
{
printf("开始更新固件...\r\n");
printf("Copying APP2FLASH...");

if(((*(vu32*)(0X20000400+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
{  
iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASH代码   
printf("Copy APP Successed!!");
printf("固件更新完成!\r\n");
applenth = 0;
app_bin = 0;
}
}
}

if(USART_RX_BUF[0] == 'E')
{
if(applenth)
printf("\r\n 将要执行APP \r\n");
app_enter = 1;
applenth = 0;

if(app_enter)
{
printf("开始执行FLASH用户代码!!\r\n");
if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
{  
iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
}else 
{
printf("非FLASH应用程序,无法执行!\r\n");
printf("Illegal FLASH APP!");  
}
}
}
}

}

4、bootloader下进去之后,后面该是app程序了。

5、app程序就比较简单了,首先设置flash向量便宜地址0x1800


其次配置程序的启动地址



6、编译后keil下载程序就可以了,或者通过串口按照自己编写的步骤进行下载。


发送 A 提示 请发送bin文件

下面以次打开选择bin文件并发送,会打印出接收的字节数跟更新固件


最好发送E,会有开始执行提示。或者单片机直接复位也可以直接执行app,到此app在线升级完成。




猜你喜欢

转载自blog.csdn.net/enfang1120/article/details/80605029