完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
一、IAP简介
IAP就相当于一个用户自定义的bootloader,这样一来,芯片上就有两个bootloader,一个是芯片出厂前固化的(关于这个bootloader究竟在哪儿,我暂时还不清楚)。另一个是用户自定义的,用户可以在程序运行的过程中对内部flash部分的区域进行烧写,主要用于产品发布后,固件程序进行更新升级。因此设计固件程序时需要编写两个项目代码:第一个是bootloader程序,主要通过外设通信(UART、USB、ETH、SD卡等)来接收程序或数据,这段程序通过JLINK或者ISP烧入;第二个称为APP程序。这段程序根据地址的不同,可以放在SRAM段和FLASH段。若放在FLASH段,一般从最低地址区开始存放BootLoader,接着是APP 程序。若放在SRAM段,则将SRAM分为三部分,第一部分给Bootloader使用,第二部分给APP程序使用,第三部分用作为APP程序的内存。 图1.1 STM32内存地址映射 二、IAP程序流程 ------------------------------------------------------------------------------------------------------------------------ BOOT1 | BOOT0 | 启动方式 X | 0 | 从STM32内置flash启动,JTAG或者SWD固化程序位置 1 | 1 | 从STM32内置SRAM启动,由于SRAM没有程序存储能力,这个模式一般用于程序debug 0 | 1 | 从STM32内置ROM启动,使用串口借助bootloader下载程序至flash,即ISP ------------------------------------------------------------------------------------------------------------------------ 通过设置BOOT1和BOOT0的电平就可以设置STM32启动时从哪个位置开始启动,通常默认从FLASH启动。 当没有IAP时,程序从0x0800000处启动,然后进入0x08000004处的复位中断,并跳转到0x08000004+n处的复位中断程序,在复位中断程序执行结束后,才会跳转到main函数进行死循环。在循环时发生中断就会进入对应的中断服务程序执行,结束后再次返回main函数。 加入IAP后,程序的运行流程就变成了: 图2.1 IAP程序流程 程序在第一次复位中断后进入的是IAP程序的main函数,判断程序是否需要更新,若需要更新,则通过串口等通讯接口接收新的APP程序,存放到某个缓冲区内,通过缓冲区内的数据对FLASH或者RAM中的APP程序进行更新,更新结束后跳转到新的APP程序进行执行。若不需要更新,则直接跳转到APP程序进行执行。 三、IAP程序解析 在一个IAP程序中比较重要的三个部分分别是: 1.接收数据部分 以串口接收数据为例: #define USART_REC_LEN 122800 //定义最大接收字节数 120K字节 #if EN_USART1_RX //如果使能了接收 //串口1中断服务程序 //注意,读取USARTx->SR能避免莫名其妙的错误 u8 USART_RX_BUF[USART_REC_LEN]__attribute__((at(0X20001000))); //接收缓冲,最大USART_REC_LEN个字节.起始地址为0X20001000. //接收状态 //bit15, 接收完成标志 //bit14, 接收到0x0d //bit13~0, 接收到的有效字节数目 u16 USART_RX_STA=0; //接收状态标记 u32 USART_RX_CNT=0; //接收数据计数器 void USART1_IRQHandler(void) { u8 res; #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntEnter(); #endif if(USART1->SR&(1<<5))//接收到数据 { res=USART1->DR; if(USART_RX_CNT USART_RX_BUF[USART_RX_CNT]=res; USART_RX_CNT++; } } #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntExit(); #endif } #endif 这段程序的作用是在SRAM中划分120K的USART_RX_BUF[ ]缓冲区用于存储USART接收到的二进制APP程序文件,USART_RX_CNT是计数作用,用于在将程序写入FLASH时判断是否写完。 2.更新程序部分 //0x20001000是USART_RX_BUF的起始地址,新的APP程序接收到该地址空间, //起始地址+4是复位中断 if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000) { iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth); //更新flash代码 } u32 iapbuf[512];//临时缓冲区 //appxaddr:应用程序的起始地址,传入值为FLASH_APP1_ADDR,这是宏定义好的APP在FLASH中的起始地址 //appbuf:应用程序code //appsize:应用程序大小(字节) 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 //appbuf是u8类型的缓冲区 //iapbuf是u32类型的,所以一次放四个appbuf temp=(u32)dfu[3]<<24; temp|=(u32)dfu[2]<<16; temp|=(u32)dfu[1]<<8; temp|=(u32)dfu[0]; dfu+=4; iapbuf[i++]=temp; if(i==512)//临时缓冲区满 { i=0; STMFLASH_Write(fwaddr,iapbuf,512); fwaddr+=2048;//偏移2048 (512*4) } } //写剩余的数据 if(i)STMFLASH_Write(fwaddr,iapbuf,i); } 重要代码分析: if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000) 0X20001000是USART_RX_BUF缓冲区指定的起始地址,即接收到的新的APP程序的起始地址,将0X20001000+4强转成(vu32*)指针并取值跟0xFF000000进行与运算,判断程序的是否在0x08XXXXXX处,即FLASH代码。 3.跳转程序部分 //从新的APP起始地址+4取出复位中断的值判断是不是flash代码 if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000) { iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码 } typedef void(*iapfun)(void); void iap_load_app(u32 appxaddr) { if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)//判断栈定地址值是否在0x2000 0000 - 0x 2000 2000之间 { jump2app=(iapfun)*(vu32*)(appxaddr+4); MSR_MSP(*(vu32*)appxaddr); //初始化 APP 堆栈指针(用户代码区的第一个字用于存放栈顶地址) jump2app(); } } 重要代码分析: typedef void(*iapfun)(void); iapfun是我们创建的一个类型别名,可通过iapfun声明一个返回值是void,参数类型是void的函数指针。 jump2app=(iapfun)*(vu32*)(appxaddr+4); 将appxaddr+4的值强转成(vu32*)指针,并从该地址取值,强转成iapfun类型函数指针,就可以通过jump2app()函数直接跳转到APP程序的复位中断地址。 MSR_MSP(*(vu32*)appxaddr); 由图2.1知道,在复位中断向量之前存放的是栈顶地址,因为这是新的APP程序,所以需要重新指定一下栈顶地址(但我觉得不指定也行,只不过栈的大小会变小,未经过验证) 0x08000000是FLASH的起始地址,根据程序的大小分配Size,注意为0x200的整数倍 FLASH APP程序起始位置和大小分配: Start:由Bootloader程序的Start+Size确定,0x08000000+8000=0x08008000 Size:由Flash的大小减去Bootloader程序的大小确定,FLASH为1024K,0x100000-0x8000=0xF8000 SRAM APP程序的起始位置和大小分配与上面的流程相似,就不废话了。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1810 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1631 浏览 1 评论
1098 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
737 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1687 浏览 2 评论
1945浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
750浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
584浏览 3评论
604浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
568浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-29 13:12 , Processed in 0.572585 second(s), Total 73, Slave 57 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号