Flash Driver Module--jianqiang.xue
- 一、 简介
- 二、 措施
- 方式一:将FLASH操作程序作为Bootloader组件的一部分固化在存储器中
- 方式二:通过通讯口将该部分代码从上位机下载到指定的RAM
- 方式三:将Flash功能函数作为数据运行(推荐!!!)
- 使用Demo
一、 简介
在汽车ECU软件运行中,软件代码运行安全性是第一,在代码中尽可能的不要固化有flash_erase、flash_write操作存在,主要是防止当出现异常情况时,程序跑飞,误调用erase、write对flash操作,使得原软件受到破坏,以致ECU不能正常工作。
Flash访问代码(Access Code)不能存储在被操作的Flash物理块中,例如我要擦除一个Flash中某一个扇区内容,这个擦除动作的代码不能存在这个Flash物理块中(Flash中代码运行时,相当于读操作,此时不能擦写)
PFlash的访问代码在Fls_17_Dmu_ac.c文件中,而该文件的代码又被烧写进PFlash中,所以,PFlash不能直接进行Write/Erase操作
解决方案就是PFlash进行Write/Erase操作前,将Write/Erase访问代码存储到RAM中,函数实际上是在RAM中执行
在AUTOSAR的负责范围内,DF0_EEPROM不会存放任何访问代码。
二、 措施
方式一:将FLASH操作程序作为Bootloader组件的一部分固化在存储器中
为了实现在线更新功能,Bootloader程序需要对flash进行操作。一般情况下,我们将FLASH操作程序作为Bootloader组件的一部分固化在存储器中,在需要执行flash擦除或烧写操作时,先将该部分代码复制到RAM中,再做调用。操作代码的复制工作也可以在Bootloader启动阶段完成。
方式二:通过通讯口将该部分代码从上位机下载到指定的RAM
两级Bootloader方案,没有在flash存储器中固化flash擦写代码,而是通过通讯口将该部分代码从上位机下载到指定的RAM出,在需要指出flash擦除或烧写操作时,再调用RAM中的该代码。
jianqiang.xue
方式三:将Flash功能函数作为数据运行(推荐!!!)
- 根据MCU新建Flash Driver工程
- 编写flash_erase和flash_write两个函数
- 编译生成bin文件,通过.map文件查看这两个函数的位置
- 在生成的bin文件中提取出这两个函数信息,注意地址是偶数。
func_addr = (map_addr-1)
func_size = (map_size+4)
const uint8_t McuFlashErasePageBuf[] = {
0xB0, 0xB5, 0x11, 0x4A, 0x30, 0x21, 0x11, 0x70, 0x14, 0x1F, 0x00, 0x23, 0x23, 0x70, 0x0A, 0x25,
0x15, 0x71, 0x05, 0x0C, 0xD5, 0x70, 0x01, 0x25, 0x25, 0x70, 0xFC, 0x24, 0x04, 0x40, 0xD4, 0x70,
0x00, 0x0A, 0x10, 0x71, 0x85, 0xF3, 0x10, 0x88, 0x80, 0x20, 0x10, 0x70, 0x10, 0x78, 0x40, 0xB2,
0x00, 0x28, 0xFB, 0xD5, 0x10, 0x78, 0x00, 0x07, 0xFC, 0xD4, 0x12, 0x78, 0x83, 0xF3, 0x10, 0x88,
0x0A, 0x40, 0x50, 0x42, 0x50, 0x41, 0xB0, 0xBD, 0x05, 0x00, 0x02, 0x40, 0x10, 0xB5, 0x8C, 0xB0,
};
const uint8_t McuFlashWritePageBuf[] = {
0xF8, 0xB5, 0x14, 0x46, 0x04, 0x43, 0x01, 0x23, 0xA4, 0x07, 0x4D, 0xD1, 0x00, 0x29, 0x4B, 0xD0,
0x00, 0x2A, 0x49, 0xD0, 0x00, 0x23, 0x25, 0x4C, 0x00, 0x93, 0x30, 0x26, 0x26, 0x71, 0x00, 0x9D,
0x25, 0x70, 0x06, 0x25, 0x25, 0x72, 0x05, 0x0C, 0xE5, 0x71, 0x01, 0x27, 0x27, 0x70, 0x05, 0x0A,
0x25, 0x72, 0xFC, 0x25, 0x05, 0x40, 0xE5, 0x71, 0x02, 0x25, 0x25, 0x70, 0x4D, 0x78, 0x25, 0x72,
0x0D, 0x78, 0xE5, 0x71, 0x03, 0x25, 0x25, 0x70, 0xCD, 0x78, 0x25, 0x72, 0x8D, 0x78, 0xE5, 0x71,
0x1D, 0x1D, 0x95, 0x42, 0x0F, 0xD2, 0x04, 0x25, 0x25, 0x70, 0x4D, 0x79, 0x25, 0x72, 0x0D, 0x79,
0xE5, 0x71, 0x05, 0x25, 0x25, 0x70, 0xCD, 0x79, 0x25, 0x72, 0x8D, 0x79, 0xE5, 0x71, 0x08, 0x30,
0x08, 0x33, 0x08, 0x31, 0x02, 0xE0, 0x00, 0x1D, 0x09, 0x1D, 0x2B, 0x46, 0x87, 0xF3, 0x10, 0x88,
0x80, 0x25, 0x25, 0x71, 0x04, 0x25, 0x65, 0x57, 0x00, 0x2D, 0xFB, 0xD5, 0x25, 0x79, 0x2D, 0x07,
0xFC, 0xD4, 0x27, 0x79, 0x00, 0x25, 0x85, 0xF3, 0x10, 0x88, 0x37, 0x40, 0x93, 0x42, 0x01, 0xD2,
0x00, 0x2F, 0xBA, 0xD0, 0x7B, 0x42, 0x7B, 0x41, 0x18, 0x46, 0xF8, 0xBD, 0x01, 0x00, 0x02, 0x40,
};
- 提取数据并存放数组,这些数据不能直接使用,因为无法到达AUTOSAR初衷。
处理数据:
(1) 数组数据全部取反,这样程序炮灰也不会误触发。
(2) 使用flash_erase和flash_write时,需要取反数据,再使用,使用结束后,再清除数据。
// 这里的数据全部取反才是真正函数,防止指针跑飞误执行。
#pragma pack (4)
const uint8_t gc_McuFlashErasePageBuf[] = {
0x73, 0x4f, 0xfe, 0x57, 0x00, 0x08, 0xa6, 0x00, 0xfb, 0x67,
0xf3, 0xb6, 0x77, 0xbd, 0xee, 0x2c, 0xea, 0xb3, 0xfd, 0xde,
0x9e, 0xa9, 0xff, 0xd6, 0x04, 0x2a, 0xf7, 0xb6, 0x00, 0x08,
0xe4, 0x00, 0xbe, 0xe1, 0xc0, 0xdf, 0xf7, 0xbf, 0xdf, 0x8f,
0xde, 0x87, 0xb6, 0x4d, 0xff, 0xd6, 0x05, 0x2a, 0xf3, 0x4f,
0xef, 0x42, 0xfc, 0x5f, 0xf7, 0x5e, 0xd6, 0xdd, 0xff, 0x0f,
0x41, 0x07, 0xbf, 0xbd, 0xf0, 0xff, 0x9c, 0x93, 0x94, 0xd1,
0x99, 0x8d, 0x8e, 0xa0, 0x9d, 0x8a, 0x8c, 0xdf, 0xc1, 0x4f
};
const uint8_t gc_McuFlashWritePageBuf[] = {
0x07, 0x4a, 0xeb, 0xb9, 0xfb, 0xbc, 0xfe, 0xdc, 0x5b, 0xf8,
0xb2, 0x2e, 0xff, 0xd6, 0xb4, 0x2f, 0xff, 0xd5, 0xb6, 0x2f,
0xff, 0xdc, 0xda, 0xb3, 0xff, 0x6c, 0xcf, 0xd9, 0xd9, 0x8e,
0xff, 0x62, 0xda, 0x8f, 0xf9, 0xda, 0xda, 0x8d, 0xfa, 0xf3,
0x1a, 0x8e, 0xfe, 0xd8, 0xd8, 0x8f, 0xfa, 0xf5, 0xda, 0x8d,
0x03, 0xda, 0xfa, 0xbf, 0x1a, 0x8e, 0xfd, 0xda, 0xda, 0x8f,
0xb2, 0x87, 0xda, 0x8d, 0xf2, 0x87, 0x1a, 0x8e, 0xfc, 0xda,
0xda, 0x8f, 0x32, 0x87, 0xda, 0x8d, 0x72, 0x87, 0x1a, 0x8e,
0xe2, 0xe2, 0x6a, 0xbd, 0xf0, 0x2d, 0xfb, 0xda, 0xda, 0x8f,
0xb2, 0x86, 0xda, 0x8d, 0xf2, 0x86, 0x1a, 0x8e, 0xfa, 0xda,
0xda, 0x8f, 0x32, 0x86, 0xda, 0x8d, 0x72, 0x86, 0x1a, 0x8e,
0xf7, 0xcf, 0xf7, 0xcc, 0xf7, 0xce, 0xfd, 0x1f, 0xff, 0xe2,
0xf6, 0xe2, 0xd4, 0xb9, 0x78, 0x0c, 0xef, 0x77, 0x7f, 0xda,
0xda, 0x8e, 0xfb, 0xda, 0x9a, 0xa8, 0xff, 0xd2, 0x04, 0x2a,
0xda, 0x86, 0xd2, 0xf8, 0x03, 0x2b, 0xd8, 0x86, 0xff, 0xda,
0x7a, 0x0c, 0xef, 0x77, 0xc8, 0xbf, 0x6c, 0xbd, 0xfe, 0x2d,
0xff, 0xd0, 0x45, 0x2f, 0x84, 0xbd, 0x84, 0xbe, 0xe7, 0xb9,
0x07, 0x42, 0xfe, 0xff, 0xfd, 0xbf
};
uint8_t McuFlashErasePageBuf[80] = {0};
uint8_t McuFlashWritePageBuf[176] = {0};
#pragma pack ()
/****************************变量定义******************************/
typedef uint8_t (*McuFlashWritePageHandler)(uint32_t addr, uint8_t* buff, uint32_t len);
typedef uint8_t (*McuFlashErasePageHandler)(uint32_t addr);
/****************************常量定义******************************/
/****************************函数原型******************************/
static void Retrieval(uint8_t *s_buf, uint8_t *l_buf, uint32_t size) {
for(uint32_t i = 0; i < size; i++) {
l_buf[i] = ~s_buf[i];
}
}
void McuFlashInstall(void) {
// 装载FlashDriver驱动函数
Retrieval((uint8_t *)gc_McuFlashErasePageBuf, McuFlashErasePageBuf, 80);
Retrieval((uint8_t *)gc_McuFlashWritePageBuf, McuFlashWritePageBuf, 176);
}
void McuFlashUnInstall(void) {
// 卸载FlashDriver驱动函数
memset(McuFlashErasePageBuf, 0, 80);
memset(McuFlashWritePageBuf, 0, 176);
}
/******************************************************************
* 函数名称:McuFlashWritePage
* 入口参数:addr 写地址;buff 数据缓存;len 数据长度
* 出口参数:0 指令操作失败,1 指令操作成功
* 函数说明:向指定地址写入一定长度的数据
* 地址必须4字节对齐且在有效操作范围内;buff本身不能低于len
* 设置的长度;len必须为4的整数倍;写入的空间必须已经擦除
******************************************************************/
McuFlashWritePageHandler McuFlashWritePage = (McuFlashWritePageHandler)(McuFlashWritePageBuf + 1);
/******************************************************************
* 函数名称:McuFlashErasePage
* 入口参数:addr 页所在地址
* 出口参数:0 指令操作失败,1 指令操作成功
* 函数说明:擦除页所在地址的一页内容
******************************************************************/
McuFlashErasePageHandler McuFlashErasePage = (McuFlashErasePageHandler)(McuFlashErasePageBuf + 1);
/******************************变量声明*****************************/
typedef uint8_t (*McuFlashWritePageHandler)(uint32_t addr, uint8_t* buff, uint32_t len);
typedef uint8_t (*McuFlashErasePageHandler)(uint32_t addr);
// 未安装flash驱动,调用下面函数会直接跑飞
extern McuFlashWritePageHandler McuFlashWritePage;
extern McuFlashErasePageHandler McuFlashErasePage;
LiSun–xuejianqiang
使用Demo
// 写入
McuFlashInstall();
McuFlashWritePage(LS_ADDR, data, len);
McuFlashUnInstall();
// 擦除
McuFlashInstall();
McuFlashErasePage(LS_ADDR);
McuFlashUnInstall();