打印

SD卡升级——SDIO IAP实验

[复制链接]
5473|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hexiaolong2008|  楼主 | 2013-5-29 19:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 hexiaolong2008 于 2013-5-29 19:56 编辑

在嵌入式项目中,经常会用到SD卡升级这一方式来进行产品的软件升级。刚好最近做的项目也需要这一功能,由于之前未接触过IAP开发,刚好在这个时候可以学习一下,于是先到各大网站去搜索相关资料,两天下来,基本对于IAP的概念和编程步骤有了大致的了解。本人手里有块正点原子的开发板,前期的实验都是在这块开发板上实现的。在实现了SD卡IAP功能以后,立马将工程移植到项目中去,很快就把这个功能添加进去了,甚是高兴,对于以前的SD卡升级功能也不再那么神秘了。
    本人是先看正点原子的超级战舰手册,先看的《第三十九章 FLASH模拟EEPROM实验》,了解了STM32片内FLASH编程的步骤,然后再看的《第五十三章 串口IAP实验》,学习IAP编程的思想,最后到***电子论坛上搜索相关的资料,最终完成了SD卡IAP编程的学习,并解决了实际问题。
    学习总结:
    1.STM32片内FLASH编程步骤4步曲:解锁、擦除、编程、上锁;
    2.设置IAP程序在FLASH的起始地址,设置用户程序的起始地址为IAP后面的地址,并修改ROM空间大小;
    3.在用户程序中,设置中断向量偏移地址为用户程序的起始地址;
    4.STM32大容量存储器的页大小为2K,起初总以为是512字节;
    5.页擦除的时候,所有的页地址都是实际的字节地址,而并非常说的“第几页第几页”中的页编号;
    6.页擦除的时候,如果指定的页地址没有和页边界对齐的话,擦除操作仍然有效,只是擦除的范围是指定地址所在的整页大小;
    原子哥的IAP实验是基于串口的,由于串口的数据发送是不可调的,只能一次性将整个用户程序的BIN文件发送给bootloader,而且bootloader是将接收到的用户文件暂存在片内SRAM的,这就限值了用户程序的大小,不能大于SRAM的大小64K。而SD卡设计则不受用户程序大小限值,只要FLASH装得下就行。由于原子哥的代码很多都是寄存器版本的,而文件系统又是他自己独门的FAT32驱动,再加上他的开发板SD卡例程都基于SPI驱动的(只有一个扩展例程是SDIO的),而我的项目时间比较急,要求用最高的效率完成这项功能,于是就产生了以ST官方库函数为主导,以网上开源文件系统Fatfs作为SD卡文件系统驱动,以SDIO4位总线的DMA访问模式为SD卡驱动这样一个方案,一切都只为了开发的效率,同时,也将源代码与大家分享,相信也有很多人使用这样一种方案的。
    本工程试验平台:
    1.硬件:正点原子超级战舰开发板,由于购买时配套的3.5寸触摸屏,对于3.5以下的屏为测试过,但应该没问题,因为LCD驱动用的还是原子哥的驱动,是兼容2.4到3.5的。SanDisk 1G SD卡, MicroSD 2G。注意:要使用超级战舰开发板上的SDIO功能,必须将开发板上的P10跳线帽接到P11上,因为原子的SD卡驱动默认使用SPI接口的,所以这里必须要设置!
    2.软件:ST官方库V3.0的,比较老了。
   FatFs文件系统,注意:本人在ff.h配置中将宏_FS_READONLY配置为1,即只生成读操作的代码,不编译写操作的代码,目的是为了减小   bootloader的代码量,包括原子哥的LCD.C中的代码也删减了很多。
    下面就将主要的源代码贴出,供大家参考。

/*****************************************************************************************************
文件名  :main.c

文件描述:程序执行的主要文件,不用说也明白

创建人  :何小龙

创建时间:2012.05.16

更改历史:2012.05.29

*****************************************************************************************************/
#include "stm32f10x.h"
#include "delay.h"
#include "LED.h"
#include "diskio.h"
#include "ff.h"
#include "lcd.h"

#define FLASH_APP_ADDR                0x08010000          //第一个应用程序起始地址(存放在FLASH)
#define STM_PAGE_SIZE                2048                        //注意:STM32F103ZET6的FLASH页大小为2K



