STM32第三十课(IAP,bootloader)

用户可以通过设置BOOT1和BOOT0引脚的状态,来选择在复位后的启动模式。
[ bootmode1:bootmode0 ]
1)00或者10:即bootmode为0时,始终从Main Flash启动。是STM32内置的Flash,一般我们使用JTAG或者SWD模式下载程序时,就是下载到这个里面,重启后也直接从这启动程序。起始地址0x80000000。
2)01:即bootmode0为1,但是bootmode1为0时,从system memory启动。系统存储器是芯片内部一块特定的区域,STM32在出厂时,由ST在这个区域内部预置了一段BootLoader, 也就是我们常说的ISP程序, 这是一块ROM,出厂后无法修改。在厂家提供的BootLoader中,提供了串口下载程序的固件,可以通过这个BootLoader将程序下载到系统的Flash中。
Step1:将BOOT0设置为1,BOOT1设置为0,然后按下复位键,这样才能从系统存储器启动BootLoader
Step2:最后在BootLoader的帮助下,通过串口下载程序到Flash中
Step3:程序下载完成后,又有需要将BOOT0设置为GND,手动复位,这样,STM32才可以从Flash启动, 需要跳帽跳来跳去。
3)11:即bootmode0为1,同时bootmode1也为1,从embeded memory启动。内置SRAM,既然是SRAM,自然也就没有程序存储的能力了,这个模式一般用于程序调试。

Flash锁死解决办法:
开发调试过程中,由于某种原因导致内部Flash锁死,无法连接SWD以及Jtag调试,无法读到设备,可以通过修改BOOT模式重新刷写代码。
修改为BOOT0=1,BOOT1=0即可从系统存储器启动,ST出厂时自带Bootloader程序,SWD以及JTAG调试接口都是专用的。重新烧写程序后,可将BOOT模式重新更换到BOOT0=0,BOOT1=X即可正常使用。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
应用中产品装配完成后,下载口不便引出的情况下,或者是某些设备需要具有远程更新程序情况下,使用串口IAP的方式将会更加便捷。
STM32单片机内部的flash可以在程序中让单片机自身去擦写编程,同时官方也提供了相应的操作函数固件库。如果要实现让单片机自身去升级程序,就必须要将内部flash空间进行划分,分不同的区域写入不同工程的程序代码,才能实现该功能。
一般情况下,我们将单片机的内部flash空间划分为两大区域,为了方便理解,我们叫做bootloader区域和app区域

如果想要将程序按照如上所示的flash空间存放的话,就必须对编译环境进行一些设置,才能到达我们的目的,不再使用默认的编译设置。
初始的设置是,
irom1的base addr 是0x0800_0000,这是main flash的起始地址开始。size是0x0010_0000,所以大小是1MBytes。
iram1的base addr 是0x2000_0000,这是embeded sram1的base addr。size是0x0001_C000,所以大小是112KBytes。
iram2的base addr 是0x2001_C000,这是embeded sram2的base addr。size是0x0000_4000,所以大小是16KBytes。

我们如果要使用IAP,那么就需要建立两个工程。
一个是bootloader工程,一个是app工程。
对于bootloader工程,我们需要设置irom1的base addr和size,
对于app工程,我们也需要设置irom1的base addr和size。

例如,
设置bootloader工程的irom1,baseaddr为0x0800_0000,size为0x0000_2000,即,分配8KBytes的Flash空间给bootloader工程。
设置app工程的irom1,baseaddr为0x8000_2000,size为0x000F_E000,即,分配剩下的1016KBytes的Flash空间给app。

这样,就设置了工程代码的编译地址空间。

除了设置工程代码的编译地址之外,还要将中断向量表偏移寄存器的值进行相对应的设置。设置中断向量表偏移寄存器的方法有两种:
在app应用程序的主程序while循环之前设置,设置格式为:

SCB->VTOR = FLASH_BASE | 0x2000;

或者修改固件库,
固件库system_stm32f10x.c文件中,使用了如下的设置:

SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET 

#define VECT_TAB_OFFSET 0x0

默认情况下,“VECT_TAB_OFFSET”的值等于0。也就是不进行偏移,在进行IAP编程的时候,可以将此处的初值改为对应的偏移量即可。偏移量不能随意任意设置,中断向量表必须对齐原则。因此中断偏移量的值必须是0x200的倍数。即必须是512Bytes的倍数。通常设置为1KBytes的倍数。

Cortex-M3内核规定,起始地址必须存放堆顶指针,而第二个地址则必须存放复位中断入口向量地址,这样在Cortex-M3内核复位后,会自动从起始地址的下一个32位空间取出复位中断入口向量,跳转执行复位中断服务程序。
Cortex-M3内核是固定了中断向量表的位置而起始地址是可变化的。

单片机要在两个区域(bootloader区域和app区域)之间进行跳转。跳转之前除了要将app工程代码中的中断偏移量进行相对应的设置外,还要在单片机跳转时,设置app区域代码的主堆栈栈顶地址。
STM32默认启动地址是0x0800_0000,而这个首地址中保存的就是堆栈的栈顶地址,这个地址是在代码编译后,有编译器自动产生。
STM32的程序存放规则和编译后的可执行文件的规则是,编译后的可执行文件中第一个字,就是被下载到STM32内部flash中的第一个存储单元中,而这个就是我们需要的堆栈栈顶地址。
重新设置STM32的堆栈栈顶地址是属于内核级别的操作,因此只能借助嵌入汇编的形式进行操作,一般是使用MSR指令进行操作的。
例如:

