STM32_IAP详解(有代码,有上位机).doc

上传人:白大夫 文档编号:3273541 上传时间:2019-08-07 格式:DOC 页数:10 大小:41.50KB
返回 下载 相关 举报
STM32_IAP详解(有代码,有上位机).doc_第1页
第1页 / 共10页
亲,该文档总共10页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《STM32_IAP详解(有代码,有上位机).doc》由会员分享,可在线阅读,更多相关《STM32_IAP详解(有代码,有上位机).doc(10页珍藏版)》请在三一文库上搜索。

1、STM32_IAP详解(有代码,有上位机)Iap,全名为in applacation programming,即在应用编程,与之相对应的叫做isp,in system programming,在系统编程,两者的不同是isp需要依靠烧写器在单片机复位离线的情况下编程,需要人工的干预,而iap则是用户自己的程序在运行过程中对User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。在工程应用中经常会出现我们的产品被安装在某个特定的机械结构中,更新程序的时候拆机很不方便,使用iap技术能很好地降低工作量.实现iap有两个很重要的前提,首

2、先,单片机程序能对自身的内部flash进行擦写,第二,单片机要有能够和外部进行通讯的方式,无论是网络还是别的方式,只要能传输数据就行通常实现 IAP 功能时,即用户程序运行中作自身的更新操作,需要在设计固件程序时编写两个项目代码,第一个项目程序不执行正常的功能操作,而只是通过某种通信方式(如 USB、 USART)接收程序或数据,执行对第二部分代码的更新;第二个项目代码才是真正的功能代码。这两部分项目代码都同时烧录在 User Flash 中,当芯片上电后,首先是第一个项目代码开始运行,它作如下操作:1)检查是否需要对第二部分代码进行更新2)如果不需要更新则转到 4)3)执行更新操作4)跳转到

3、第二部分代码执行第一部分代码必须通过其它手段,如 JTAG 或 ISP 烧入;第二部分代码可以调用第一部分的功能也就是说,将iap和app做成两个程序,这是其中的一种策略,还有一种策略,可以把iap程序和app程序做在一个代码中,但是那样耦合性有点高,我们先进行第一种尝试.要做iap首先我们要知道stm32的启动流程,流程如下1、单片机从0x80000000位置启动,并将该地址当成系统栈顶地址2、运行到中断向量表中,默认的中断向量表为0x80000004,该位置存放复位中断3、跳转到复位中断处理函数当中,进行系统初始化,然后运行main函数当我们准备用iap的时候,单片机内部是有着两套程序的,

4、这个时候我们就需要在iap中和app中分别放置两套中断向量表,当iap代码中将app烧写到flash中之后,跳转到app的中断向量表中,程序就可以正常执行了,当然需要修改某些系统设置,使得在app和iap阶段单片机可见的中断向量表只能有一套(具体请查看stm32芯片的启动代码)而当需要从app跳转到iap的时候,只需要将app的中断向量表修改成iap的中断向量表,同时主动跳转到iap的reset中断处理程序,这样就能再次开始iap流程.这样,在系统中就需要我们确定几个东西,第一个是iap程序的中断向量表,为0x80000004位置(80000000存放的是msp的初始值),第二个是app程序的

5、中断向量表,该位置需要根据iap程序的长度计算,比如iap占用了64K,那么512K的芯片而言,就还有448K的空间存放app程序,448K的最开始放置中断向量表,位置就应该是0x08000000+0x10004的位置.Cortex-m3的中断向量并不是在程序中固定的,我们可以通过修改某些寄存器来修改对于当前应用的中断向量表位置.决定中断向量表的寄存器是如下这个通过修改这个寄存器的值,我们可以控制对于当前单片机应用来说可见的向量表的位置(也就说说逻辑上我们有两个向量表,但是同一时间只有一个运行)以上是内核阶段的操作,在此之外我们还需要对stm32的flash进行编程,那么就涉及到删除的编程和擦

6、除操作,这需要参考stm32的闪存编程手册首先,当单片机复位之后,闪存式被锁住的,需要主动去解锁,向FLASH_KEYR写入两个指定的连续键值用于解锁然后将需要写入的闪存擦除,擦除之后在进行写入,写入完成,再次上锁对应的代码如下u16 STMFLASH_BUFSTM_SECTOR_SIZE/2;/最多是2K字节void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)u32 secpos; /扇区地址u16 secoff; /扇区内偏移地址(16位字计算)u16 secremain; /扇区内剩余地址(16位字计算) u16 i