//****************************************************************************************************
//全局变量声明
FATFS Fs;
FIL file;     
BYTE buffer[STM_PAGE_SIZE];
FRESULT res;        
UINT br;        

typedef  void (*fun)(void);                                //定义一个函数类型的参数.   
fun AppStart;

/*****************************************************************************************************
函数名  :Jump2App

功    能:从Bootloader跳转到用户APP程序地址空间

入口参数:Addr,用户APP的起始执行地址

出口参数:无

返回值  :无
*****************************************************************************************************/
void Jump2App(u32 Addr)
{
        if(((*(vu32*)Addr)&0x2FFE0000) == 0x20000000)        //检查栈顶地址是否合法.
        {
                AppStart = (fun)(*(vu32*)(Addr+4));                        //用户代码区第二个字为程序开始地址(复位地址)               
                AppStart();                                                                        //跳转到APP.
        }
}                 


/*****************************************************************************************************
函数名  :FirmwareUpdate

功    能:固件升级函数

入口参数:无

出口参数:无

返回值  :无
*****************************************************************************************************/
void FirmwareUpdate(void)
{
int PageOffest = 0;                //页偏移,从APP的基地址到当前页起始位置的字节总数
int ByteOffest;                        //当前页内的字节偏移,从当前操作页的起始位置到正在写入位置的字节偏移
int a, b;
u8 i = 0;

        /*首先初始化SD卡*/
        if(0 != disk_initialize(0))        return;

        /*接着挂载文件系统对象*/
        f_mount(0, &Fs);

        /*查找是否存在要升级的BIN文件*/
        res = f_open(&file, "RTC.bin", FA_OPEN_EXISTING | FA_READ);
        if(FR_OK != res) return;

        /*绘制进度条边框*/
        LCD_DrawRectangle(50, 225, 250, 255);

        /*初始化临时变量*/
        a = file.fsize / 100;  //100表示将进度条平均分成100份,由于进度条长度为200个像素,所以1份占用2个像素
        a &= 0xfffffffe;           //将文件平均分成100份,所以a表示一份文件所占的字节数,为确保该字节数为偶数,故做此转换
        b = 0;                                   //b表示当前已经更新了多少字节

        /*执行主要的IAP功能*/
        while(1)
        {
                /*每次读取一个页的数据到内存缓冲区,注意:STM32F103ZE的页大小为2K*/
            res = f_read(&file, buffer, STM_PAGE_SIZE, &br);
            if (res || br == 0) break;   

                /*然后就是永恒的4步骤:解锁、擦除、更新、上锁*/
                FLASH_Unlock();
                FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
                FLASH_ErasePage(FLASH_APP_ADDR + PageOffest);
                for(ByteOffest = 0; ByteOffest < STM_PAGE_SIZE; ByteOffest += 2)
                {
                        /*更新FLASH,注意当前操作的实际位置:APP基地址FLASH_APP_ADDR+页偏移字节PageOffest+当前页内的字节偏移ByteOffest*/
                        FLASH_ProgramHalfWord(FLASH_APP_ADDR + PageOffest + ByteOffest, *(u16*)(buffer + ByteOffest));
                        
                        b += 2;

                        /*更新显示进度条,(b % a == 0)的目的是确保当前正好写完1份文件*/
                        if(b % a == 0)
                        {
                                LCD_Fill(50, 225, 50 + 2 * (b / a), 255, 0x7e0); //(b / a)表示已经写了几份文件
                        }
                }
                FLASH_Lock();
                PageOffest += STM_PAGE_SIZE;

                /*每更新完1页,让LED状态翻转一次*/
                i = !i;
                if(i)
                        GPIO_SetBits(GPIOB, GPIO_Pin_5);
                else
                        GPIO_ResetBits(GPIOB, GPIO_Pin_5);
        }

        /*关闭文件,卸载文件系统*/
        f_close(&file);
        f_mount(0, 0);
}


/*****************************************************************************************************
函数名  :main

功    能:主程序入口函数

入口参数:无

出口参数:无

返回值  :int
*****************************************************************************************************/
int main(void)
{
        SystemInit();
        delay_init(72);
        LED_Init();
        LCD_Init();
        FirmwareUpdate();
        Jump2App(FLASH_APP_ADDR);
        while(1);
}


