打印
[开发工具]

IAR环境下STM32+IAP方案的实现(转)

[复制链接]
3847|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ccw1986|  楼主 | 2015-9-26 07:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
基于STM32F103ZET6UART通讯实现
、什么IAP,为什么要IAP
      IAP即为In Application Programming(在应用中编程),一般情况下STM32F10x系列芯片为主控制器的设备在出厂时就已经使用J-Link仿真器将应用代码烧录了,如果在设备使用过程中需要进行应用代码更换、升级等操作的话,则可能需要将设备返回原厂拆解出来再使用J-Link重新烧录代码,这就增加了很多不必要的麻烦。站在用户的角度来说,就是能让用户自己来更换设备里边的代码程序而厂家这边只需要提供给用户一个代码文件即可。
      IAP却能很好的解决掉这个难题,一片STM32芯片的Code(代码)区内一般只有一个用户程序而IAP方案则是将代码划分为两部分,两部分区域各存放一个程序,一个叫bootloader(引导加载程序)另一个user application(用户应用程序)bootload[url=]er出厂时固定下来了,在需要变更user application时只需要通过触发bootloader对userapplication擦除和重新写入即可完成用户应用的更换。1-1所示[/url]

图 1-1
[url=]      程序执行初始进入bootloader,在bootloader里面检测条件是否被触发(可通过按键是否被按下、串口是否接收到特定的数据、U盘是否插入等等),如果有则进行对user application进行擦除和重新写入操作,如果没有则直接跳转到user application执行应用;如果有则进行擦除用户代码并重新写入新的用户代码。[/url]

[url=]、STM32F103ZET6硬件条件[/url]
[url=]      STM32F103ZET6的启动方式有三种:内置FLASH启动、内置SRAM启动、系统存储器ROM启动,通过BOOT0和BOOT1引脚设置可以选择从哪中方式启动这里选择内置的FLASH启动。FLASH地址为0x08000000—0x0807ffff512KB这些都能从芯片数据手册中直接得到。这里首要的一个问题是中断的问题。正常情况下发生中断的过程为:发生中断(中断请求)à中断向量表查找中断函数入口地址à跳转到中断函数à执行中断函数à中断返回也就是说在STM32内置的Flash中一个中断向量表存放各个中断服务函数的入口地址,内置Flash的分配情况大致如下图2-1[/url]

图2-1

[url=]只有一个程序的情况下,程序执行的走向应该如图2-2所示(借用网友的原图)[/url]

图2-2
[url=]      STM32F10x有一个中断向量表,这个中断向量表存放在代码开始部分的后4个字节处(即0x08000004),代码开始的4个字节存放的是堆栈栈顶的地址,发生中断后程序通过查找该表得到相应的中断服务程序入口地址,然后再跳到相应的中断服务程序中执行。上电后从0x08000004处取出复位中断向量的地址,然后跳转到复位中断程序的入口(标号所示)执行结束后跳转到main函数中(标号②所示)。在执行main函数的过程中发生中断STM32强制PC指针指回中断向量(标号所示)从中断向量表中找到相应的中断函数入口地址,跳转到相应的中断服务函数(标号所示),执行完中断函数后返回到main函数中来(标号所示)。[/url]
[url=]      在STM32F103x中使用IAP方案,则内置的Flash分配情况大致如下图2-3[/url]

图2-3


评分
参与人数 1威望 +15 收起 理由
mmuuss586 + 15 很给力!
沙发
ccw1986|  楼主 | 2015-9-26 07:54 | 只看该作者
[url=]在内置的Flash里面添加一个BootLoader程序,BootLoader程序和user application各有一个中断向量假设BootLoader程序占用的空间为N+M字节,则程序的走向应该如图2-2所示(借用网友的原图做改动其中虚线部分为原图步骤④⑤走向,本人改为指向灰色部分)。[/url]

