2)代码的使用方法 先上代码,转跳到app的程序 上面这段代码是转跳到应用程序的代码,这里要画个重点。 1)设置栈顶地址 1.在app中开启中断,需要在mian开头的位置,开启中断以及初始化用到的外设和使能相应的外设时钟。 在上一篇博客中我提到了STM32F407+虚拟串口在线升级的基本原理,这一篇我讲一下关于一些,在虚拟串口在线升级的代码和注意的一些细节。 在线升级原理不清楚的请移步参考上一篇[我用一张图了解虚拟串口IAP](https://blog.csdn.net/cs111211/article/details/105142049)
1.升级代码讲解
1)拷贝app代码到flash。
void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite) { FLASH_Status status = FLASH_COMPLETE; u32 addrx=0; u32 endaddr=0; if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return; //非法地址 FLASH_Unlock(); //解锁 FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间禁止数据缓存。 addrx=WriteAddr; //写入起始地址 endaddr=WriteAddr+NumToWrite*4; //写入结束地址 if(addrx<0X1FFF0000) //只有主存储区才执行擦除操作 ! while(addrx<endaddr) //对非0xFF的地方先擦除 if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//擦除非0XFFFFFFFF地方 { status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);//VCC=2.7~3.6V之间 if(status!=FLASH_COMPLETE)break; //发生错误了 }else addrx+=4; } } if(status==FLASH_COMPLETE) { while(WriteAddr<endaddr)//写数据 { if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)//写入数据 { break; //写数据异常 } WriteAddr+=4; pBuffer++; } } FLASH_DataCacheCmd(ENABLE); //FLASH擦除结束,开启数据缓存 FLASH_Lock();//上锁 } u32 iapbuf[512]; //缓冲 void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize) { u32 t; u16 i=0; u32 temp; u32 fwaddr=appxaddr;//写入当前的地址 u8 *dfu=appbuf; for(t=0;t<appsize;t+=4) { temp=(u32)dfu[3]<<24; temp|=(u32)dfu[2]<<16; temp|=(u32)dfu[1]<<8; temp|=(u32)dfu[0]; dfu+=4;//偏移4个地址 iapbuf[i++]=temp; if(i==512) { i=0; STMFLASH_Write(fwaddr,iapbuf,512); fwaddr+=2048;//偏移2048 512*4=2048 } } if(i)STMFLASH_Write(fwaddr,iapbuf,i);// }
上面这部分代码是将app写入到FLASH的指定区域的方法,需要在工程里把flash的库加到工程中。
也就是stm32f4xx_flash.c。
这些函数是用来写app的,我们需要调用接口是void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)。这里有三个输入的参数:
2.跳转代码以及注意点
void iap_load_app(u32 appxaddr) { if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法 { __disable_irq();//关闭所有中断 RCC_AHB2PeriphResetCmd(RCC_AHB2Periph_OTG_FS, ENABLE); RCC_AHB2PeriphResetCmd(RCC_AHB2Periph_OTG_FS, DISABLE); //复位USB OTG TIM_Cmd(TIM3,DISABLE);//定时器失能 jump2app=(iapfun)*(vu32*)(appxaddr+4); //代码区第二个字是程序开始地址(复位地址) MSR_MSP(*(vu32*)appxaddr); //初始化app堆栈指针(第一个字用于存放栈顶地址) jump2app(); //转跳到app } }
1)关闭所有中断
在转跳到app程序前要把已经开启的所有中断关闭掉。因为升级只上一次电,如果不关闭中断的话,中断寄存器什么的都没有变。在跳到app程序后中断仍然在,但是中断函数却没了,程序不知道中断是来自哪个地方的,所以会导致程序卡死。所以使用__disable_irq();//关闭所有中断
2)失能已经开启的外设
这个和上一条的注意点要类似,因为在我的bootloader 程序中用到了定时器和usb虚拟串口,而app程序中也用到了定时器和虚拟串口。所以要想在app里也能够正常使用这些外设的话必须在转跳之前将这些外设失能,而失能外设的方法就是disable它的时钟。
RCC_AHB2PeriphResetCmd(RCC_AHB2Periph_OTG_FS, ENABLE);
RCC_AHB2PeriphResetCmd(RCC_AHB2Periph_OTG_FS, DISABLE); //这两句就是复位USB OTG
TIM_Cmd(TIM3,DISABLE);//是定时器失能。
3)实现跳转
jump2app=(iapfun)(vu32)(appxaddr+4); 这句对应的是app中断向量表的第二项,复位地址强制转化为函数指针
MSR_MSP((vu32)appxaddr); //初始化app堆栈指针(第一个字用于存放栈顶地址)
这句话是设置主函数栈指针。
最后一句 jump2app(); //转跳到app调用函数,去app复位地址去执行复位操作3.app程序的生成方法
APP程序在主函数变量定义之后加入这句话
SCB->VTOR=0x8000000|0X10000;
这句话的意思是app栈顶地址是0x08010000,同理可设其他地址。
2)设置add
在target for options中的target选项中照下图编辑,在IROM1后的第一个框后的地址改为0x08010000这个地址是app的起始地址,第二个框改成0xf0000这个框是app程序的大小我这里用的flash是1m的所以size=1M-64k=0xf0000。这两个框里面的内容必须是0x400的整数倍。
4)生成bin文件
在设置完地址之后,我们需要一个把程序转化成bin文件的东西,在keilv5里面可以实现这个功能首先找到 fromelf.exe的路径然后在找到你output里的文件名我这里工程是USART,然后编译后会生成一个.axf后缀的文件.
然后在user选项中的Run#1前点上勾,在后面的框填入如下格式的一段路径
E:MDK5ARMARMCCbinfromelf.exe –bin -o …OBJUSART.bin …OBJUSART.AXF
前面的是 fromelf.exe的路径 –bin -o …OBJUSART.bin …OBJUSART.AXF
然后点ok,点击编译然后在输出区出现下面的提示说明成功生成bin文件。在OBJ文件夹中可以找到USART.bin这个文件。
4.app程序的一些注意点
2.user里的路径一定要输入正确不然会报错。我的是在 E:MDK5ARMARMCCbinfromelf.exe路径下,根据自己的MDK装的位置不同这个会不同。
3.一定要在程序中加入 SCB->VTOR=0x8000000|0X10000;。不然不升级之后代码不能运行。
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算