使用外部的SD卡更新内部FLASH程序
IAP程序实现的思路如下:
1.复位之后检查一下连接按键的引脚电平,如果被按下说明要更新Flash里面的程序
2.挂载文件系统,并从指定的目录下面打开代码文件
3.检查文件大小,如果文件大小大于Flash剩余的容量,程序就无法写入,那么就直接跳转到APP程序去执行
3.计算要擦除的扇区大小,并擦除扇区
4.向指定的地址写入代码
5.程序写入完毕就跳转到新地址去执行代码。
具体代码的实现如下:
- int InternalFlash_Test(void)
- {
- uint16_t i,j;
- uint32_t EraseCounter = 0x00; //记录要擦除多少页
- uint32_t NbrOfPage = 0x00; //记录写入多少页
- uint32_t Address = WRITE_START_ADDR; //记录写入的地址
- FLASH_Status FLASHStatus = FLASH_COMPLETE; //记录每次擦除的结果
- if(Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_OFF) //不更新程序
- {
- iap_load_app(WRITE_START_ADDR);
- return FAILED;
- }
- printf("开始挂载文件系统\r\n");
- res_sd = f_mount(&fs,"0:",1);
- if(res_sd != FR_OK)
- {
- printf("挂载文件系统失败\r\n");
- iap_load_app(WRITE_START_ADDR);
- return FAILED;
- }
- printf("正在打开程序文件,路径为:0:bin/Code.bin\r\n");
- res_sd = f_open(&fnew, "0:bin/Code.bin", FA_OPEN_EXISTING | FA_READ);
- if(res_sd != FR_OK)
- {
- printf("打开文件失败\r\n");
- iap_load_app(WRITE_START_ADDR);
- return FAILED;
- }
- printf("文件大小为:%dByte\r\n",(uint32_t)fnew.fsize);
- if(fnew.fsize > WRITE_END_ADDR - WRITE_START_ADDR)
- {
- printf("FLASH容量不足,无法写入\r\n");
- iap_load_app(WRITE_START_ADDR);
- return FAILED;
- }
- NbrOfPage = fnew.fsize / FLASH_PAGE_SIZE; /* 计算要擦除多少页 */
- if((fnew.fsize % FLASH_PAGE_SIZE) != 0)
- {
- NbrOfPage++; //还有不足2048个字节的数据,就加一
- }
- FLASH_Unlock(); /* 解锁 */
- printf("开始擦除扇区,扇区地址为:%#X\r\n",Address);
- FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); /* 清空所有标志位 */
- for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++) /* 按页擦除*/
- {
- FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
-
- }
- printf("扇区擦除完毕\r\n");
- printf("开始写入程序......\r\n");
- for(i = 0;i < NbrOfPage;i++)
- {
- res_sd = f_read(&fnew, ReadBuffer,READ_BUFFER_SIZE, &fnum);
- if(res_sd != FR_OK) return FAILED;
- for(j = 0;(j < fnum/4) && (FLASHStatus == FLASH_COMPLETE);j++)
- {
- FLASHStatus = FLASH_ProgramWord(Address, ReadBuffer[j]);
- Address+=4;
- }
- }
- printf("程序写入完成,正在跳转到新程序\r\n");
- FLASH_Lock();
- f_close(&fnew);
- f_mount(NULL,"0:",1);
- iap_load_app(WRITE_START_ADDR);
- return FAILED;
- }
复制代码 程序写入完毕之后还要跳转到指定的地址去执行程序,代码如下:
- typedef void (*iapfun)(void); //定义一个函数类型的参数.
- iapfun jump2app;
复制代码- //跳转到应用程序段
- //appxaddr:用户代码起始地址.
- static void iap_load_app(uint32_t appxaddr)
- {
- if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法.
- {
- delay(); //此处加延时,可以防止串口发送数据乱码
- jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址)
- __set_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
- jump2app(); //跳转到APP.
- }
- }
复制代码
关于栈顶指针和程序开始地址的说明可以参考“1-STM32F10x-中文参考手册.pdf”第33页。
APP程序实现的过程如下: 1.首先设置程序的开始地址,就是IAP程序的开始写入地址,然后设置Flash的大小,即为FLASH总容量 - IAP程序占用的容量 2.设置中断向量表的偏移,将中断向量表的地址偏移到写入程序的地址,有关这部分可以参考配套资料的“CM3权威指南CnR2.pdf” 3.生成bin文件,有关这部分可参考“【野火®】零死角玩转STM32—F103指南者.pdf”,第46章 MDK的编译过程及文件类型全解 具体步骤如下:
勾选这个复选框,在后面加上这句话:
fromelf --bin --output ../../output/Code.bin ../../output/流水灯.axf
其中 ../../output/Code.bin是生成bin文件的路径和名称,../../output/流水灯.axf,这个是编译生成的axf文件的路径和名称,如果生成的时候有错误,请根据自己工程的实际情况做修改。
4.在SD卡新建文件夹命名为bin,并将生成的bin文件此文件夹中
程序最后的运行结果如下:
APP程序使用的是指南者开发板的开机例程,经过测试使用SD卡更新的程序运行一切正常
最后附上源代码:
SD卡更新Flash程序例程.rar
(843.63 KB, 下载次数: 38)
40.UCOSIII_emWin_DEMO.rar
(2.82 MB, 下载次数: 21)
|