[首页]
[文章]
[教程]
首页
Web开发
Windows开发
编程语言
数据库技术
移动平台
系统服务
微信
设计
布布扣
其他
数据分析
首页
>
其他
> 详细
【转】stm32 IAP升级程序
时间:
2019-11-01 14:37:56
阅读:
70
评论:
0
收藏:
0
[点我收藏+]
一、什么是IAP,为什么要IAP
IAP即为In Application Programming(在应用中编程),一般情况下,以STM32F10x系列芯片为主控制器的设备在出厂时就已经使用J-Link仿真器将应用代码烧录了,如果在设备使用过程中需要进行应用代码的更换、升级等操作的话,则可能需要将设备返回原厂并拆解出来再使用J-Link重新烧录代码,这就增加了很多不必要的麻烦。站在用户的角度来说,就是能让用户自己来更换设备里边的代码程序而厂家这边只需要提供给用户一个代码文件即可。
而IAP却能很好的解决掉这个难题,一片STM32芯片的Code(代码)区内一般只有一个用户程序。而IAP方案则是将代码区划分为两部分,两部分区域各存放一个程序,一个叫bootloader(引导加载程序),另一个较user application(用户应用程序)。bootload
er在出厂时就固定下来了,在需要变更user application时只需要通过触发bootloader对userapplication的擦除和重新写入即可完成用户应用的更换。如图1-1所示
图 1-1
在程序执行初始进入bootloader,在bootloader里面检测条件是否被触发(可通过按键是否被按下、串口是否接收到特定的数据、U盘是否插入等等),如果有则进行对user application进行擦除和重新写入操作,如果没有则直接跳转到user application执行应用;如果有则进行擦除用户代码并重新写入新的用户代码。
二、STM32F103ZET6硬件条件
STM32F103ZET6的启动方式有三种:内置FLASH启动、内置SRAM启动、系统存储器ROM启动,通过BOOT0和BOOT1引脚的设置可以选择从哪中方式启动,这里选择内置的FLASH启动。其FLASH的地址为0x08000000—0x0807ffff,共512KB,这些都能从芯片数据手册中直接得到。而这里首要的一个问题是中断的问题。正常情况下发生中断的过程为:发生中断(中断请求)à到中断向量表查找中断函数入口地址à跳转到中断函数à执行中断函数à中断返回。也就是说在STM32的内置的Flash中有一个中断向量表来存放各个中断服务函数的入口地址,内置Flash的分配情况大致如下图2-1。
图2-1
在只有一个程序的情况下,程序执行的走向应该如图2-2所示(借用网友的原图)。
图2-2
STM32F10x有一个中断向量表,这个中断向量表存放在代码开始部分的后4个字节处(即0x08000004),代码开始的4个字节存放的是堆栈栈顶的地址,当发生中断后程序通过查找该表得到相应的中断服务程序入口地址,然后再跳到相应的中断服务程序中执行。上电后从0x08000004处取出复位中断向量的地址,然后跳转到复位中断程序的入口(标号①所示),执行结束后跳转到main函数中(标号②所示)。在执行main函数的过程中发生中断,则STM32强制将PC指针指回中断向量表处(标号③所示),从中断向量表中找到相应的中断函数入口地址,跳转到相应的中断服务函数(标号④所示),执行完中断函数后再返回到main函数中来(标号⑤所示)。
若在STM32F103x中使用IAP方案,则内置的Flash分配情况大致如下图2-3。
图2-3
在内置的Flash里面添加一个BootLoader程序,BootLoader程序和user application各有一个中断向量表,假设BootLoader程序占用的空间为N+M字节,则程序的走向应该如图2-2所示(借用网友的原图并做改动,其中虚线部分为原图步骤④⑤的走向,本人改为指向灰色部分)。
图2-2
上电初始程序依然从0x08000004处取出复位中断向量地址,执行复位中断函数后跳转到IAP的main(标号①所示),在IAP的main函数执行完成后强制跳转到0x08000004+N+M处(标号②所示),最后跳转到新的main函数中来(标号③所示),当发生中断请求后,程序跳转到新的中断向量表中取出新的中断函数入口地址,再跳转到新的中断服务函数中执行(标号④⑤所示),执行完中断函数后再返回到main函数中来(标号⑥所示)。
对于步骤④⑤,网友认为是:“在main执行的过程中,如果CPU得到一个中断请求,PC指针仍强制跳转到地址0x08000004中断向量表处,而不是新的中断向量表,如图标号④所示,程序再根据我们设置的中断向量表偏移量,跳转到对应中断源新的中断服务程序中,如图标号⑤所示”。我对此的理解是:“当发生中断后,程序从0x08000004(旧)处的中断向量表中得到相应的中断服务函数入口地址,继而跳转到相应的中断服务程序”。但是旧的中断向量列表里边存放的是IAP程序中断函数的入口地址,它是如何得到user程序中断函数的入口地址呢?所以我觉得此种说法是错误的。“当发生中断时PC指针强制会跳转到0x08000004处”这种说法并没有错,只是忽略了后续的一些知识要点而导致这个说法出现矛盾。
对于步骤④⑤我认为的是,在main函数的执行过程中,如果CPU得到一个中断请求,PC指针本来应该跳转到0x08000004处的中断向量表,由于我们设置了中断向量表偏移量为N+M,因此PC指针被强制跳转到0x08000004+N+M处的中断向量表中得到相应的中断函数地址(待求证),再跳转到相应新的中断服务函数,执行结束后返回到main函数中来。
三、实现过程
STM32F103ZET6的Flash地址为0x08000000—0x0807ffff共512KB,把这512KB的空间分为两块,第一块大小为32KB存放BootLoader程序,剩余的空间存放用户程序(根据实际情况分配这两块空间的大小,BootLoader程序占用的空间越小越好,则BootLoader地址为0x08000000—0x08007fff,用户程序地址为0x08008000—0x0807ffff。BootLoader流程图大致应该如下:
1、初始化时钟。
2、初始化中断向量表地址。
3、初始化按键。 (使用按键触发方式,上电时如果按键被按下则进行用户程序更新操作)
4、初始化串口。
5、检测按键是否被按下,是则执行步骤6,否则执行步骤10。
6、擦除用户程序(擦除0x08008000—0x0807ffff地址空间Flash)。
7、从串口读取新的用户代码数据,把代码写入用户程序空间。
8、检测串口数据接收完毕?是则执行步骤9,否则跳回步骤7。
9、用户程序更新完毕,等待重新上电或硬件复位。
10、跳转到用户程序(强制将PC指针跳转到0x08008000+4处)。
到这里首先要解决的问题就有:
1、如何进行对STM32的Flash进行擦除和写入操作。
2、中断向量表偏移如何设置。
3、如何改变代码存放的地址空间(因为BootLoader要存放在0x08000000处,用户程序要存放在0x08008000处,而默认的代码存放的地址空间为0x08000000)。
4、怎么进行PC指针的强制跳转,跳转时需要做些什么。
5、串口接收的用户代码数据是什么样的代码数据,是一种什么样的文件。
问题的解决:
1、使用STM32的固件库函数,只需调用几个库函数即可轻松解决,使用的固件库为stm32f10x_flash.c文件,对Flash的操作过程简要为:Flash解锁àFlash擦除àFlash写入àFlash上锁。(对Flash编程的更详细操作参考STM32F10xxx闪存编程手册)
①解锁:
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个半字)
}
说明:因为STM32的Flash写入为双字节(1个半字)写入,FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)函数即为对地址为Address写入1个半字的Data,每次写入完成后地址要加2。
④上锁:
FLASH_Lock(); //Flash 上锁,一个固件库函数即可实现。
2、关于中断向量表的偏移设置,对于BootLoader程序只需设置中断向量表的指向在0x08000000处,对于用户程序需要设置中断向量表的指向在0x08008000处即可。
①在BootLoader程序的中断向量表指向设置中应有这么一句:
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); //设置中断向量表指向
其中NVIC_VectTab_FLASH是个宏定义,的值为0x08000000。
②在用户程序的中断向量表指向设置用应有这么一句:
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x8000); //设置中断向量表指向
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
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这个函数指针指向复位函数入口地址。
④堆栈的初始化,重新设定栈顶代地址,把栈顶地址设置为用户代码指向的栈顶地址。
⑤跳转到新的复位函数。
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文件进行用户程序更新,这也避免了STM32与PC笨重的通讯,只需插一个SD卡(或U盘)更显得人性化一些,但需要去弄懂STM32如何与SD卡(或U盘)的通讯。
一
、什么
是
IAP,为什么要IAP
IAP
即为
In Application Programming
(在
应用中编程
),一般情况下
,
以
STM32F10x
系列芯片为
主控制器的设备在出厂时就已经使用
J-Link
仿真器将应用代码烧录了,
如果在
设备使用过程中需要进行
应用
代码
的
更换、升级等
操作
的话
,则
可能需要将设备
返回
原厂
并
拆解出来再使用J-Link重新烧录代码,
这就
增加了很多不必要的麻烦。站在用户的角度来说,就是能让用户自己来更换设备里边的代码程序而厂家这边只需要提供给用户一个代码文件即可。
而
IAP却能很好的解决掉这个难题,
一片
STM32芯片
的Code(代码)区内
一般只有一个用户程序
。
而IAP
方案
则是将代码
区
划分为
两部分,
两部分
区域各
存放一个程序,
一个
叫bootloader(
引导
加载程序)
,
另一个
较
user application(
用户
应用程序)
。
bootload
er
在
出厂时
就
固定下来了,在需要变更user application时只需要通过
触发
bootloader对
user
application
的
擦除和重新
写入
即可完成
用户
应用的更换。
如
图
1
-1
所示
图 1
-1
在
程序执行初始进入
bootloader
,在bootloader里面
检测条件
是否被触发
(可
通过按键
是否被
按下、串口
是否
接收到特定的数据、U盘
是否插入
等等
),
如果有则进行对user application进行擦除和重新写入操作,
如果
没有则直接跳转到user application执行应用
;如果
有则进行擦除用户代码并重新写入新的用户代码。
二
、STM32F103ZET6硬件条件
STM32F103ZET6的启动方式有三种:内置FLASH
启动、
内置
SRAM
启动、
系统
存储器ROM启动
,通过
BOOT0和BOOT1引脚
的
设置可以选择从哪中方式启动
,
这里
选择
内置的FLASH启动。
其
FLASH
的
地址为
0
x08000000—0x0807ffff
,
共
512
KB
,
这些都能从芯片数据手册中直接得到。
而
这里
首要
的一个问题是
中断
的问题。
正常
情况下发生中断的过程为:
发生
中断
(中断
请求
)
à
到
中断向量表查找中断函数入口地址
à
跳转
到中断函数
à
执行
中断函数
à
中断
返回
。
也就
是说
在STM32
的
内置的Flash中
有
一个中断向量表
来
存放各个中断服务函数的入口地址,内置Flash的分配情况大致如下
图2
-1
。
图2
-1
在
只有一个程序的情况下,程序执行的走向应该如图
2
-2
所示(借用网友
的原图
)
。
图2
-2
STM
32F10x
有一个
中断向量表,
这个
中断向量表存放在
代码
开始部分的后4个字节处
(即0
x08000004
)
,代码开始的4个字节存放的是堆栈栈顶的地址,
当
发生中断
后程序
通过查找该表
得到
相应的中断服务程序入口地址,
然后
再跳到相应的中断服务程序中执行。
上电后从0x08000004处
取出
复位
中断向量的地址,然后跳转到复位中断程序的入口
(标号
①
所示)
,
执行
结束后跳转到main函数
中(标号
②所示
)。在
执行main函数的过程中
发生
中断
,
则
STM
32
强制
将
PC
指针
指回
中断
向量
表
处
(
标号
③
所示
)
,
从中断向量表中找到相应的中断函数入口地址,跳转到相应的中断服务函数
(标号
④
所示),
执行完中断函数后
再
返回到main
函数
中来
(标号
⑤
所示)。
若
在STM32F103x中使用
IAP
方案,则内置的Flash
分配
情况大致如下
图2
-3
。
图2
-3
在内置的Flash里面添加一个BootLoader程序,
BootLoader
程序和
user
application
各有
一个中断向量
表
,
假设
BootLoader程序占用的空间为N+M字节,则程序的走向应该如图
2
-2
所示(借用
网友的原图
并
做改动
,
其中虚线部分为
原图步骤
④⑤
的
走向
,本人
改为
指向
灰色
部分)。
图2
-2
上电
初始程序依然从
0
x08000004
处
取出复位中断向量地址
,
执行复位中断函数后跳转到
IAP
的main
(标号
①
所示
)
,在
IAP的main函数
执行
完成后强制跳转到
0
x08000004+N+M处
(标号
②
所示),
最后跳转到
新的
main函数中来
(标号
③
所示)
,
当
发生中断请求后,程序跳转到新的中断向量表中取出新的中断函数入口地址,
再
跳转到新的中断服务函数中执行
(标号
④⑤
所示),执行
完中断函数后再返回到main函数中来
(标号
⑥
所示)。
对于步骤
④⑤
,
网友
认为
是:
“在
main执行的过程中
,
如果CPU
得到
一个中断请求,
PC
指针
仍
强制
跳转
到地址
0
x08000004
中断
向量表
处,
而不是新的中断向量表,
如
图标号
④
所示
,
程序
再根据
我们
设置的中断
向量表偏移量,
跳转
到
对应中断
源新
的中断服务
程序
中
,
如图标号
⑤
所示”。我对此
的理解是
:“当
发生中断后,程序从
0
x08000004(
旧
)
处的
中断向量表中
得到相应
的中断
服务
函数入口地址,继而跳转
到
相应的中断服务程序
”
。
但是
旧的中断向量列表里边存放的是
IAP
程序
中断
函数的入口地址,它是如何得到user程序中断函数的入口地址
呢
?所以
我
觉得
此种
说法是错误的。
“
当发生中断时PC指针强制会跳转
到0
x08000004
处”这种
说法并没有错,只是忽略了
后续
的一些
知识
要点
而
导致
这个
说法出现矛盾。
对于
步骤
④⑤
我认为
的是
,
在main函数的执行过程中,如果CPU得到一个中断请求,
PC
指针本
来应该
跳转到
0
x08000004
处
的中断向量表,
由于
我们设置
了
中断向量表偏移量为
N+M,因此PC
指针
被
强制
跳转
到
0
x08000004+N+M
处
的中断向量表中得到相应的中断
函数
地址
(待求证)
,再跳转到相应新的中断服务函数,执行结束后返回到main函数中来。
三
、
实现过程
STM32F103ZET6的Flash地址为
0x08000000
—
0x
0807ffff
共512
KB
,把
这512KB的空间
分为两块
,第一块大小为
32
KB
存放
BootLoader程序,
剩余
的空间存放用户程序
(根据
实际情况分配
这
两块空间的大小,BootLoader程序占用的空间越小越好
,
则BootLoader
地址
为
0x08000000
—
0x
08007fff
,
用户程序地址
为0x08008000
—
0x
0807ffff
。BootLoader
流程图
大致
应该如下:
1、初始化
时钟
。
2、
初始化中断向量表地址
。
3
、
初始化按键
。
(
使用
按键触发方式,
上电
时如果按键被按下则
进行
用户程序更新操作)
4、
初始化串口
。
5、
检测按键是否被按下
,
是则执行
步骤6,
否则执行步骤
10。
6
、
擦除用户程序
(擦除0x08008000
—
0x
0807ffff
地址
空间Flash
)。
7
、从
串口读取新的用户代码数据
,
把
代码
写入用户程序空间
。
8、
检测串口数据接收完毕?是
则
执行步骤
9,
否则
跳回
步骤
7。
9、用户
程序更新完毕,等待重新上电
或硬件
复位。
10
、
跳转到用户程序
(强制
将PC指针
跳转
到
0
x08008000+4
处)。
到这里首先
要解决的问题就有:
1
、如何
进行对STM32
的
Flash
进行
擦除和写入操作。
2
、
中断向量表偏移
如何
设置。
3
、如何改变
代码
存放
的地址空间
(因为BootLoader
要存放在
0x08000000处
,
用户
程序要存放在
0x08008000处,而
默认
的
代码存放的地址空间为
0x08000000)。
4
、
怎么进行PC指针的强制跳转,
跳转
时需要做些什么
。
5
、
串口接收
的
用户
代码
数据
是
什么样的
代码数据
,是一种什么样的文件。
问题
的
解决
:
1
、使用
STM32的固件库函数,只需调用几个库函数即可轻松解决
,
使用的
固件库
为stm32f10x_flash.c
文件,
对Flash的操作过程简要为:Flash解锁
à
Flash擦除
à
Flash写入
à
Flash
上锁。(对
Flash
编程
的
更
详细操作参考
S
TM32F10xxx
闪存编程手册
)
①
解锁
:
FLASH_Unlock(); //解锁Flash
FLASH_SetLatency(FLASH_Latency_2); //
因为
系统时钟为
72
M所以要设置两个时钟周期的延时
②
擦除
:
for(i=0;i<240;i++)
{
if(FLASH_ErasePage(FLASH_ADDR+i*2048) != FLASH_COMPLETE) //
一定
要判断是否擦除成功
return ERROR;
}
说明
:FLASH_ErasePage(uint32_t Page_Address)
即
为Flash擦除操作,按
页
擦除,每页
2
KB,Page_Address
为
页的起始地址,
如0
x08000000
是
第一页起始地址,
0
x08000800
为
第二页起始地址,这里
的
操作
擦除
了
0x08008000
—
0x
0807ffff
地址
空间的Flash。
③
写入
:
u
nsigned
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
个
半字
)
}
说明:因为
STM32的Flash写入为双字节
(
1
个
半字
)写入
,FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
函数
即为对
地址
为Address
写入
1
个
半字
的
Data,每次写入完成后地址要加
2。
④
上锁
:
FLASH_Lock(); //Flash
上锁
,
一个固件库
函数即可实现。
2、关于
中断向量表的
偏移
设置,对于BootLoader程序
只需
设置中断向量表
的
指向在
0x
08000000
处
,
对于
用户程序需要设置中断向量表的指向在
0x08008000处
即可
。
①
在
BootLoader程序的中断向量表指向设置
中
应有这么一句:
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); //
设置
中断向量表指向
其中
NVIC_VectTab_FLASH
是
个宏定义,的值为
0x08000000。
②
在用户
程序
的
中断向量表指向设置用应有这么一句:
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x8000); //
设置
中断向量表指向
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
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
这个
函数
指针
指向复位函数入口地址
。
④堆栈
的初始化,
重新
设定栈顶代
地址
,
把栈顶
地址设置为用户代码
指向
的栈顶地址
。
⑤跳转
到
新的
复位函数。
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
文件
进行
用户
程序更新,这也避免了STM32
与
PC笨重的通讯,只需插一个SD卡(或U盘)更显得人性化一些,但需要去弄懂STM32
如何
与SD卡
(
或U盘
)
的通讯。
【转】stm32 IAP升级程序
原文:https://www.cnblogs.com/birdBull/p/11776749.html
踩
(
0
)
赞
(
0
)
举报
评论
一句话评论(
0
)
登录后才能评论!
分享档案
更多>
2021年09月23日 (328)
2021年09月24日 (313)
2021年09月17日 (191)
2021年09月15日 (369)
2021年09月16日 (411)
2021年09月13日 (439)
2021年09月11日 (398)
2021年09月12日 (393)
2021年09月10日 (160)
2021年09月08日 (222)
最新文章
更多>
2021/09/28 scripts
2022-05-27
vue自定义全局指令v-emoji限制input输入表情和特殊字符
2022-05-27
9.26学习总结
2022-05-27
vim操作
2022-05-27
深入理解计算机基础 第三章
2022-05-27
C++ string 作为形参与引用传递(转)
2022-05-27
python 加解密
2022-05-27
JavaScript-对象数组里根据id获取name,对象可能有children属性
2022-05-27
SQL语句——保持现有内容在后面增加内容
2022-05-27
virsh命令文档
2022-05-27
教程昨日排行
更多>
1.
list.reverse()
2.
Django Admin 管理工具
3.
AppML 案例模型
4.
HTML 标签列表(功能排序)
5.
HTML 颜色名
6.
HTML 语言代码
7.
jQuery 事件
8.
jEasyUI 创建分割按钮
9.
jEasyUI 创建复杂布局
10.
jEasyUI 创建简单窗口
友情链接
汇智网
PHP教程
插件网
关于我们
-
联系我们
-
留言反馈
- 联系我们:wmxa8@hotmail.com
© 2014
bubuko.com
版权所有
打开技术之扣,分享程序人生!