图2-2
[url=]      上电初始程序依然从0x08000004取出复位中断向量地址执行复位中断函数后跳转到IAP的main(标号所示),在IAP的main函数执行完成后强制跳转到0x08000004+N+M处(标号所示),最后跳转到新的main函数中来(标号所示)发生中断请求后,程序跳转到新的中断向量表中取出新的中断函数入口地址,跳转到新的中断服务函数中执行(标号④⑤所示),执行完中断函数后再返回到main函数中来(标号所示)。[/url]
[url=]      对于步骤④⑤网友认为是:“在main执行的过程中如果CPU得到一个中断请求,PC指针强制跳转到地址0x08000004中断向量表处,而不是新的中断向量表,图标号所示程序再根据我们设置的中断向量表偏移量,跳转对应中断源新的中断服务程序如图标号所示”。我对此的理解是:“当发生中断后,程序从0x08000004()处的中断向量表中得到相应的中断服务函数入口地址,继而跳转相应的中断服务程序但是旧的中断向量列表里边存放的是IAP程序中断函数的入口地址,它是如何得到user程序中断函数的入口地址?所以觉得此种说法是错误的。当发生中断时PC指针强制会跳转到0x08000004处”这种说法并没有错,只是忽略了后续的一些知识要点导致这个说法出现矛盾。[/url]
[url=]      对于步骤④⑤我认为的是在main函数的执行过程中,如果CPU得到一个中断请求,PC指针本来应该跳转到0x08000004的中断向量表,由于我们设置中断向量表偏移量为N+M,因此PC指针强制跳转0x08000004+N+M的中断向量表中得到相应的中断函数地址(待求证),再跳转到相应新的中断服务函数,执行结束后返回到main函数中来。[/url]

使用特权

评论回复
板凳
ccw1986|  楼主 | 2015-9-26 07:55 | 只看该作者
[url=]实现过程[/url]
[url=]      STM32F103ZET6的Flash地址为0x080000000x0807ffff共512KB,把这512KB的空间分为两块,第一块大小为32KB存放BootLoader程序,剩余的空间存放用户程序(根据实际情况分配两块空间的大小,BootLoader程序占用的空间越小越好则BootLoader地址0x080000000x08007fff用户程序地址为0x080080000x0807ffff。BootLoader流程图大致应该如下:[/url]
[url=]1、初始化时钟[/url]
[url=]2、初始化中断向量表地址[/url]
[url=]3初始化按键      (使用按键触发方式,上电时如果按键被按下则进行用户程序更新操作)[/url]
[url=]4、初始化串口[/url]
[url=]5、检测按键是否被按下是则执行步骤6,否则执行步骤10。[/url]
[url=]6擦除用户程序(擦除0x080080000x0807ffff地址空间Flash)。[/url]
[url=]7、从串口读取新的用户代码数据代码写入用户程序空间[/url]
[url=]8、检测串口数据接收完毕?是执行步骤9,否则跳回步骤7。[/url]
[url=]9、用户程序更新完毕,等待重新上电或硬件复位。[/url]
[url=]10跳转到用户程序(强制将PC指针跳转0x08008000+4处)。[/url]
[url=]     [/url]
[url=]到这里首先要解决的问题就有:[/url]
[url=]1、如何进行对STM32Flash进行擦除和写入操作。[/url]
[url=]2中断向量表偏移如何设置。[/url]
[url=]3、如何改变代码存放的地址空间(因为BootLoader要存放在0x08000000处用户程序要存放在0x08008000处,而默认代码存放的地址空间为0x08000000)。[/url]
[url=]4怎么进行PC指针的强制跳转,跳转时需要做些什么[/url]
[url=]5串口接收用户代码数据什么样的代码数据,是一种什么样的文件。[/url]

[url=]问题解决[/url]
[url=]1、使用STM32的固件库函数,只需调用几个库函数即可轻松解决使用的固件库为stm32f10x_flash.c文件,对Flash的操作过程简要为:Flash解锁àFlash擦除àFlash写入àFlash上锁。(对Flash编程详细操作参考STM32F10xxx闪存编程手册)[/url]
[url=]解锁[/url]

使用特权

评论回复
地板
ccw1986|  楼主 | 2015-9-26 07:56 | 只看该作者
FLASH_Unlock();            //解锁Flash
FLASH_SetLatency(FLASH_Latency_2);            //因为系统时钟为72M所以要设置两个时钟周期的延时
②擦除:
for(i=0;i<240;i++)
{
  if(FLASH_ErasePage(FLASH_ADDR+i*2048) != FLASH_COMPLETE)      //一定要判断是否擦除成功
    return ERROR;
}

说明:FLASH_ErasePage(uint32_t Page_Address)即为Flash擦除操作,按页擦除,每页2KB,Page_Address为页的起始地址,如0x08000000是第一页起始地址,0x08000800为第二页起始地址,这里的操作擦除了0x08008000—0x0807ffff地址空间的Flash。
③写入:
unsigned char buf[1024];            //假设待写入的代码数据
unsigned short temp;            //临时数据
for(i=0;i<512;i++)
{
      temp = (buf[2*i+1]<<8) | buf[2*i];            //2个字节整合为1个半字
      if(FLASH_ProgramHalfWord(ADDR,temp) != FLASH_COMPLETE)      //判断是否写入成功
      {
            Return ERROR;
      }
ADDR +=2;      //地址要加2,因为每次写入的是2个字节(1个半字)
}

使用特权

评论回复
5
ccw1986|  楼主 | 2015-9-26 07:56 | 只看该作者
说明:因为STM32的Flash写入为双字节(1个半字)写入,FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)函数即为对地址为Address写入1个半字的Data,每次写入完成后地址要加2。
④上锁:
FLASH_Lock();      //Flash 上锁,一个固件库函数即可实现。

