
本帖最后由 yu0405jie 于 2015-12-16 21:13 编辑 9 p4 b: A/ \' O: }/ d6 L6 U 5 @7 s; ~6 Q3 O1 T/ l% N IAP,全称是“In Application Programming”,中文可意为“在线应用编程”,简单的说就是在单片机中写入一段可以称为自定义Bootloader的程序,通过该程序可以更新我们需要的应用程序,并跳转到应用程序执行。那么如何实现IAP功能呢? 首先我们需要对整个存储区进行分配,避免不同的程序写入到同一片存储区而造成错误。我们让Bootloader占16k个字节,即地址范围为0x08000000至0x08003FFF,其余作为应用程序的存储区,对于互联型单片机来说为0x08004000至0x0803FFFF。 既然设计到程序的烧写和程序的执行,我们就不得不对单片机的启动和中断的处理有一个认识。 单片机上电之后,会将主闪存存储器(0x08000000)映射到启动空间(0x00000000)中,并固定的从0x00000000获取栈顶地址,从0x00000004获取代码的执行地址,那么0x08000000存储的都是什么内容呢?其实0x08000000存储的是一个指针数组,其中第一元素存储的是栈顶地址,第二个元素开始存储的都是各中断处理函数的地址,而第一个中断函数指针指向的便是复位中断处理函数的地址。这些中断处理函数指针数组就是所谓的“中断向量表”,每当单片机发生中断时,CPU就从中断向量表中获取相应的地址,执行相应的处理函数。 同时中断向量表的位置是可以更改的,而且必须能够更改,否则我们的IAP功能就无法实现了,通过库函数NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x4000),我们可以将中断向量表定义在0x08004000地址处,这个函数只是告诉CPU中断向量表在某个地址处,但这个地址存放的是否真的是中断向量表呢?还需要我们在链接文件中做一些处理,这个稍后再讲。现在重新梳理一下单片机的工作流程,从中来看我们都需要做哪些工作。 单片机上电之后,从0x08000000地址处(这个地址不就是我们的Bootloader存放地址吗?所以单片机上电之后首先执行的是Bootloader程序)取得栈顶地址和复位中断处理函数地址,并执行复位中断处理函数,如下所示(以IAR为例): PUBWEAK Reset_Handler SECTION .text:CODE:REORDER(2) Reset_Handler LDR R0, =SystemInit BLX R0 LDR R0, =__iar_program_start BX R0 由上述代码可知,复位中断处理函数共执行了两个函数,SystemInit用于初始化系统时钟和Flash接口,__iar_program_start主要用于初始化全局变量,并最终顺利进入我们Bootloader的main()函数中,开始执行我们的Bootloader程序。 Bootloader中有两个分支,是更新应用程序?还是跳转到应用程序?可以由一个外部按键决定,比如按键按下时开始更新应用程序,按键没有按下时进入应用程序。 当需要更新应用程序时,我们首先需要获得应用程序的二进制数据,这可以通过串口从上位机获得,可以从SD卡或U盘获得,这里就不在进行介绍,不过需要注意的是如果接受的是bin文件,可以直接读取文件里的数据写入Flash,如果是hex文件,则还需要进行解析在写入Flash中,编写的地址自然是从我们设计好的应用程序地址0x08004000开始依次写入,至于Flash 的操作,可以参考其他的资料。 要跳转到应用程序时,就必须知道需要执行指令的地址,这个地址如何获取呢?想想单片机上电之后是如何获取执行指令地址的?是从中断向量表中获取的,我们也采取同样的方法,通过在应用程序中的设置,我们可以将中断向量表写到0x08004000这个地址处,通过如下的代码就可以获得应用程序中复位中断处理函数的地址值了 uint32_t AppAddress = *(uint32_t *)(0x08004000 + 4); 这个地址存放的是复位中断处理函数,因此可以利用函数指针来获取复位中断处理函数,通过一个简单的函数调用,就可以进入应用程序的复位中断处理函数,并最终进入应用程序的main()函数,执行应用程序指令了。 Typedef void (*pFunc)(void); pFunc AppFunc = (pFunc)AppAddress; (*AppFunc)(); Bootloader端的程序到目前就结束了,应用程序需要什么特殊处理呢?主要就是中断向量地址的设置和应用程序指令的地址分配。 设置中断向量地址是为了告诉CPU,在发生中断时应该从新的地址寻找中断处理函数,以和Bootloader的中断区分开来,通过下面一条语句就可以实现: NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x4000); C语言中的变量、函数等到了目标文件中全部转换为地址的读取和跳转,为了防止这些地址和Bootloader中的地址相冲突,也必须对指令地址的分配进行约束,其方法是通过设置链接文件实现的,对于IAR来说,执行如下图的两个设置: 图一设置中断向量表的地址,此时的设置将影响生成的bin文件中中断向量表的位置,也就是影响中断向量表在Flash中的位置。 图二设置存储区的地址范围,当开发环境对文件进行地址分配时,所有指令的地址都会在该范围内。 设置好地址信息后,应用程序端的工作也就完成了。 |
å¾ä¸ï¼è®¾ç½®ä¸æåé表å°å
å¾äºï¼è®¾ç½®åå¨åºå°å
学习一下
1 M z# c" j5 c2 e2 ` m+ [- t8 t& W
学习一下