前言
在汽車行業(yè)控制器軟件刷新流程中,一般會將Flash驅(qū)動單獨進行刷寫,目的是防止程序中一直存在Flash驅(qū)動的話,可能會造成對APP軟件的異常操作,導(dǎo)致應(yīng)用程序無法執(zhí)行。本文介紹STM32F103使用KEIL生成指定FlashDriver地址的hex文件,然后使用HexView命令行提取FlashDriver及Remapping flash地址到ram地址
本文參考github,SummerFalls大神的UDS_S32K144_FlashDriver
芯片內(nèi)存定義
STM32F103RCT6,flash大小256k,一個扇區(qū)2k,SRAM:48KB;
實現(xiàn)過程
FlashDriver生成
段定義
由于我無法直接在Keil中導(dǎo)出指定ram地址的hex文件,所以采用先定義指定flash地址的flash驅(qū)動,后面通過hexview實現(xiàn)地址重映射
keil中的內(nèi)存區(qū)域定義通過分散加載文件(.sct格式)實現(xiàn),如下所示
; *************************************************************
; *** 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)
}
}
此處設(shè)置了兩個段,NVM_Driver_Section_offset用來設(shè)置函數(shù)偏移地址,NVM_Driver_Section用來設(shè)置函數(shù)地址
增加段的宏定義
#define NVM_DRIVER_SECTION __attribute__((section (".NVM_Driver_Section")))
#define NVM_DRIVER_SECTION_OFFSET __attribute__((section (".NVM_Driver_Section_offset")))
函數(shù)地址偏移量定義
__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文件的前面
此處使用庫函數(shù)中的FLASH_ErasePage和FLASH_ProgramWord函數(shù)。由于提取的函數(shù)最終是以數(shù)組的形式存在,以函數(shù)指針的方式進行調(diào)用,所以函數(shù)中不能存在全局變量或調(diào)用其他的函數(shù)。
需要將原庫函數(shù)中的函數(shù)的調(diào)用函數(shù)使用宏定義的方式進行定義,使用do while語法實現(xiàn)。
擦除函數(shù)
__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函數(shù)使用宏定義進行展開
#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函數(shù)
#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)
寫入函數(shù)
__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;
}
其中用到的函數(shù)也已經(jīng)改為宏定義
編譯后的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)
函數(shù)需要偶數(shù)地址對齊
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, 0xD5, 0x02, 0x20, 0x17, 0xE0, 0xCA, 0x68, 0xD2, 0x06, 0x14, 0xD5, 0x03, 0x20, 0x12, 0xE0,
0xCB, 0x68, 0x04, 0x20, 0xDB, 0x07, 0x02, 0xD0, 0x52, 0x1E, 0xF9, 0xD1, 0x0A, 0xE0, 0xCB, 0x68,
0x5B, 0x07, 0x01, 0xD5, 0x02, 0x20, 0x03, 0xE0, 0xCB, 0x68, 0xDB, 0x06, 0x00, 0xD5, 0x03, 0x20,
0x01, 0x2A, 0x00, 0xD1, 0x05, 0x20, 0x0A, 0x69, 0x41, 0xF6, 0xFD, 0x73, 0x1A, 0x40, 0x0A, 0x61,
0x30, 0xBD
};
__align(4) uint8_t flash_write_buf[]={
0xF8, 0xB5, 0x00, 0x92, 0x3C, 0x4A, 0x06, 0x46, 0x04, 0x20, 0xC3, 0x02,
0xD4, 0x68, 0x1D, 0x46, 0xE4, 0x07, 0x09, 0xD1, 0xD4, 0x68, 0x64, 0x07, 0x01, 0xD5, 0x02, 0x20,
0xF8, 0xBD, 0xD4, 0x68, 0xE4, 0x06, 0x18, 0xD5, 0x03, 0x20, 0xF8, 0xBD, 0xD4, 0x68, 0x04, 0x20,
0xE4, 0x07, 0x02, 0xD0, 0x6D, 0x1E, 0xF9, 0xD1, 0x1B, 0xE0, 0xD4, 0x68, 0x64, 0x07, 0x01, 0xD5,
0x02, 0x20, 0x06, 0xE0, 0xD4, 0x68, 0xE4, 0x06, 0x03, 0xD5, 0x03, 0x20, 0x01, 0x2D, 0x10, 0xD0,
0xF8, 0xBD, 0x01, 0x2D, 0x0D, 0xD0, 0x04, 0x28, 0xFA, 0xD1, 0x14, 0x69, 0x44, 0xF0, 0x01, 0x04,
0x14, 0x61, 0x31, 0x80, 0xD5, 0x68, 0x1C, 0x46, 0xEF, 0x07, 0x41, 0xF6, 0xFE, 0x75, 0x09, 0xD1,
0x01, 0xE0, 0x05, 0x20, 0xF8, 0xBD, 0xD4, 0x68, 0x64, 0x07, 0x21, 0xD4, 0xD4, 0x68, 0xE4, 0x06,
0x23, 0xD4, 0x13, 0xE0, 0xD7, 0x68, 0x04, 0x20, 0xFF, 0x07, 0x02, 0xD0, 0x64, 0x1E, 0xF9, 0xD1,
0x2F, 0xE0, 0xD7, 0x68, 0x7F, 0x07, 0x01, 0xD5, 0x02, 0x20, 0x03, 0xE0, 0xD7, 0x68, 0xFF, 0x06,
0x00, 0xD5, 0x03, 0x20, 0x01, 0x2C, 0x24, 0xD0, 0x04, 0x28, 0x23, 0xD1, 0xB6, 0x1C, 0x09, 0x0C,
0x00, 0x96, 0x31, 0x80, 0xD1, 0x68, 0xC9, 0x07, 0x09, 0xD1, 0xD1, 0x68, 0x49, 0x07, 0x01, 0xD5,
0x02, 0x20, 0x17, 0xE0, 0xD1, 0x68, 0xC9, 0x06, 0x14, 0xD5, 0x03, 0x20, 0x12, 0xE0, 0xD1, 0x68,
0x04, 0x20, 0xC9, 0x07, 0x02, 0xD0, 0x5B, 0x1E, 0xF9, 0xD1, 0x0A, 0xE0, 0xD1, 0x68, 0x49, 0x07,
0x01, 0xD5, 0x02, 0x20, 0x03, 0xE0, 0xD1, 0x68, 0xC9, 0x06, 0x00, 0xD5, 0x03, 0x20, 0x01, 0x2B,
0x00, 0xD1, 0x05, 0x20, 0x11, 0x69, 0x29, 0x40, 0x11, 0x61, 0xF8, 0xBD, 0x00, 0x20, 0x02, 0x40,
};
typedef void (*flash_erase_handler)(uint32_t u32addr);
typedef void (*flash_write_handler)(uint32_t u32addr, uint32_t u32data);
flash_erase_handler flash_erase = (flash_erase_handler)(flash_erase_buf + 1);
flash_write_handler flash_write = (flash_write_handler)(flash_write_buf + 1);
#define Test_addr 0x08030000
函數(shù)地址為0x08020009,往前一位開始復(fù)制,186byte,得到擦除函數(shù)
此處數(shù)組+1是因為指令LSB即最低有效位為0時是ARM指令,為1時是Thumb代碼,此處需要+1使其成為Thumb代碼
同理,可得到寫入函數(shù)。
運行擦除函數(shù):
目的地址內(nèi)容被擦除
運行寫入函數(shù):
可以看到寫入值正常。
HexView提取指定地址內(nèi)容并重映射
編輯bat腳本如下
.\HexTools\hexview.exe /G /s .\RVMDK\Output\Project.hex /AR:0x8020000-0x80201bf /xi:16 -o FlashDrv.hex /e:errorfile
.\HexTools\hexview.exe /G /s FlashDrv.hex /remap:0x8020000-0x80201bf,0x20001000,0x1c0,0x1c0 /xi:16 -o FlashDrv.hex /e:errorfile
使用/AR命令提取指定地址內(nèi)容
使用/remap命令對地址進行remap,重映射地址為0x20001000,block大小為0x1c0
提取的flashdrv如下圖所示:
文章來源:http://www.zghlxwxcb.cn/news/detail-624595.html
總結(jié)
本文介紹了STM32F103 Flashdriver的制作過程,如果編譯器有工具支持直接重映射到ram地址的話,就不需要后面hexview的步驟了,例如S32DS中就有。(keil中可能也有,后面如果研究出來了再補上)文章來源地址http://www.zghlxwxcb.cn/news/detail-624595.html
若你覺得本文對你有幫助,歡迎點贊,關(guān)注,收藏,轉(zhuǎn)發(fā)~~~ 你的鼓勵是對小弟的最大支持~~~ 建了一個WX公眾h,《汽車電子學(xué)習筆記》感興趣可以關(guān)注一下~~~文章都會同步更新~
到了這里,關(guān)于STM32F103制作FlashDriver的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!