使用特权

评论回复
6
ccw1986|  楼主 | 2015-9-26 07:56 | 只看该作者
本帖最后由 ccw1986 于 2015-9-26 08:00 编辑

2、关于中断向量表的偏移设置,对于BootLoader程序只需设置中断向量表指向在0x08000000对于用户程序需要设置中断向量表的指向在0x08008000处即可
BootLoader程序的中断向量表指向设置应有这么一句:
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);      //设置中断向量表指向
其中NVIC_VectTab_FLASH个宏定义,的值为0x08000000。
在用户程序中断向量表指向设置用应有这么一句:
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x8000);      //设置中断向量表指向[/url]

3、确认代码存放的地址空间,IAR和在Keil中的设置是不同的,网上有在Keil中设置的方法,设立介绍在IAR软件环境下的设置方法。
在固件库目录\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template\EWARM找到一个stm32f10x_flash.icf文件,将其复制到工程目录中来打开IAR工程,将配置文件添加到工程中,如下图3-2所示

图3-1
工程中打开stm32f10x_flash.icf该文件,修改两个参数即可改变代码存放的地址空间图下图3-2所示

图3-2


使用特权

评论回复
7
ccw1986|  楼主 | 2015-9-26 07:57 | 只看该作者
4、关于PC指针的强制跳转,想在BootLoader程序中将PC指针跳转到用户代码处,可选择下面的操作
typedef        void (*pFunction)(void);     
pFunction       Jump_To_Application;
uint32_t       JumpAddress;
#define       ApplicationAddress       0x08008000


if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)       //--------①
{
  JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);                  //--------②
  Jump_To_Application = (pFunction) JumpAddress;                              //--------③
  __set_MSP(*(__IO uint32_t*) ApplicationAddress);                             //--------④
  Jump_To_Application();                                                                 //--------⑤
}

①因为用户程序开始位置(0x08008000处)的前4个字节存放的是堆栈的地址,堆栈地址必定是指向RAM空间的,而STM32的RAM空间起始地址为0x20000000,所以要进行判断。
②程序跳转地址的确认,前面已经说过0x08008004处的4个字节存放的是复位函数的入口地址,该句的意思为获得(ApplicationAddress + 4)地址处的数据,即为获得新的复位函数入口地址。
③令Jump_To_Application这个函数指针指向复位函数入口地址。
④堆栈的初始化,重新设定栈顶代地址,把栈顶地址设置为用户代码指向的栈顶地址。
⑤跳转到新的复位函数。

