STM32F103-串口IAP

一、IAP是什么
IAP即为In Application Programming,解释为在应用中编程,用户自己的程序在运行过程中对User Flash的部分区域进行烧写。即是一种对单片机flash擦写的一种编程方案。
通常情况下,一片stm32单片机的flash只有一个用户程序,而IAP编程则是将单片机的flash分成至少两大区域,一部分叫做bootloader区,一部分叫做app用户代码区,还可留出一部分区域为代码备份区。

二、IAP的应用场所
通常情况下我们给stm32单片机烧录更新程序时是通过SWD、J-link或者通过设置BOOT引脚后,使用串口进行程序下载,这样的方式直接一次性将程序文件下载到单片机的flash中,比较适合绝大部分的应用。
但是当产品投入实际应用时,封装完成后在后期的使用过程中遇到某些程序上的bug或者是根据客户需求需要增加一些功能的时候,使用传统代码烧录的方法就可能需要拆除封装,而使用IAP编程在bootloader区提前写入与外部通信的接口用于升级单片机代码,使得我们不用对已完成包装的产品进行拆除既可以更新代码,这样既节约了成本,也更加方便快捷。

三、IAP编程的流程
IAP编程将Flash区分成的两个区域,bootloader区和app用户代码区具有截然不同的功能。
bootloader区,主要实现接收程序文件,并将该程序写于特定位置的Flash区域。而这里接收外部程序文件,就需要实时和外部通信了。Stm32单片机与外部通信大多是通过自身的串口接收和发送数据,不过Stm32单片机的串口可以外接多种通讯接口,例如422、485、GPRS及ESP8266等。即我们可以通过串口外接蓝牙模块、WiFi模块或者是其他网络模块,就可以实现远程的文件传送更新单片机程序了。
app用户代码区则是主要实现我们所需要的功能操作,除此之外app用户代码区还需要实时检查代码运行情况,通过判断更新程序的标志位来判断是否需要升级程序。若是需要升级程序则进入bootloader区进行代码更新;若不需要则继续运行功能函数代码即可。
因此IAP编程下的单片机运行流程如下图:

根据运行流程,我们可以总结出简单几条bootloader设计过程中需要注意的地方:
1、精简、程序尽可能精简。在单片机Flash有限的情况下,bootloader代码占用Flash的空间越小,则APP程序代码就可占用更多,实现更多功能函数。
2、标志位不受复位的影响。
3、Bootloader中尽量不使用中断。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

一、确定需要解决的问题
二、解决问题
1、准备好Bootloder和APP应用两个程序。
2、对flash进行擦除和重写
3、设置APP应用程序的中断向量表偏移
4、改变APP用户程序的代码存放地址空间
5、在BootLoader程序中将PC指针跳转到用户代码处,如下操作即可:
6、通过串口接收文件
参考链接
本次所采用的编译环境为Keil,本来是想在IAR环境下开发的,但是还是用不太惯它的调试,所以还是换成了Keil。
本次用到的单片机是Stm32F103C8T6。

在知道了IAP编程的原理之后,需要知道具体实现的过程,这里推荐一篇博文
http://www.51hei.com/stm32/4315.html
博文中博主把IAP方案实现的原理以及所需要注意的问题和解决办法说得很通透了,这里我就不再赘述了

一、确定需要解决的问题

实现IAP编程需要着手编写两个程序,一个是Bootloader程序,一个是APP应用程序。
需要对STM32的Flash进行擦除和写入操作。
需要根据APP应用程序开始地址设置中断向量表的偏移
需要改变代码存放的地址空间(因为BootLoader要存放在0x08000000处,用户程序要存放在0x08005000处,而默认的代码存放的地址空间为0x08000000)。
在下载完更新文件之后需要进行PC指针的强制跳转,跳转时需要做什么
串口接收的用户代码数据是什么样的代码数据,是一种什么样的文件,该如何得到该格式文件

二、解决问题
1、准备好Bootloder和APP应用两个程序。