工程源码下载: SDIO_IAP.zip (833.88 KB)
    还要注意的地方:用户程序是放在FLASH地址0x08010000的位置的,而且该代码只识别SD卡根目录下的RTC.bin文件,如果要更改文件名,则只需将FirmwareUpdate函数中的“RTC.bin”文件改成你要升级的文件即可。
    以下是运行效果图:
   
   
希望对你能有所帮助。










沙发
jsll86| | 2013-5-29 22:54 | 只看该作者
正想学这块呢,好东西呀

使用特权

评论回复
板凳
wuguoyan| | 2013-5-29 23:41 | 只看该作者
顶起

使用特权

评论回复
地板
wwchang| | 2013-5-30 08:21 | 只看该作者
好东西,学习了。

使用特权

评论回复
5
yuchl| | 2013-5-30 11:35 | 只看该作者
不错的好东西!

使用特权

评论回复
6
tk1974| | 2013-6-21 09:05 | 只看该作者
好,厉害。拜读了

使用特权

评论回复
7
wuguoyan| | 2013-6-21 11:35 | 只看该作者
好东西呀

使用特权

评论回复
8
liuje| | 2013-6-21 16:30 | 只看该作者
正是好物啊.     产品就该这么设计,  如同手机一样能方便的让用户自行更新固件.    这个好 !!!!   全力支持!

代码感谢了!

使用特权

评论回复
9
mugenwon| | 2013-6-26 19:01 | 只看该作者
我正要弄类似的东西。只测试了一下你的void Jump2App(u32 Addr)函数。
我打算跳到0x08001004,他却跑到0x08001024去了,这是什么原因?

使用特权

评论回复
10
hsbjb| | 2013-6-26 19:35 | 只看该作者
很有参考价值,鼓励共享

使用特权

评论回复
11
cjhk| | 2013-6-26 20:33 | 只看该作者
不错哦   学习学习   不错   有时间需要好好看看  

使用特权

评论回复
12
触觉的爱| | 2013-6-27 10:25 | 只看该作者
这个方便,有没有人能弄个STM8S的版本

使用特权

评论回复
13
不爱说话| | 2013-6-27 13:01 | 只看该作者
很好的想法,支持。

使用特权

评论回复
14
jomosiron| | 2013-6-27 13:25 | 只看该作者
不错了 多谢楼主

使用特权

评论回复
15
lin34337151| | 2013-7-5 17:13 | 只看该作者
哇!太给力了,项目正用到这个,楼主万岁啊,太伟大了!好东西啊。本人QQ 1732158020 希望路过的朋友也正在做这个东西加一起学习一下,周末了,祝楼主及路过的朋友,周末愉快。本人周末回家要把这个东西搞定,下周来分享。希望能搞定。现在SD卡部分都正常。就等楼主这个了。

使用特权

评论回复
16
lin34337151| | 2013-7-6 12:13 | 只看该作者
楼主,

使用特权

评论回复
17
lin34337151| | 2013-7-6 12:17 | 只看该作者
楼主,你好,能不能帮我指导一下,我用的是STM32R8T6  64K 的
我在你的程序上做了这样的修改,其他的都没变,不成功。
#define FLASH_APP_ADDR                0x08006000  
#define STM_PAGE_SIZE                1024
出现的现象是,读SD后程序就死掉了,不读SD卡程序正常,我SD卡里面的文件是“aa.hex”文件大小只有17K  
能指点一下,还有什么地方要修改吗       

使用特权

评论回复
18
lin34337151| | 2013-7-6 13:43 | 只看该作者
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP
大家好,我看了一下,我的程序一直停在这个地方,用楼主的代码试也是停止在这个地方

使用特权

评论回复
19
onepiece120116| | 2013-7-13 11:15 | 只看该作者
谢谢楼主!

使用特权

评论回复
20
hexiaolong2008|  楼主 | 2013-7-17 22:25 | 只看该作者
lin34337151 发表于 2013-7-6 12:17
楼主,你好,能不能帮我指导一下,我用的是STM32R8T6  64K 的
我在你的程序上做了这样的修改,其他的都没变 ...

你确定你的FLASH页大小是1024 bytes?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

8

帖子

0

粉丝