#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,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);
}