原子代码:

  1 #include "led.h"
  2 #include "delay.h"
  3 #include "key.h"
  4 #include "sys.h"
  5 #include "lcd.h"
  6 #include "usart.h"
  7 #include "stmflash.h"
  8 #include "iap.h"
  9 //ALIENTEK战舰STM32开发板实验48
 10 //IAP实验 Bootloader V1.0 代码
 11 //技术支持:www.openedv.com
 12 //广州市星翼电子科技有限公司
 13 int main(void)
 14 {
 15     u8 t;
 16     u8 key;
 17     u16 oldcount=0;    //老的串口接收数据值
 18     u16 applenth=0;    //接收到的app代码长度
 19     u8 clearflag=0;
 20
 21     uart_init(256000);    //串口初始化为256000
 22     delay_init();                //延时初始化
 23     LCD_Init();
 24     LED_Init();                  //初始化与LED连接的硬件接口
 25
 26      KEY_Init();                //按键初始化
 27
 28      POINT_COLOR=RED;//设置字体为红色
 29     LCD_ShowString(60,50,200,16,16,"Warship STM32");
 30     LCD_ShowString(60,70,200,16,16,"IAP TEST");
 31     LCD_ShowString(60,90,200,16,16,"[email protected]");
 32     LCD_ShowString(60,110,200,16,16,"2012/9/24");
 33     LCD_ShowString(60,130,200,16,16,"WK_UP:Copy APP2FLASH");
 34     LCD_ShowString(60,150,200,16,16,"KEY1:Erase SRAM APP");
 35     LCD_ShowString(60,170,200,16,16,"KEY0:Run SRAM APP");
 36     LCD_ShowString(60,190,200,16,16,"KEY2:Run FLASH APP");
 37     POINT_COLOR=BLUE;
 38     //显示提示信息
 39     POINT_COLOR=BLUE;//设置字体为蓝色
 40     while(1)
 41     {
 42          if(USART_RX_CNT)
 43         {
 44             if(oldcount==USART_RX_CNT)//新周期内,没有收到任何数据,认为本次数据接收完成.
 45             {
 46                 applenth=USART_RX_CNT;
 47                 oldcount=0;
 48                 USART_RX_CNT=0;
 49                 printf("用户程序接收完成!\r\n");
 50                 printf("代码长度:%dBytes\r\n",applenth);
 51             }else oldcount=USART_RX_CNT;
 52         }
 53         t++;
 54         delay_ms(10);
 55         if(t==30)
 56         {
 57             LED0=!LED0;
 58             t=0;
 59             if(clearflag)
 60             {
 61                 clearflag--;
 62                 if(clearflag==0)LCD_Fill(60,210,240,210+16,WHITE);//清除显示
 63             }
 64         }
 65         key=KEY_Scan(0);
 66         if(key==KEY_UP)
 67         {
 68             if(applenth)
 69             {
 70                 printf("开始更新固件...\r\n");
 71                 LCD_ShowString(60,210,200,16,16,"Copying APP2FLASH...");
 72                  if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
 73                 {
 74                     iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASH代码
 75                     delay_ms(100);
 76                     LCD_ShowString(60,210,200,16,16,"Copy APP Successed!!");
 77                     printf("固件更新完成!\r\n");
 78                 }else
 79                 {
 80                     LCD_ShowString(60,210,200,16,16,"Illegal FLASH APP!  ");
 81                     printf("非FLASH应用程序!\r\n");
 82                 }
 83              }else
 84             {
 85                 printf("没有可以更新的固件!\r\n");
 86                 LCD_ShowString(60,210,200,16,16,"No APP!");
 87             }
 88             clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示
 89         }
 90         if(key==KEY_DOWN)
 91         {
 92             if(applenth)
 93             {
 94                 printf("固件清除完成!\r\n");
 95                 LCD_ShowString(60,210,200,16,16,"APP Erase Successed!");
 96                 applenth=0;
 97             }else
 98             {
 99                 printf("没有可以清除的固件!\r\n");
100                 LCD_ShowString(60,210,200,16,16,"No APP!");
101             }
102             clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示
103         }
104         if(key==KEY_LEFT)
105         {
106             printf("开始执行FLASH用户代码!!\r\n");
107             if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
108             {
109                 iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
110             }else
111             {
112                 printf("非FLASH应用程序,无法执行!\r\n");
113                 LCD_ShowString(60,210,200,16,16,"Illegal FLASH APP!");
114             }
115             clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示
116         }
117         if(key==KEY_RIGHT)
118         {
119             printf("开始执行SRAM用户代码!!\r\n");
120             if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x20000000)//判断是否为0X20XXXXXX.
121             {
122                 iap_load_app(0X20001000);//SRAM地址
123             }else
124             {
125                 printf("非SRAM应用程序,无法执行!\r\n");
126                 LCD_ShowString(60,210,200,16,16,"Illegal SRAM APP!");
127             }
128             clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示
129         }
130
131     }
132 }

2、对flash进行擦除和重写
在原子的例程中就包含了对Flash的擦除和重写,在操作Flash之前一定要记得先释放Flash的操作权限,即解锁。通过阅读原子例程的代码可以清晰的知道,他实现的对Flash的操作主要是调用了stm32固件库中的stm32f10x_flash.c中的三个库函数:

void FLASH_Unlock(void);
FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)

