野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 17818|回复: 7

指南者开发板使用SD卡更新内部FLASH程序

[复制链接]

发表于 2020-7-13 14:15:25 | 显示全部楼层 |阅读模式
使用外部的SD卡更新内部FLASH程序

IAP程序实现的思路如下:

1.复位之后检查一下连接按键的引脚电平,如果被按下说明要更新Flash里面的程序

2.挂载文件系统,并从指定的目录下面打开代码文件

3.检查文件大小,如果文件大小大于Flash剩余的容量,程序就无法写入,那么就直接跳转到APP程序去执行

3.计算要擦除的扇区大小,并擦除扇区

4.向指定的地址写入代码

5.程序写入完毕就跳转到新地址去执行代码。

具体代码的实现如下:

  1. int InternalFlash_Test(void)
  2. {         
  3.         uint16_t i,j;
  4.         uint32_t EraseCounter = 0x00;                     //记录要擦除多少页        
  5.         uint32_t NbrOfPage = 0x00;                                //记录写入多少页                                            
  6.         uint32_t Address = WRITE_START_ADDR;                //记录写入的地址
  7.         FLASH_Status FLASHStatus = FLASH_COMPLETE;  //记录每次擦除的结果        
  8.         if(Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_OFF)  //不更新程序
  9.         {        
  10.       iap_load_app(WRITE_START_ADDR);
  11.           return FAILED;
  12.         }
  13.         printf("开始挂载文件系统\r\n");        
  14.         res_sd = f_mount(&fs,"0:",1);
  15.         if(res_sd != FR_OK)
  16.         {
  17.           printf("挂载文件系统失败\r\n");        
  18.       iap_load_app(WRITE_START_ADDR);
  19.           return FAILED;
  20.         }
  21.         printf("正在打开程序文件,路径为:0:bin/Code.bin\r\n");               
  22.     res_sd = f_open(&fnew, "0:bin/Code.bin", FA_OPEN_EXISTING | FA_READ);         
  23.         if(res_sd != FR_OK)
  24.         {
  25.           printf("打开文件失败\r\n");        
  26.       iap_load_app(WRITE_START_ADDR);
  27.           return FAILED;
  28.         }
  29.         printf("文件大小为:%dByte\r\n",(uint32_t)fnew.fsize);        
  30.         if(fnew.fsize > WRITE_END_ADDR - WRITE_START_ADDR)
  31.         {
  32.           printf("FLASH容量不足,无法写入\r\n");        
  33.       iap_load_app(WRITE_START_ADDR);
  34.           return FAILED;
  35.         }                                 
  36.     NbrOfPage = fnew.fsize / FLASH_PAGE_SIZE;     /* 计算要擦除多少页 */
  37.     if((fnew.fsize % FLASH_PAGE_SIZE) != 0)
  38.         {
  39.                 NbrOfPage++;                             //还有不足2048个字节的数据,就加一
  40.         }
  41.     FLASH_Unlock();                               /* 解锁 */  
  42.         printf("开始擦除扇区,扇区地址为:%#X\r\n",Address);               
  43.     FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);         /* 清空所有标志位 */
  44.     for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)   /* 按页擦除*/
  45.     {
  46.           FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
  47.   
  48.         }
  49.         printf("扇区擦除完毕\r\n");               
  50.         printf("开始写入程序......\r\n");               
  51.     for(i = 0;i < NbrOfPage;i++)
  52.         {
  53.                 res_sd = f_read(&fnew, ReadBuffer,READ_BUFFER_SIZE, &fnum);
  54.                 if(res_sd != FR_OK) return FAILED;               
  55.                 for(j = 0;(j < fnum/4) && (FLASHStatus == FLASH_COMPLETE);j++)
  56.                 {
  57.                         FLASHStatus = FLASH_ProgramWord(Address, ReadBuffer[j]);
  58.                         Address+=4;               
  59.                 }
  60.         }
  61.         printf("程序写入完成,正在跳转到新程序\r\n");        
  62.     FLASH_Lock();
  63.         f_close(&fnew);
  64.         f_mount(NULL,"0:",1);
  65.     iap_load_app(WRITE_START_ADDR);
  66.         return FAILED;
  67. }