7、;u32 offaddr; /去掉0X08000000后的地址if(WriteAddr=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)return;/非法地址FLASH_Unlock(); /解锁offaddr=WriteAddr-STM32_FLASH_BASE; /实际偏移地址.secpos=offaddr/STM_SECTOR_SIZE; /扇区地址 0127 for STM32F103RBT6secoff=(offaddr%STM_SECTOR_SIZE)/2; /在扇区内的偏移(2个字节为基本单位.)secremain=STM_SECTOR_SIZE

8、/2-secoff; /扇区剩余空间大小if(NumToWrite(STM_SECTOR_SIZE/2)secremain=STM_SECTOR_SIZE/2;/下一个扇区还是写不完else secremain=NumToWrite;/下一个扇区可以写完了;FLASH_Lock();/上锁该函数可以实现flash的写入操作,接下来我们需要定义一套通讯协议用于串口数据传输/串口接收缓冲区u8 serial_BufferSERIAL_MAX_LENGTH = 0;/串口接收数据长度u16 serial_Buffer_Length = 0;u8 receiveMode = 0;/接收参数的中断处理模

9、型,为0的时候是命令模式,为1的时候为下载模式u8 receiveExpectCount = 0;/串口期望接收长度/串口中断处理static void SerialRecv(u8 ch)if(receiveMode = 0)if(serial_Buffer_Lengthserial_Buffer_Length |= 0x8000;/退出else if(serial_Buffer_Lengthif(ch = n)serial_Buffer_Length |= 0x8000;else/一帧接受失败serial_Buffer_Length = 0;elseif(serial_Buffer_Leng

10、thif(ch = r)serial_Buffer_Length |= 0x4000;elseserial_Buffer(serial_Buffer_Lengthserial_Buffer_Length+;else/一帧接受失败serial_Buffer_Length = 0;else/下载模式,只控制字符串的量,数据的第一位是该数据包的长度,接收到这么多长度,接收完成位置一/注意,在这种模式下,清除serial_Buffer_Length之前应当清除receiveExpectCount的值if(receiveExpectCount = 0)/期望下载为0,第一个数就是期望下载数receive

11、ExpectCount = ch;elseif(serial_Buffer_Lengthserial_Buffer_Length |= 0x8000;/退出elseserial_Buffer(serial_Buffer_Length/接收数据并保存serial_Buffer_Length+;if(serial_Buffer_Lengthserial_Buffer_Length |= 0x8000;/一包接收完成标志这样系统就能接收数据了,接下来定义五个命令iap_downiap_jump_appiap_overiap_set_flagiap_clear_flag第一个命令为系统开始下载,在这个

12、命令之后上位机就能够将程序数据发下来了,第二个命令为iap跳转到app的跳转指令第三个命令是指示iap完成,将系统缓冲区清空的指令第四个指令为设置app标志,当iap检测到该标志的时候直接跳转到app程序中第五个指令为清除app标志,让iap程序不自动跳转到app程序中,我们分别来看首先是iap_set_flag,其响应函数如下#define APP_CONFIG_ADDR 0X08001FFC /配置地址#define APP_CONFIG_SET_VALUE 0X5555 /设置值#define APP_CONFIG_CLEAR_VALUE 0XFFFF /清零值/设置app固化配置voi

13、d iap_set_flag_s(void)Test_Write(APP_CONFIG_ADDR,APP_CONFIG_SET_VALUE);printf(okrn);我们使用0x08000000-0x08003000来存放iap代码,并将0X08001FFC作为存放app固化标志的地方/清除app固化配置void iap_clear_flag(void)Test_Write(APP_CONFIG_ADDR,APP_CONFIG_CLEAR_VALUE);printf(okrn);对iap_jump2app命令的响应如下/跳转到应用程序段/appxaddr:用户代码起始地址.void iap_

14、load_app(u32 appxaddr)if(*(vu32*)appxaddr)printf(okrn);Delay_Ms(10);jump2app=(iapfun)*(vu32*)(appxaddr+4); /用户代码区第二个字为程序开始地址(复位地址)MSR_MSP(*(vu32*)appxaddr); /初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)jump2app(); /跳转到APP.elseprintf(program in flash is errorrn);/跳转到app区域运行void iap_jump_app_s(void)iap_load_app(FLA

15、SH_APP1_ADDR);/跳转到app的复位向量地址接下来就是iap_down,用于下载的核心算法#define FLASH_APP1_ADDR 0x08002000 /第一个应用程序起始地址(存放在FLASH)/保留的空间为IAP使用u16 iapbuf1024 = 0; /用于缓存数据的数组u16 receiveDataCur = 0; /当前iapbuffer中已经填充的数据长度,一次填充满了之后写入flash并清零u32 addrCur = FLASH_APP1_ADDR; /当前系统写入地址,每次写入之后地址增加2048/开始下载void iap_down_s(void)u16

16、i = 0;u16 temp = 0;u16 receiveCount;printf(begin,wait data downloadrn);receiveMode = 1;/串口进入下载接收数据模式while(1)/循环接收数据,每次必须要发128个数据下来,如果没有128,说明这是最后一包数据/接收到一包数据之后,返回一个小数点,发送完成,系统编程完成之后返回一个iap_overif(serial_Buffer_Length receiveCount = (u8)(serial_Buffer_Lengthif(receiveCount = 128)/满足一包,填充并查看是否有了1024字节

17、,有了写入闪存for(i = 0; i 如果需要flash下载的话还需要设置jlink的flash下载设置如下.这样可以直接使用jlink将代码下载到单片机中,而且不会影响原先的app程序,注意,要选择erase sector used,不能全部擦除flash桥斗麻袋,我们忘了一件事情,假设我们设置了app标志,那及时app能跳转到iap中,iap岂不是马上会跳转回app,永远不能等待下载?解决办法就是我们在app中app跳转到iap的指令中将app固化标志清除掉,在app代码中添加一条指令Iap,其响应方法为_asm void MSR_MSP(u32 addr)MSR MSP, r0 /se

18、t Main Stack valueBX r14void iap_jump(u32 iapxaddr)if(*(vu32*)iapxaddr)printf(okrn);Delay_Ms(10);jump2iap=(iapfun)*(vu32*)(iapxaddr+4); /用户代码区第二个字为程序开始地址(复位地址)MSR_MSP(*(vu32*)iapxaddr); /初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)jump2iap(); /跳转到APP.elseprintf(iap program loss,please checkrn);#define APP_CONFIG_

19、ADDR 0X08001FFC /配置地址#define APP_CONFIG_SET_VALUE 0X5555 /设置值#define APP_CONFIG_CLEAR_VALUE 0XFFFF /清零值void iap_Func(void)Test_Write(APP_CONFIG_ADDR,APP_CONFIG_CLEAR_VALUE);iap_jump(FLASH_IAP_ADDR);/跳转到iap的复位向量地址可以看到,我们先清除了app标志,然后在跳转到iap程序中,就不会影响到iap的流程了,同时app代码也还在单片机里面,另外,app工程里面也要设置两个东西因为flash的起始

20、地址为0x08000000,而我们用了之前2000的空间作为iap代码空间,那么,app代码的起始空间就变成了0x8002000,还有一个下载界面需要设置红框部分也要修改.是不是没有说中断向量表的问题,在iap中我们不需要考虑中断向量表,因为默认就是在0x8000000位置的,但是在app中代码的起始位置变了,必须重新设置中断向量表在system_stm32f10x.c中有一个system_init函数,该函数被启动代码调用,配置系统时钟,在该函数中的最后一句为#ifdef VECT_TAB_SRAMSCB-VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vect

21、or Table Relocation in Internal SRAM. */#elseSCB-VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */#endif其中VECT_TAB_OFFSET就是我们要定义的偏移量,也就是app程序的起始地址偏移,我们知道是2000,那么该值的宏就需要修改,在大约128行的位置/此处为flash偏移地址,app应当修改这个地址#define VECT_TAB_OFFSET 0x2000 /*!三个代码的工程我会打包上传到csdn,想更深入了解的可以下载来看看,软件用mfc编写的

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1