STM32补充——IAP

打印 上一主题 下一主题

主题 1012|帖子 1012|积分 3036

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
0 前置知识:

FLASH相干内容:前往STM32补充——FLASH
STM32三种烧录方式(看看就行):
1.ISP:In System Programming(在体系编程)
执行芯片厂商的 Bootloader 程序进入 ISP 模式,进入ISP 模式后,用户可选择官方提供的烧录通信接口(如:串口),并配合ISP 编程工具(如:FlyMcu)对闪存进行烧录。
2.ICP:In Circuit Programing(在线编程)
使用IDE并通过JTAG/SWD接口对闪存进行烧录。
3.IAP:In Application Programming(在应用编程)
使用用户的应用程序(也称为:Bootloader程序)对闪存进行烧录。该应用程序须要通过一种通信接口(如:IO口\USB\CAN\UART\I2C\SPI等)对闪存进行烧录(即把APP程序烧录到闪存)。IAP 通常被开辟者用作远程升级的手段。

1.IAP原理介绍


1.1 程序正常运行过程:


①跳转到复位中断服务函数
②跳转到main函数
③发生中断时,会欺压跳转到中断向量表
④根据中断源,跳转到对应的中断服务函数
⑤执行中断服务程序后,回到main函数原来的位置执行  
 

1.2 参加IAP后程序运行过程


①执行复位中断服务函数后,跳转到IAP程序main函数
②执行IAP过程,跳转到APP中断向量表
③跳转到APP的main函数
④发生中断时,会欺压跳转到地址为0x08000000的中断向量表
⑤根据设置的中断向量表偏移量,跳转到APP对应的中断服务函数
⑥执行中断服务程序后,回到main函数原来的位置执行 


2.APP的天生步骤


  • 设置APP程序的起始地址和存储空间大小
  • 设置中断向量表偏移量(设置SCB->VTOR的值即可)
  • 设置MDK编译后运行fromelf.exe,天生.bin文件(在User选项卡,设置编译后调用fromelf.exe,根据.axf文件天生.bin文件,用于IAP更新)
注意:APP程序的起始地址可在Keil上直接设置,但中断向量表偏移量须要别的手动设置

 
2.1 设置APP程序的起始地址和存储空间大小

设置APP起始地址要注意的点:
1,APP要在BootLoader后面
2,内存不能出现重叠
3,偏移量是0x200的倍数

FLASH_APP:


SRAM_APP:


①Bootloader程序运行预留4KB SRAM
②存放APP程序预留48KB SRAM
③APP程序运行预留12KB SRAM
 
2.2 设置中断向量表偏移量 

APP存放在FLASH中的设置方法:
  1. SCB->VTOR = FLASH_BASE | 0x10000;
复制代码
 
APP存放在SRAM中的设置方法:
  1. SCB->VTOR = SRAM_BASE | 0x1000;
复制代码

2.3 设置MDK编译后运行fromelf.exe,天生.bin文件


D:\MDK5.36\ARM\ARMCC\bin\fromelf  --bin -o ..\..\Output\@L.bin  ..\..\Output\%L


3. 代码

iap模块:
  1. iapfun jump2app;
  2. uint16_t g_iapbuf[1024];       /* 2K字节缓存 */
  3. /**
  4. * @brief       IAP写入APP BIN
  5. * @param       appxaddr : 应用程序的起始地址
  6. * @param       appbuf   : 应用程序CODE
  7. * @param       appsize  : 应用程序大小(字节)
  8. * @retval      无
  9. */
  10. void iap_write_appbin(uint32_t appxaddr, uint8_t *appbuf, uint32_t appsize)
  11. {
  12.     uint16_t t;
  13.     uint16_t i = 0;
  14.     uint16_t temp;
  15.     uint32_t fwaddr = appxaddr; /* 当前写入的地址 */
  16.     uint8_t *dfu = appbuf;
  17.     for (t = 0; t < appsize; t += 2)
  18.     {
  19.         temp = (uint16_t)dfu[1] << 8;
  20.         temp |= (uint16_t)dfu[0];
  21.         dfu += 2;               /* 偏移2个字节(FLASH每次写入两个字节) */
  22.         g_iapbuf[i++] = temp;
  23.         if (i == 1024)
  24.         {
  25.             i = 0;
  26.             stmflash_write(fwaddr, g_iapbuf, 1024);
  27.             fwaddr += 2048;     /* 偏移2048  16 = 2 * 8  所以要乘以2 */
  28.         }
  29.     }
  30.     if (i)
  31.     {
  32.         stmflash_write(fwaddr, g_iapbuf, i);  /* 将最后的一些内容字节写进去 */
  33.     }
  34. }
  35. /**
  36. * @brief       跳转到应用程序段(执行APP)
  37. * @param       appxaddr : 应用程序的起始地址
  38. * @retval      无
  39. */
  40. void iap_load_app(uint32_t appxaddr)
  41. {
  42.     if (((*(volatile  uint32_t *)appxaddr) & 0x2FFE0000) == 0x20000000)     /* 检查栈顶地址是否合法.可以放在内部SRAM共64KB(0x20000000) */
  43.     {
  44.         /* 用户代码区第二个字为程序开始地址(复位地址) */
  45.         jump2app = (iapfun) * (volatile uint32_t *)(appxaddr + 4);
  46.         
  47.         /* 初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) */
  48.         sys_msr_msp(*(volatile uint32_t *)appxaddr);
  49.         
  50.         /* 跳转到APP */
  51.         jump2app();
  52.     }
  53. }
复制代码
 