3、设置APP应用程序的中断向量表偏移
在推荐的博文中把APP应用程序的中断向量表需要设置偏移的原因已经讲的很清楚了,这里就不再赘述了。
首先我将Flash分成了两个部分,从Flash起始地址0x8000000到0x8005000的20KB大小作为Bootloader区域;从0x8005000以后作为APP应用程序区域。
所以我们这里需要设置一下之前写好的APP应用程序的中断向量表。

注意:Bootloader程序的中断向量表不需要做任何设置,只需要对APP应用程序的STM32工程进行设置。

设置中断向量表偏移可以直接修改库文件中对中断向量表的操作,但是一般情况下我们不要随意修改库文件,所以我们只需要在APP应用程序的代码中的主函数开头添加一句话即可:

SCB->VTOR = FLASH_BASE | 0x5000;

因为我定义的APP用户程序开始地址是0x8005000,所以中断向量表偏移0x5000就可以了。

4、改变APP用户程序的代码存放地址空间
在Keil编译环境下改变代码存放的地址空间操作如下图:
 

在IAR环境下则是修改stm32f10x_flash.icf文件中的参数。一般该文件在工程的目录文件夹下,不在IAR的工程显示目录下。将该文件拖到IAR中修改两个参数即可,如下图。

5、在BootLoader程序中将PC指针跳转到用户代码处,如下操作即可:

 1 typedef        void (*pFunction)(void);
 2 pFunction       Jump_To_Application;
 3 uint32_t       JumpAddress;
 4 #define       ApplicationAddress       0x08005000
 5
 6 //检测栈顶的地址,判断用户代码的堆栈地址是否落在0x2000000~0x2001ffff区间
 7 if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
 8 {
 9     /* 锁定 Flash */
10     FLASH_Lock();
11
12     /* 跳转至用户程序 */  //ApplicationAddress + 4  对应的是app中断向量表的第二项,复位地址
13     JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
14
15     Jump_To_Application = (pFunction) JumpAddress;  //把地址强转为函数指针
16
17     //设置主函数栈指针   将用户代码的栈顶地址设为栈顶指针
18     __set_MSP(*(__IO uint32_t*) ApplicationAddress);
19
20     //调用函数,实际失去app复位地址去执行复位操作---设置程序指针为复位地址
21     Jump_To_Application();
22 }

6、通过串口接收文件
这里我们需要通过串口接收更新代码的文件,然后将文件内容写入指定的Flash地址中,那么这里接收的数据最好是可以直接写入Flash中去的。
而我们常用的烧写代码的文件有**.hex文件和.bin文件,hex文件中不仅包含了代码数据,还包含了代码的位置信息,所以若是我们采用hex文件则需要对接收到的数据进行处理,去掉里面的位置信息,然后再写于相应的地址空间里,这样操作就显得麻烦了许多。而bin文件里的数据全部都是代码数据,也就是我们可以直接读取bin文件中的数据然后直接写入Flash中。
所以,这里我选择的是使用bin文件,即将APP用户程序的可执行文件转换成bin文件之后,再运行bootloader程序,通过按键触发更新操作,然后通过串口工具发送文件给串口,串口接收到该文件之后将其写入指定的Flash地址中,然后再跳转到该起始地址开始运行程序,即通过串口实现了流水灯程序的写入。
如此,现在想要更新该程序,比如想把流水灯效果改为呼吸灯,那么我们只需要先编写好呼吸灯的程序并生成bin文件,然后通过串口上传该文件即可更新程序,达到不用通过烧写器烧写程序即可改变运行的程序。
Keil环境下直接通过配置即可生成bin文件,首先我们得先找到Keil安装目录下自带的fromelf.exe所在的目录,然后将生成的.axf**文件转换为bin文件即可。具体配置如下图:

F:\Keil_v5\ARM\ARMCC\bin\fromelf.exe --bin -o …\OBJ\firstApp.bin …\OBJ\测试.axf
 

原文地址:https://www.cnblogs.com/linxw-blog/p/12655516.html

时间: 2024-10-08 22:25:13

STM32F103-串口IAP的相关文章

STM32串口IAP分享

什么是IAP? IAP是In Application Programming的首字母缩写,IAP是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级. 在重新编程过程中可以使用任意类型的通信协议,如UART.I2S.SPI等.这篇笔记分享的是使用UART方式IAP. 串口IAP实验 先理一理流程(本实验是以STM32F103ZET6为例): 1.实验说明 做这个实验需要准备两个keil工程,一个工程用

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级

完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第69章       STM32H7的系统bootloader之串口IAP固件升级 本章节为大家讲解使用系统bootloader做程序升级的方法,即使不依赖外部boot引脚也可以方便升级. IAP的全称是In Application Programming,即在线应用编程. 69.1 初学者重要提示 69.2 跳转到系统bootloader的程序设计 69.3 STM

