首先申明一点,我这个不是什么原创,但也不是转载。以正点原子的战舰开发板的资料和神州IV号以及广大网友的资料为基础来做的。 我使用的硬件神州IV号开发板,stm32f107系列的芯片,256K flash。IAP在线升级的确是个好东西,对于那些已经安装好的设备来说,真是一大利器。IAP的核心理论其实比较简单:总共有两个程序,一个叫bootloader ,一个叫app。其中bootloader 、是一个引导程序,通过串口、u***、或者其他通讯接口,将app的代码(也是一个完整的程序,但是稍有一点不同),接收,然后存储到指定的flash处,最后跳转到存储app的地址,执行app。 app也是一个完整的程序只是他的堆zha地址往后移到,存储app的位置。下面我就截取一下原子的用户资料。
注:此图是从STM32开发指南是截取。
这就是这bootloader和app的整个执行过程。其中可以看出,bootloader是一个正常的程序,只是最后转到APP而已。app就稍有不同了他的中断复位地址要改变一下了。就是bootloader将其存储的位置。这些待会再说。
现在让我们来屡一下,其中bootloader,要的模块就是串口、和flash。所以函数就只要,串口中断接收、flash存储、跳转app。
下面就是我的bootloader的部分代码,很多是移植了原子哥的
这里是main.c里面的
#define FLASH_APP1_ADDR 0x08010000 //第一个应用程序起始地址(存放在FLASH)
//保留0X08010000~0X0800FFFF的空间为IAP使用
USART2_Init();
while (1)
{
if(USART_RX_CNT)
{
if(oldcount==USART_RX_CNT)//新周期内,没有收到任何数据,认为本次数据接收完成。
{
applenth=USART_RX_CNT;
oldcount=0;
USART_RX_CNT=0;
printf(“用户程序接收完成!rn”);
printf(“代码长度:%dBytesrn”,applenth);
flag=1;
}else oldcount=USART_RX_CNT;
}
t=6553;
while(t)
{t--;}
if(flag)
{
// printf(“nr 这是buffrx %s”,USART_RX_BUF);
// flag=0;
printf(“nr 开始更新固件”) ;
if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
{
iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASH代码
// delay_ms(100);
// LCD_ShowString(60,210,200,16,16,“Copy APP Successed!!”);
printf(“固件更新完成!rn”);
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);//开启中断
}else
{
// LCD_ShowString(60,210,200,16,16,“Illegal FLASH APP! ”);
printf(“非FLASH应用程序!rn”);
}
if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
{
iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
}else
{
printf(“非FLASH应用程序,无法执行!rn”);
// LCD_ShowString(60,210,200,16,16,“Illegal FLASH APP!”);
}
}
USART.C里面的
u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));//接收缓冲,最大xx字节,起始地址 这一段比较重要,这是把某一个数组指定存储到某一个位置
u16 USART_RX_STA=0; //接收状态标记
u16 USART_RX_CNT=0; //接收的字节数
void USART2_IRQHandler(void) //
{
//printf(“nr wo ok la!”);
// rx=0;
u8 res;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
//
res=USART_ReceiveData(USART2);
//flag =1;
if(USART_RX_CNT《USART_REC_LEN)
{
USART_RX_BUF[USART_RX_CNT]=res;
// USART_RX_BUF[USART_RX_CNT++] = USART_ReceiveData(USART2);
USART_RX_CNT++;
}
}
以上两个文件里面的函数,就可以实现相应的功能了。
接下来就是app程序了。app程序和普通程序是一样的但是要注意,两点
1、需要使用 SCB-》VTOR = FLASH_BASE | 0x10000;这条语句将堆栈偏移到bootloader的存储位置与之相对应
2、
107的空间是0x8000000到0x804000,其中0x8000000到0x8010000留给了bootloader,剩下的就是app的了。
对了app要。bin格式的,可以通过串口助手,直接发送到mcu。
首先申明一点,我这个不是什么原创,但也不是转载。以正点原子的战舰开发板的资料和神州IV号以及广大网友的资料为基础来做的。 我使用的硬件神州IV号开发板,stm32f107系列的芯片,256K flash。IAP在线升级的确是个好东西,对于那些已经安装好的设备来说,真是一大利器。IAP的核心理论其实比较简单:总共有两个程序,一个叫bootloader ,一个叫app。其中bootloader 、是一个引导程序,通过串口、u***、或者其他通讯接口,将app的代码(也是一个完整的程序,但是稍有一点不同),接收,然后存储到指定的flash处,最后跳转到存储app的地址,执行app。 app也是一个完整的程序只是他的堆zha地址往后移到,存储app的位置。下面我就截取一下原子的用户资料。
注:此图是从STM32开发指南是截取。
这就是这bootloader和app的整个执行过程。其中可以看出,bootloader是一个正常的程序,只是最后转到APP而已。app就稍有不同了他的中断复位地址要改变一下了。就是bootloader将其存储的位置。这些待会再说。
现在让我们来屡一下,其中bootloader,要的模块就是串口、和flash。所以函数就只要,串口中断接收、flash存储、跳转app。
下面就是我的bootloader的部分代码,很多是移植了原子哥的
这里是main.c里面的
#define FLASH_APP1_ADDR 0x08010000 //第一个应用程序起始地址(存放在FLASH)
//保留0X08010000~0X0800FFFF的空间为IAP使用
USART2_Init();
while (1)
{
if(USART_RX_CNT)
{
if(oldcount==USART_RX_CNT)//新周期内,没有收到任何数据,认为本次数据接收完成。
{
applenth=USART_RX_CNT;
oldcount=0;
USART_RX_CNT=0;
printf(“用户程序接收完成!rn”);
printf(“代码长度:%dBytesrn”,applenth);
flag=1;
}else oldcount=USART_RX_CNT;
}
t=6553;
while(t)
{t--;}
if(flag)
{
// printf(“nr 这是buffrx %s”,USART_RX_BUF);
// flag=0;
printf(“nr 开始更新固件”) ;
if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
{
iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASH代码
// delay_ms(100);
// LCD_ShowString(60,210,200,16,16,“Copy APP Successed!!”);
printf(“固件更新完成!rn”);
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);//开启中断
}else
{
// LCD_ShowString(60,210,200,16,16,“Illegal FLASH APP! ”);
printf(“非FLASH应用程序!rn”);
}
if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
{
iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
}else
{
printf(“非FLASH应用程序,无法执行!rn”);
// LCD_ShowString(60,210,200,16,16,“Illegal FLASH APP!”);
}
}
USART.C里面的
u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));//接收缓冲,最大xx字节,起始地址 这一段比较重要,这是把某一个数组指定存储到某一个位置
u16 USART_RX_STA=0; //接收状态标记
u16 USART_RX_CNT=0; //接收的字节数
void USART2_IRQHandler(void) //
{
//printf(“nr wo ok la!”);
// rx=0;
u8 res;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
//
res=USART_ReceiveData(USART2);
//flag =1;
if(USART_RX_CNT《USART_REC_LEN)
{
USART_RX_BUF[USART_RX_CNT]=res;
// USART_RX_BUF[USART_RX_CNT++] = USART_ReceiveData(USART2);
USART_RX_CNT++;
}
}
以上两个文件里面的函数,就可以实现相应的功能了。
接下来就是app程序了。app程序和普通程序是一样的但是要注意,两点
1、需要使用 SCB-》VTOR = FLASH_BASE | 0x10000;这条语句将堆栈偏移到bootloader的存储位置与之相对应
2、
107的空间是0x8000000到0x804000,其中0x8000000到0x8010000留给了bootloader,剩下的就是app的了。
对了app要。bin格式的,可以通过串口助手,直接发送到mcu。
举报