复制代码
程序写入完毕之后还要跳转到指定的地址去执行程序,代码如下:

  1. typedef  void (*iapfun)(void);                        //定义一个函数类型的参数.
  2. iapfun jump2app;

复制代码
  1. //跳转到应用程序段
  2. //appxaddr:用户代码起始地址.
  3. static void iap_load_app(uint32_t appxaddr)
  4. {
  5.         if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)        //检查栈顶地址是否合法.
  6.         {      
  7.         delay();                                            //此处加延时,可以防止串口发送数据乱码
  8.                 jump2app=(iapfun)*(vu32*)(appxaddr+4);                //用户代码区第二个字为程序开始地址(复位地址)               
  9.                 __set_MSP(*(vu32*)appxaddr);                                //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
  10.                 jump2app();                                                                        //跳转到APP.
  11.         }
  12. }       
复制代码

关于栈顶指针和程序开始地址的说明可以参考“1-STM32F10x-中文参考手册.pdf”第33页。

截图.jpg

APP程序实现的过程如下:
1.首先设置程序的开始地址,就是IAP程序的开始写入地址,然后设置Flash的大小,即为FLASH总容量 - IAP程序占用的容量
截图2.jpg
2.设置中断向量表的偏移,将中断向量表的地址偏移到写入程序的地址,有关这部分可以参考配套资料的“CM3权威指南CnR2.pdf”
截图3.jpg
3.生成bin文件,有关这部分可参考“【野火®】零死角玩转STM32—F103指南者.pdf”,第46章  MDK的编译过程及文件类型全解
具体步骤如下:
截图4.jpg 勾选这个复选框,在后面加上这句话:
fromelf --bin --output ../../output/Code.bin ../../output/流水灯.axf
其中 ../../output/Code.bin是生成bin文件的路径和名称,../../output/流水灯.axf,这个是编译生成的axf文件的路径和名称,如果生成的时候有错误,请根据自己工程的实际情况做修改。
4.在SD卡新建文件夹命名为bin,并将生成的bin文件此文件夹中
截图7.jpg
程序最后的运行结果如下:

截图5.jpg
APP程序使用的是指南者开发板的开机例程,经过测试使用SD卡更新的程序运行一切正常

截图6.jpg
最后附上源代码:
SD卡更新Flash程序例程.rar (843.63 KB, 下载次数: 34)
40.UCOSIII_emWin_DEMO.rar (2.82 MB, 下载次数: 17)
回复

使用道具 举报

发表于 2020-7-14 10:46:31 | 显示全部楼层
这个也是一直想要有的功能
回复 支持 反对

使用道具 举报

发表于 2020-7-15 08:52:02 | 显示全部楼层
你好, delay();  //此处加延时,可以防止串口发送数据乱码 。开始打印串口为什么会发出一些乱码,什么原因知道吗??
回复 支持 反对

使用道具 举报

发表于 2020-7-15 09:11:16 | 显示全部楼层
总是在最后一条打印语句后输出一排\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-7-15 09:12:06 | 显示全部楼层
zhanming1990 发表于 2020-7-15 08:52
你好, delay();  //此处加延时,可以防止串口发送数据乱码 。开始打印串口为什么会发出一些乱码,什么原因 ...

现在还有吗?我在这里加了这句不会有乱码的
回复 支持 反对

使用道具 举报

发表于 2020-7-15 14:37:09 | 显示全部楼层
猜测:由于复位的时候,电平不稳定导致串口解析数据的时候容易出错。
回复 支持 反对

使用道具 举报

发表于 2020-7-16 11:17:57 | 显示全部楼层
Yuhailong 发表于 2020-7-15 09:12
现在还有吗?我在这里加了这句不会有乱码的

我的是跳转到APP后,串口输出这些。
你有试过野火的SPI接口的SD卡做IAP吗?

感觉这个函数SD_ReadMultiBlocks(uint8_t* pBuffer, uint64_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)读2个BLOCK大小就有问题,里面只是简单的封装了读单块block的函数。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-7-17 14:55:22 | 显示全部楼层
zhanming1990 发表于 2020-7-16 11:17
我的是跳转到APP后,串口输出这些。
你有试过野火的SPI接口的SD卡做IAP吗?

没有试过
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-4-28 22:43 , Processed in 0.045423 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表