目录
前言
FlashDriver意为flash驱动代码块,出于某些原因,本地不允许保存修改flash的代码,因此需要更新时,将通过外部接口,传输flash驱动,即用即毁。以STM32F103为例,FlashDriver的应用流程如下:
1.驱动源码编写
在过程中实现并测试flash驱动,需要注意的是,flashdriver作为独立执行的映像,不允许有外部依耐(即调用其他模块的接口),知名系统库除外(但最好自己实现,如memcpy)。
void waitFlash(void)
{
}
void flash_erase(uint32_t addr, uint32_t cnt)
{
}
uint8_t flash_read(uint32_t addr, uint8_t *buffer, uint32_t len)
{
}
void flash_cpy(uint8_t *des, uint8_t *src, uint32_t len)
{
}
void flash_write(uint32_t addr, uint8_t *buffer, uint32_t len)
{
}
const FlashApi_t fp __attribute__((section("flbase"),used)) =
{
.read = flash_read,
.write = flash_write,
.erase = flash_erase,
};
2.代码重定向
既然是打着主意将FlashDriver放到RAM中执行,我们可以自定义sct文件,将flashDriver相关驱动,重定向到RAM中(可能涉及到寻址,这一块我也不太清楚)。
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00020000 { ; load region size_region
ER_IROM1 0x08000000 0x00020000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x00004000 { ; RW data
.ANY (+RW +ZI)
}
RW_IRAM2 0x20004000 0x00001000 { ; RW data
* (flbase, +First) ;确保header信息在最前面
flashDriver.o (+RO +XO +RW +ZI) ;将 flashDriver所有数据放到RW_IRAM2
;.ANY (FLASH)
}
}
我们可以看到,flashDriver.c所有的所有函数的执行域都在RW_IRAM2中,且header信息位于RW_IRAM2的起始位置。
3.获取映像文件
这里提供两种方法
1)查看map文件,确定flashdriver的执行地址和映像大小,在Keil command中,输入指令获取hex文件:
SAVE <文件名.hex> <起始地址>, <结束地址>
SAVE flash.hex 0x20004000, 0x200041a0
接着使用Jflash工具将hex转为bin。
2)查看map文件,可以确定flashDriver的加载地址和映像大小,直接将整个工程的hex导入JFlash,将指定范围的数据导出为bin。
对比两种方法生成的文件,不能说有点相似,只能说一模一样,啊,不对,这个少一个字节了么?哦,不好意思,区间一般是左闭右开,第二种方法,有可能少一个。
4.使用映像文件
在没有flash的工程中,使用外部接口,将flashdriver的映像文件传输到指定的RAM区域(为什么不是任意RAM区域:和寻址有关。如果驱动代码实现了位置独立,也不是不可以),通过header信息可直接定位各接口位置。
uint8_t flashBin[512] __attribute__((section(".FLASH"))) = {0};
FlashApi_t *api = NULL;
void flashInit(void)
{
memcpy(flashBin, bin_Start, (bin_End- bin_Start)<<2);
api = (FlashApi_t*)flashBin;
}
#ifdef FLASH_TEST
flashInit();
#endif
{
uint8_t tm[8] ={1,2,3,4,5,6,7,8};
uint8_t tn[48] ={0};
api->write(0x08010000, tm ,8);
tm[0]++;
api->write(0x08010000+16, tm ,8);
tm[0]++;
api->write(0x08010000+32, tm ,8);
tm[0]++;
api->read(0x08010000+32, tn ,8);
api->erase(0x08010000, 1);
}
结语
这里偷了个懒,直接用汇编的语法将bin文件写入flash,然后手动拷贝到指定RAM区,模拟外部传输,测试通过~