前言
在汽车行业控制器软件刷新流程中,一般会将Flash驱动单独进行刷写,目的是防止程序中一直存在Flash驱动的话,可能会造成对APP软件的异常操作,导致应用程序无法执行。
本文介绍STM32F103使用KEIL生成指定FlashDriver地址的hex文件,然后使用HexView命令行提取FlashDriver及Remapping flash地址到ram地址
本文参考github,SummerFalls大神的UDS_S32K144_FlashDriver
芯片内存定义
STM32F103RCT6,flash大小256k,一个扇区2k,SRAM:48KB;
实现过程
FlashDriver生成
段定义
由于我无法直接在Keil中导出指定ram地址的hex文件,所以采用先定义指定flash地址的flash驱动,后面通过hexview实现地址重映射
keil中的内存区域定义通过分散加载文件(.sct格式)实现,如下所示
; *************************************************************
; *** 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 0x20000800 0x0000C000 { ; RW data
.ANY (+RW +ZI)
}
}
LR_IROM2 0x08020000 0x00020000 {
RW_IROM_flashdrvoffset 0x08020000 0x00000008{; load address = execution address
*(.NVM_Driver_Section_offset)
}
RW_IROM_flashdrv 0x08020008 0x000007F8{; load address = execution address
*(.NVM_Driver_Section)
}
}
此处设置了两个段,NVM_Driver_Section_offset用来设置函数偏移地址,NVM_Driver_Section用来设置函数地址
增加段的宏定义
#define NVM_DRIVER_SECTION __attribute__((section (".NVM_Driver_Section")))
#define NVM_DRIVER_SECTION_OFFSET __attribute__((section (".NVM_Driver_Section_offset")))
函数地址偏移量定义
__attribute__((used)) NVM_DRIVER_SECTION_OFFSET static const tFlashDriverAPIInfo gs_FlashDriverAPI = {
(tpfFLASH_DRV_EraseSector) CAL_OFFSET(FLASH_ErasePage),
(tpfFLASH_DRV_Program) CAL_OFFSET(FLASH_ProgramWord),
};
分两个段,保证地址偏移量在生成的hex文件的前面
此处使用库函数中的FLASH_ErasePage和FLASH_ProgramWord函数。由于提取的函数最终是以数组的形式存在,以函数指针的方式进行调用,所以函数中不能存在全局变量或调用其他的函数。
需要将原库函数中的函数的调用函数使用宏定义的方式进行定义,使用do while语法实现。
擦除函数
__attribute__((used)) NVM_DRIVER_SECTION FLASH_Status FLASH_ErasePage(uint32_t Page_Address)
{
FLASH_Status status = FLASH_COMPLETE;
FLASH_WaitForLastOperation(EraseTimeout,&status);
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to erase the page */
FLASH- >CR|= CR_PER_Set;
FLASH- >AR = Page_Address;
FLASH- >CR|= CR_STRT_Set;
/* Wait for last operation to be completed */
FLASH_WaitForLastOperation(EraseTimeout,&status);
/* Disable the PER Bit */
FLASH- >CR &= CR_PER_Reset;
}
/* Return the Erase Status */
return status;
}
上面的FLASH_WaitForLastOperation函数使用宏定义进行展开
#define FLASH_WaitForLastOperation(Timeout,pstatus)\\
do{\\
uint32_t TimeoutCnt = Timeout;\\
*pstatus = FLASH_COMPLETE;\\
FLASH_GetBank1Status(pstatus);\\
while((*pstatus == FLASH_BUSY) && (TimeoutCnt != 0x00))\\
{\\
FLASH_GetBank1Status(pstatus);\\
TimeoutCnt--;\\
}\\
if(TimeoutCnt == 0x00 )\\
{\\
*pstatus = FLASH_TIMEOUT;\\
}\\
}while(0)
里面又用到一个FLASH_GetBank1Status函数
#define FLASH_GetBank1Status(pFLASH_Status)\\
do{\\
*pFLASH_Status = FLASH_COMPLETE;\\
if((FLASH- >SR & FLASH_FLAG_BANK1_BSY) == FLASH_FLAG_BSY)\\
{\\
*pFLASH_Status = FLASH_BUSY;\\
}\\
else\\
{\\
if((FLASH- >SR & FLASH_FLAG_BANK1_PGERR) != 0)\\
{\\
*pFLASH_Status = FLASH_ERROR_PG;\\
}\\
else\\
{\\
if((FLASH- >SR & FLASH_FLAG_BANK1_WRPRTERR) != 0 )\\
{\\
*pFLASH_Status = FLASH_ERROR_WRP;\\
}\\
else\\
{\\
*pFLASH_Status = FLASH_COMPLETE;\\
}\\
}\\
}\\
}while(0)
写入函数
__attribute__((used)) NVM_DRIVER_SECTION FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
FLASH_Status status = FLASH_COMPLETE;
__IO uint32_t tmp = 0;
FLASH_WaitForLastOperation(ProgramTimeout,&status);
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to program the new first
half word */
FLASH- >CR |= CR_PG_Set;
*(__IO uint16_t*)Address = (uint16_t)Data;
/* Wait for last operation to be completed */
FLASH_WaitForLastOperation(ProgramTimeout,&status);
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to program the new second
half word */
tmp = Address + 2;
*(__IO uint16_t*) tmp = Data > > 16;
/* Wait for last operation to be completed */
FLASH_WaitForLastOperation(ProgramTimeout,&status);
/* Disable the PG Bit */
FLASH- >CR &= CR_PG_Reset;
}
else
{
/* Disable the PG Bit */
FLASH- >CR &= CR_PG_Reset;
}
}
/* Return the Program Status */
return status;
}
其中用到的函数也已经改为宏定义
编译后的map
gs_FlashDriverAPI 0x08020000 Data 8 main.o(.NVM_Driver_Section_offset)
FLASH_ErasePage 0x08020009 Thumb Code 186 stm32f10x_flash.o(.NVM_Driver_Section)
FLASH_ProgramWord 0x080200c3 Thumb Code 250 stm32f10x_flash.o(.NVM_Driver_Section)
函数需要偶数地址对齐
hexview中显示:
手动测试
__align(4) uint8_t flash_erase_buf[]={
0x30,0xB5, 0x6C, 0x49, 0x04, 0x46, 0x4F, 0xF4,
0x30, 0x22, 0xCD, 0x68, 0x04, 0x20, 0x13, 0x46, 0xED, 0x07, 0x09, 0xD1, 0xCB, 0x68, 0x5B, 0x07,
0x01, 0xD5, 0x02, 0x20, 0x30, 0xBD, 0xCB, 0x68, 0xDB, 0x06, 0x18, 0xD5, 0x03, 0x20, 0x30, 0xBD,
0xCD, 0x68, 0x04, 0x20, 0xED, 0x07, 0x02, 0xD0, 0x5B, 0x1E, 0xF9, 0xD1, 0x1C, 0xE0, 0xCD, 0x68,
0x6D, 0x07, 0x01, 0xD5, 0x02, 0x20, 0x06, 0xE0, 0xCD, 0x68, 0xED, 0x06, 0x03, 0xD5, 0x03, 0x20,
0x01, 0x2B, 0x11, 0xD0, 0x30, 0xBD, 0x01, 0x2B, 0x0E, 0xD0, 0x04, 0x28, 0xFA, 0xD1, 0x0B, 0x69,
0x43, 0xF0, 0x02, 0x03, 0x0B, 0x61, 0x4C, 0x61, 0x0B, 0x69, 0x43, 0xF0, 0x40, 0x03, 0x0B, 0x61,
0xCB, 0x68, 0xDB, 0x07, 0x0C, 0xD1, 0x01, 0xE0, 0x05, 0x20, 0x30, 0xBD, 0xCA, 0x68, 0x52, 0x07,
0x01,