stm32f103串口实现映射功能

在实际开发中,经常遇到串口的默认输出IO口被其他模块占用了,所以我们要用到串口IO口映射功能,是指将原来实现功能的IO口映射到其他指定IO口,其他不变.具体操作如下: 先贴出默认下的串口初始化设置: void USART1Conf(u32 baudRate) { USART_InitTypeDef USART_InitSturct;//定义串口1的初始化结构体 GPIO_InitTypeDef GPIO_InitStruct;//定义串口对应管脚的结构体 RCC_APB2PeriphClockC

STM32F103串口配置,并且使用printf进行打印

首先要配置串口时钟: // USART1 clock enable    RCC_APB2PeriphClockCmd(   RCC_APB2Periph_USART1 |   RCC_APB2Periph_GPIOA |   RCC_APB2Periph_AFIO, ENABLE); 然后再配置端口,在配置串口,再使能即可. void USART1_Init(void)   {   /////// config the gpio   GPIO_InitTypeDef GPIO_InitStru

简单实现stm32f103芯片usb模拟U盘进行IAP更新用户程序

更新单片机内的用户程序,方式一般都是仿真器,串口,网络口,usb DFU,另类一点CAN也行,但是这些方式都有一个共同点,必须要有相应的上位机配合操作,还要教会别人使用,那么能不能有更简单傻瓜化的升级方式呢? 今天二逼程序猿就来说说另类一点的USB模拟U盘进行IAP更新升级用户程序的方法!USB模拟U盘,顾名思义就是用STM32的usb device接口,根据usb massstorage大容量存储协议连接电脑,由于现在的电脑都自带massstorage的驱动程序,因此可以在任意一台电脑使用而不

STM32 IAP工具

捣鼓了几天,用QT写了一个串口IAP工具. 使用前,需要将axf转换成bin文件.可以使用keil的fromelf来生产bin文件.然后载入文件并打开串口,按下载就可以了. 工具特点:将文件按1K为单位发送.不足1K,在末尾补全0xff至1K 按下面的格式传送 data_len_L data_len_H data(no more than 1K) index_L index_H CRC 2B数据长度 最多1KB的有效数据(真正的烧录数据) 2B的数据索引(表示接收/发送的数据是第几个1K) 4B

IAP技术原理

目录 IAP技术原理 更新记录 IAP与ISP的概念及原理 ISP简介 ISP原理 IAP简介 IAP原理 IAP优势 IAP的设计 1.程序启动流程 2.中断向量表的重定位 3.IAP跳转APP函数分析 4.APP跳转IAP函数分析 5.Keil MDK的设置 参考资料 IAP技术原理 更新记录 version status description date author V1.0 C Create Document 2018.10.17 John Wan V2.0 M 对中断向量表的理解有误

博客开通第一帖,给自己的学习历程立个Flag!

看到博客园里其他朋友写的文章很有技术深度也很有参考价值,随便看一个技术人员的博客就能看出他的学习和进步成长的历程,最近工作不是特别忙,一直也想系统性有选择的学习下相关知识,特开此贴! 初步给自己定的学习目标如下:1.STM32串口IAP→2.STM32外加网口芯片实现网络通信→3.STM32 emWin 完成以上学习后准备开始ESP8266的学习之路,一直都想搞点物联网类的可玩性高的小玩意. 原文地址:https://www.cnblogs.com/MR-zhanglei/p/9284602.h

stm32f103的串口通信之串口轮询实验

经过两天的艰苦战斗,经历了心平气和-->烦躁-->放任自由-->心平气和,我今天晚上的最后一分钟,终于将它搞定了! 首先阐述问题:在把usart.c文件里有关中断的部分注释掉以后,使用轮询模式进行串口通讯,但是在这过程中,遇到的问题是只能显示第一个字符: 首先说明原因:在使用轮询模式时,不要使用延时函数,也不要使用中断,如使用printf()这样的函数:      如下是完整代码:      main.c #include "stm32f10x.h" #include

STM32F103 USB虚拟串口 驱动例程移植

1)驱动下载及安装.目前ST公司支持WIN7版本号为:VCP_V1.3.1_Setup.exe (在官网上搜索stsw-stm32102即是了):先安装驱动后再插入USB不然安装不成功. 2)固件下载.目前ST公司最新USB固件库为:STM32_USB-FS-Device_Lib_V4.0.0(在官网上搜索stsw-stm32121即是了). 3)ST官网:www.st.com 4)检查系统是否带了usbser.sys文件.很多GHOST版本的系统,系统驱动文件丢失导致!INF文件下载地址:ht