__asm void stach_setting(unsigned int stack_addr)
{
	MSR MSP, r0
	BX r14
}

从r0中取出参数表中的第一个参数,存入MSP寄存器中。
然后从r14中取出返回点,return。

+++++++++++++++++++++++++++++++++++++++++++++++
完成对工程的设置与程序代码的编写之后,我们还需要得到相应工程的BIN格式文件,keil软件自带输出BIN文件的功能,但是一般情况下我们不使用BIN文件,所以程序代码编译完毕后,软件默认是不输出BIN格式的文件。
如想要keil在编译完成之后,同时输出BIN文件,则需要进行设置,设置方法是在工程管理的选项卡的User选项中的
Run #1处编写命令

fromelf.exe --bin -o "$L@L.bin" "#L"

在KEIL环境中设置,name of Executable为axf文件的名
字,实际上.bin文件是通过.axf文件转换的。
例如:

D:\Keil_v5\ARM\ARMCC\bin\fromelf.exe --bin -o .\led.bin .\led\led.axf

在工程目录下,生成 .\led.bin 文件,源文件为 .\led\led.axf 文件。

+++++++++++++++++++++++++++++++++++++++++++++++
AREA指令:伪指令,用于定义代码段或数据段,后跟属性标号。
其中比较重要的一个标号为“READONLY”或者“READWRITE”,
其中“READONLY”表示该段为只读属性,联系到STM32的内部存储介质,可知具有只读属性的段保存于FLASH区,即0x8000000地址后。
而“READWRITE”表示该段为“可读写”属性,可知“可读写”段保存于SRAM区,即0x2000000地址后。堆栈段位于SRAM空间。
中断向量表放置与FLASH区,而这也是整片启动代码中最先被放进FLASH区的数据。
0x8000000地址存放的是栈顶地址__initial_sp,
0x8000004地址存放的是复位中断向量Reset_Handler(STM32使用32位总线,因此存储空间为4字节对齐)。

DCD指令:作用是开辟一段空间,其意义等价于C语言中的地址符“&”。
因此从DCD开始建立的中断向量表则类似于使用C语言定义了一个指针数组,其每一个成员都是一个函数指针,分别指向各个中断服务函数。

标号:标号主要用于表示内存空间的某个位置,等价于C语言中的“地址”概念。
地址仅仅表示存储空间的一个位置,从C语言的角度来看,变量的地址,数组的地址或是函数的入口地址在本质上并无区别。

__main标号表示C/C++标准实时库函数里的一个初始化子程序__main的入口地址。该程序的一个主要作用是初始化堆栈(对于程序清单一来说则是跳转__user_initial_stackheap标号进行初始化堆栈的),并初始化映像文件,最后跳转C程序中的main函数。

总结一下STM32的启动文件和启动过程。首先对栈和堆的大小进行定义,并在代码区的起始处建立中断向量表,其第一个表项是栈顶地址,第二个表项是复位中断服务入口地址。然后在复位中断服务程序中跳转¬¬C/C++标准实时库的__main函数,完成用户堆栈等的初始化后,跳转.c文件中的main函数开始执行C程序。
假设STM32被设置为从内部FLASH启动(这也是最常见的一种情况),中断向量表起始地位为0x8000000,则栈顶地址存放于0x8000000处,而复位中断服务入口地址存放于0x8000004处。
当STM32遇到复位信号后,则从0x80000004处取出复位中断服务入口地址,继而执行复位中断服务程序,然后跳转__main函数,最后进入mian函数,来到C的世界。

++++++++++++++++++++++++++++++++++++++++++++++++
编译bootloader工程。

官方参考例程是AN2557。
http://www.st.com/internet/com/SOFTWARE_RESOURCES/SW_COMPONENT/FIRMWARE/an2557.zip

官方参考例程AN4657。
https://www.st.com/en/embedded-software/x-cube-iap-usart.html

官方参考例程AN3965。
https://www.st.com/en/embedded-software/stsw-stm32067.html

首先下载官方bootloader例程,修改ROM空间大小,例如修改为0x2000,即8KBytes。
然后添加宏定义,STM32F40X_MD,
然后更改启动文件,startupxxx.s。
在option for file starupxxx.s设置框内,确认勾选include in target build,勾选always build。
然后修改工程中的C代码,
修改定义。在common.h中,修改

#define ApplicationAddress 0x08002000

将app的起始位置后移。
这样做的目的,是最后hand-off的时候,跳转到app的起始地址重新执行reset_handler。

++++++++++++++++++++++++++++++++++++++++++++++
编译app工程。
在cubemx生成的工程中,修改。
在app中,需要重新设置VTOR。
可以在main中修改,也可以修改app的库函数。
以main中修改为例,放置main的第一个执行语句,就是修改VTOR。

/*USER CODE BEGIN1*/
	SCB->VTOR = FLASH_BASE | 0x2000;
	...
/*USER CODE END1*/
	HAL_Init();

设置工程时,附加生成bin文件的run#1命令。

++++++++++++++++++++++++++++++++++++++++++++
YModem协议是由XModem协议演变而来的,每包数据可以达到1024字节,是一个非常高效的文件传输协议。
采用Ymodem协议的调制解调器以1024字节数的块发送数据。成功接收的不会被确认。有错误的块被确认(NAK),并重发。
文件传输函数包含了YModem协议文件传输的过程,根据YModem协议,发送数据之前和之后都需建立握手通信,
Ymodem使用循环冗余码校验作为错误校验方式。
需要使用支持Ymodem协议的工具,例如secureCRT。

++++++++++++++++++++++++++++++++++++++++++

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值