STM32F072使用SD卡进行IAP升级
来源:互联网 发布:数据库图片存储类型 编辑:程序博客网 时间:2024/05/19 05:30
之前做的一个小项目,因为刚开始没有考虑到以后会经常升级,而每次升级都要旋开4颗螺丝拆壳,然后烧程序,再装壳,如果只要更新几个倒没啥感觉,但是一下更新几百个,那工作量。。。。,正好板子上有SD卡,就想着写个Bootloader程序,通过读取SD卡中的Bin文件进行IAP升级,这样可以大大简化以后的升级。IAP升级原理就不多说了,网上相关的资料和帖子一大堆,这里简单介绍我做的IAP方案,欢迎大家批评指正!
跳转程序也是参考的官方例程。我设置的App程序起始地址为:0x0800 A000
Bootloader程序设计
bootloader程序的设计思路很简单,流程图如下:
初始化程序就不介绍了,比较简单。主要介绍下Bin文件检测以及IAP过程。我将IAP过程分为5个步骤,如下:
Step1:检查是否存在升级文件,若存在,打开后跳至Step2,若不存在或者打开失败,跳至Step5
Step2:擦除App程序对应的扇区,擦除成功后跳至Step3,若擦除失败,跳至Step5
Step3:使用f_read()函数读取Bin文件,每次读取2048个字节,并写入Flash。当文件全部被写入flash后跳至Step4,若中间出现写入错误,跳至Step5
Step4:检查栈顶地址,跳转至App程序。若栈顶地址非法,跳至Step5
Step5:此步表示本次升级失败,死循环,同时LED提示升级失败,等待重新上电
查找升级文件时我固定从Update文件夹查找,所以只要将Bin文件拷贝至Update文件夹就行了。
五个步骤的转换是通过switch函数实现的。代码如下:
while(1) { switch(iap_step) { /* Step1:检查是否存在升级文件 */ case 1: { /* 查找升级文件 */ result = f_findfirst(&dj, &fno, "0:/Update", "FDR_update*.bin"); /* 存在升级文件 */ if(result==FR_OK && fno.fname[0]) { /* 获取文件名字符串 */ #if _USE_LFN fn_str = *fno.lfname ? fno.lfname : fno.fname; #else fn_str = fno.fname; #endif /* 得到完整的文件名路径 */ sprintf(fname_path,"/Update/%s",fn_str); /* 打开升级文件 */ result = f_open(&file_fdr,fname_path,FA_OPEN_EXISTING|FA_READ); if(result==FR_OK) { /* 打开成功,准备升级 */ iap_step = 2; } else { /* 打开失败 */ f_close(&file_fdr); f_closedir(&dj); iap_step = 5; } } else { /* 不存在升级文件,直接跳转 */ f_closedir(&dj); iap_step = 4; } break; } /* Step2:存在升级文件,先擦除扇区 */ case 2: { FLASH_Unlock(); res = IAP_FLASH_Erase(APPLICATION_ADDRESS); FLASH_Lock(); if( res ) { iap_step = 3; } else { f_close(&file_fdr); f_closedir(&dj); iap_step = 5; } break; } /* Step3:扇区擦除成功,准备依次读取并写入 */ case 3: { memset(appbuf,0xFF,2052); f_read(&file_fdr,appbuf,2048,&br); FLASH_Unlock(); res = IAP_FLASH_Write((u32*)appbuf,(u16)ceil(br/4.0f)); FLASH_Lock(); Toggle_LED_AP(); if(res == 0) { f_close(&file_fdr); f_closedir(&dj); iap_step = 5; } else { /* 文件读完了 */ if(br<2048) { f_close(&file_fdr); f_closedir(&dj); f_unlink(fname_path); iap_step = 4; } } break; } /* Step4:跳转至App程序 */ case 4: { /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */ if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { /* Jump to user application */ JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); /* Jump to application */ Jump_To_Application(); } else { iap_step = 5; } break; } /* Step5:升级失败,等待重新上电 */ case 5: { if(GetFreqFlag(FREQ_0_5HZ)) { Toggle_LED_AP(); } break; } default: { iap_step = 1; break; } }//iap step switch }//end of bootloader while(1)其中的Flash擦除函数是参考的官方例程:
uint32_t IAP_FLASH_Erase(uint32_t StartSector){ uint32_t flashaddress; flashaddress = StartSector; while (flashaddress <= (uint32_t) USER_FLASH_LAST_PAGE_ADDRESS) { if (FLASH_ErasePage(flashaddress) == FLASH_COMPLETE) { flashaddress += FLASH_PAGE_SIZE; } else { /* Error occurred while page erase */ return (0); } } return (1);}写Flash函数是我在例程的基础上修改的,将flash地址定义为局部静态变量,这样每次写完flash后地址会自增。
uint32_t IAP_FLASH_Write(uint32_t* Data ,uint16_t DataLength){ uint32_t i = 0; volatile static uint32_t wr_addr = APPLICATION_ADDRESS; for (i = 0; (i < DataLength) && (wr_addr <= (USER_FLASH_END_ADDRESS-4)); i++) { /* the operation will be done by word */ if (FLASH_ProgramWord(wr_addr, *(uint32_t*)(Data+i)) == FLASH_COMPLETE) { /* Check the written value */ if (*(uint32_t*)wr_addr != *(uint32_t*)(Data+i)) { /* Flash content doesn't match SRAM content */ return 0; } /* Increment FLASH destination address */ wr_addr += 4; } else { /* Error occurred while writing data in Flash memory */ return (0); } } return (1); }特别要注意形参uint16_t Datalength是指的字数,就是uint32_t类型变量的数量,而f_read读取的是字节数,要除以4进行转换,刚开始就是没有转换导致写的flash数据不正常,跳转后死机。
跳转程序也是参考的官方例程。我设置的App程序起始地址为:0x0800 A000
此外bootloader程序的IAR工程配置如图,flash地址范围:0x0800 0000 - 0x0800 9FFF,占用40K
App程序设计
1、App程序主要在原来的程序基础上修改flash起始和结束地址,以及中断向量偏移。Flash地址范围我设为:0x0800 A000 – 0x0801 FFFF,占用88K,IAR配置如下:
2、由于STM32F0没有像F1,F4那样的中断向量偏移寄存器,需要通过进行内存地址映射来实现,具体实现原理参见点击打开链接 http://www.51hei.com/bbs/dpj-40938-1.html
所以在App程序main函数开始的地方加如下代码:(参考官方例程修改)
#define APPLICATION_ADDRESS (uint32_t)0x0800A000#if (defined ( __CC_ARM ))__IO uint32_t VectorTable[48] __attribute__((at(0x20000000)));#elif (defined (__ICCARM__))#pragma location = 0x20000000__no_init __IO uint32_t VectorTable[48];#elif defined ( __GNUC__ )__IO uint32_t VectorTable[48] __attribute__((section(".RAMVectorTable")));#elif defined ( __TASKING__ )__IO uint32_t VectorTable[48] __at(0x20000000);#endif/*========================================= Main Function ============================================*/void main(void){ uint32_t i = 0; //float sdsize; /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/ /* Copy the vector table from the Flash (mapped at the base of the application load address 0x0800A000) to the base address of the SRAM at 0x20000000. */ for(i = 0; i < 48; i++) { VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2)); } /* Enable the SYSCFG peripheral clock*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); /* Remap SRAM at 0x00000000 */ SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);其实在官方例程中为 RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);这并没有打开系统配置时钟,应该改为RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);我也是看到网上其他帖子才发现并改正过来的,在这里感谢网友们的分享!
以上就是我做的STM32F0的IAP升级方案,实际测试感觉速度很快,可能我的App程序不大,50K左右,升级过程基本在3秒以内。
阅读全文
0 0
- STM32F072使用SD卡进行IAP升级
- SD卡升级——SDIO IAP实验
- SD卡升级——SDIO IAP实验
- 使用USART接口进行STM32F0的在线升级(AN4065)-基于标准库的STM32F070的IAP移植手记
- 使用USART接口进行STM32F0的在线升级(AN4065)-基于标准库的STM32F070的IAP移植手记
- [RK3288][Android6.0] 使用SD卡升级固件到eMMC
- 现场升级方案:LPC1788采用U盘方式进行程序IAP升级功能的实现
- 现场升级方案:LPC1778采用U盘方式进行程序IAP升级功能的实现
- 现场升级方案:采用U盘方式进行程序IAP升级功能的实现
- s3c2443Eboot支持SD卡升级
- android 制作sd升级卡
- RK2928 SD卡升级失败
- Android系统SD卡升级
- ARM IAP升级方法
- 深入谈谈IAP升级
- STM32 IAP在线升级
- IAP升级 说明
- STM32 IAP在线升级
- sudo 自动输入密码的脚本 alias别名
- 数据库学习---4
- 欢迎使用CSDN-markdown编辑器
- Android Studio apk 打包流程
- PullToRefresh+HorizontalScrollView+DrawerLayout
- STM32F072使用SD卡进行IAP升级
- 【干货分享】大数据计算服务MaxCompute使用教程
- S3C2440 gpio
- 自定义Toast
- Win10 中的文件链接
- Android中的链式调用
- ThinkPHP【系统常量与模板替换】
- 默默前行的livego--基于go语言的rtmp直播服务器
- Docker源码分析(二):Docker Client创建与命令执行