main函数:
  1. int main(void)
  2. {
  3.     uint8_t t;
  4.     uint8_t key;
  5.     uint32_t oldcount = 0;      /* 老的串口接收数据值 */
  6.     uint32_t applenth = 0;      /* 接收到的app代码长度 */
  7.     uint8_t clearflag = 0;
  8.     HAL_Init();                                 /* 初始化HAL库 */
  9.     sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟, 72Mhz */
  10.     delay_init(72);                             /* 延时初始化 */
  11.     usart_init(115200);                         /* 串口初始化为115200 */
  12.     led_init();                                 /* 初始化LED */
  13.     lcd_init();                                 /* 初始化LCD */
  14.     key_init();                                 /* 初始化按键 */
  15.     lcd_show_string(30,  50, 200, 16, 16, "STM32", RED);
  16.     lcd_show_string(30,  70, 200, 16, 16, "IAP TEST", RED);
  17.     lcd_show_string(30,  90, 200, 16, 16, "ATOM@ALIENTEK", RED);
  18.     lcd_show_string(30, 110, 200, 16, 16, "KEY_UP: Copy APP2FLASH!", RED);
  19.     lcd_show_string(30, 130, 200, 16, 16, "KEY1: Run FLASH APP", RED);
  20.     lcd_show_string(30, 150, 200, 16, 16, "KEY0: Run SRAM APP", RED);
  21.     while (1)
  22.     {
  23.         if (g_usart_rx_cnt)
  24.         {
  25.             if (oldcount == g_usart_rx_cnt)   /* 新周期内,没有收到任何数据,认为本次数据接收完成 */
  26.             {
  27.                 applenth = g_usart_rx_cnt;
  28.                 oldcount = 0;
  29.                 g_usart_rx_cnt = 0;
  30.                 printf("用户程序接收完成!\r\n");
  31.                 printf("代码长度:%dBytes\r\n", applenth);
  32.             }
  33.             else oldcount = g_usart_rx_cnt;
  34.         }
  35.         t++;
  36.         delay_ms(100);
  37.         if (t == 3)
  38.         {
  39.             LED0_TOGGLE();
  40.             t = 0;
  41.             if (clearflag)
  42.             {
  43.                 clearflag--;
  44.                 if (clearflag == 0)
  45.                 {
  46.                     lcd_fill(30, 190, 240, 210 + 16, WHITE);    /* 清除显示 */
  47.                 }
  48.             }
  49.         }
  50.         key = key_scan(0);
  51.         if (key == WKUP_PRES)   /* WKUP按下,更新固件到FLASH */
  52.         {
  53.             if (applenth)
  54.             {
  55.                 printf("开始更新固件...\r\n");
  56.                 lcd_show_string(30, 190, 200, 16, 16, "Copying APP2FLASH...", BLUE);
  57.                 if (((*(volatile uint32_t *)(0X20001000 + 4)) & 0xFF000000) == 0x08000000)  /* 判断是否为0X08XXXXXX */
  58.                 {
  59.                     iap_write_appbin(FLASH_APP1_ADDR, g_usart_rx_buf, applenth);            /* 更新FLASH代码 */
  60.                     lcd_show_string(30, 190, 200, 16, 16, "Copy APP Successed!!", BLUE);
  61.                     printf("固件更新完成!\r\n");
  62.                 }
  63.                 else
  64.                 {
  65.                     lcd_show_string(30, 190, 200, 16, 16, "Illegal FLASH APP!  ", BLUE);
  66.                     printf("非FLASH应用程序!\r\n");
  67.                 }
  68.             }
  69.             else
  70.             {
  71.                 printf("没有可以更新的固件!\r\n");
  72.                 lcd_show_string(30, 190, 200, 16, 16, "No APP!", BLUE);
  73.             }
  74.             clearflag = 7; /* 标志更新了显示,并且设置7*300ms后清除显示 */
  75.         }
  76.         if (key == KEY1_PRES)   /* KEY1按键按下, 运行FLASH APP代码 */
  77.         {
  78.             if (((*(volatile uint32_t *)(FLASH_APP1_ADDR + 4)) & 0xFF000000) == 0x08000000) /* 判断FLASH里面是否有APP,有的话执行 */
  79.             {
  80.                 printf("开始执行FLASH用户代码!!\r\n\r\n");
  81.                 delay_ms(10);
  82.                 iap_load_app(FLASH_APP1_ADDR);/* 执行FLASH APP代码 */
  83.             }
  84.             else
  85.             {
  86.                 printf("没有可以运行的固件!\r\n");
  87.                 lcd_show_string(30, 190, 200, 16, 16, "No APP!", BLUE);
  88.             }
  89.             clearflag = 7; /* 标志更新了显示,并且设置7*300ms后清除显示 */
  90.         }
  91.         if (key == KEY0_PRES)   /* KEY0按下 */
  92.         {
  93.             printf("开始执行SRAM用户代码!!\r\n\r\n");
  94.             delay_ms(10);
  95.             if (((*(volatile uint32_t *)(0x20001000 + 4)) & 0xFF000000) == 0x20000000)   /* 判断是否为0X20XXXXXX */
  96.             {
  97.                 iap_load_app(0x20001000);   /* SRAM地址 */
  98.             }
  99.             else
  100.             {
  101.                 printf("非SRAM应用程序,无法执行!\r\n");
  102.                 lcd_show_string(30, 190, 200, 16, 16, "Illegal SRAM APP!", BLUE);
  103.             }
  104.             clearflag = 7; /* 标志更新了显示,并且设置7*300ms后清除显示 */
  105.         }
  106.     }
  107. }
复制代码
 


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

飞不高

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表