使用特权

评论回复
8
ccw1986|  楼主 | 2015-9-26 07:57 | 只看该作者
本帖最后由 ccw1986 于 2015-9-26 07:59 编辑

5、通过串口来接收代码数据,就是PC机通过串口将代码数据发送到STM32中去。这里就涉及到两个问题:
数据怎么得来
数据传输的过程需要遵循的协议,什么时候开始,什么时候结束
解决一般我们就将*.hex文件使用JFlash-ARM打开再通过Jlink仿真器烧录到STM32芯片中,但是*.hex文件里边包含的数据不纯粹是代码数据还有一些别的东西,*.bin文件数据就全部是代码数据。
IAR软件环境中打开一个用户工程,先设置好中断向量表偏移和代码存放的地址空间后(前面已介绍过两种方法)。设置工程如下图3-3所示确认后重新编译工程,在工程的\Debug\Exe目录下会相应生成一个xxx.bin文件这就是所需要的代码文件。

图3-3
数据通过串口来传输文件常用的协议有XModem、YModem、ZModem这三种协议,在PC端使用这些协议传输文件只需要PC的超级终端或者终端工具SecureCRT即可,但是在STM32这边的编程会增加一些困难(因为要先去读懂、解析这些协议,在通过编程来实现)。也可选择自己定义一套简单的传输协议,同样会有一些困难(因为要在PC进行文件和串口编程)。总之不管通过什么办法都行,只要能将xxx.bin文件数据通过串口全部发送到STM32并且STM32够全部接收到这些数据并写入Flash即可(我选择后者,自定义传输协议并用VC进行文件和串口编程)

、结束语
     总的来说STM32的IAP方案实现需要在进行用户程序之前加一段Bootloader程序,BootLoader程序的作用就是:
什么都不做,直接跳转到用户程序。
②删除原有的用户程序,读取*.bin文件数据将数据重新写入新的用户程序
对于用户程序相比普通的编程只需要做三步改动即可
①改变中断向量表。
③修改生成*.bin文件

使用通过UART的IAP方案并不是很好的选择,这只是IAP方案的一个机制,因为能使用PC机通过串口升级程序,同样能通过Jlink烧写程序,并且自定义的串口通讯协议没有校CRC校验的情况下不能及时发现数据传输过程发生的错误。这里推荐使用SD卡(或U盘)进行用户程序更新,*.bin文件复制到SD卡(或U盘)中,STM32再通过读取SD卡(或U盘)*.bin文件进行用户程序更新,这也避免了STM32PC笨重的通讯,只需插一个SD卡(或U盘)更显得人性化一些,但需要去弄懂STM32如何与SD卡(或U盘)的通讯。



使用特权

评论回复
9
ticomi| | 2015-9-26 08:33 | 只看该作者
我也刚刚实现了IAP,通过SD卡方式,原理是一样的!懂了原理,可以实现任何一种IAP方式升级

使用特权

评论回复
10
bbapple| | 2015-9-26 09:49 | 只看该作者
关于IAP的方案,网上的资料还真的不少啊。。

使用特权

评论回复
11
mmuuss586| | 2015-9-26 10:43 | 只看该作者

不错,谢谢分享;

使用特权

评论回复
12
FireRiver9| | 2015-9-28 22:26 | 只看该作者
通过串口来接收代码数据,就是PC机通过串口将代码数据发送到STM32中去

使用特权

评论回复
13
HORSE7812| | 2015-9-29 10:13 | 只看该作者
mark

使用特权

评论回复
14
lanjackg2003| | 2015-9-29 10:28 | 只看该作者
写得不错,图文并茂,用了不少心思...点赞!

使用特权

评论回复
15
android2| | 2015-9-30 15:01 | 只看该作者
楼主讲的很详细啊,收藏了

使用特权

评论回复
16
水化冰| | 2017-7-24 10:46 | 只看该作者
mark

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

925

帖子

6

粉丝