STM32
直播中

HCPcry

8年用户 1187经验值
擅长:处理器/DSP
私信 关注
[问答]

探讨一下IAP在线升级的核心理论

IAP的核心是什么?
怎样去编写bootloader的部分代码呢?
编写app程序有哪些注意事项呢?

回帖(1)

殷晓婷

2021-11-4 10:58:40
  首先申明一点,我这个不是什么原创,但也不是转载。以正点原子的战舰开发板的资料和神州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。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分