1. 起因
Can接口調通之后緊接著調的就是flash接口,因為第一部分工作是準備先做一個5744基于can的bootloader出來。這部分之前在stm32和S32K上都做過,其實就是解鎖,加鎖,成片區擦除和buf寫入,如果有工作量吧,主要應該在上層的接口優化,其實有時間的話,還挺想看看別人flash相關的開源庫是怎么做的,比如easyflash。
2. 借鑒
2.1 官方demo
調試第一步還是上demo。
簡單看了一下,主要接口:
上鎖 FLASH_DRV_SetLock
解鎖 FLASH_DRV_SetLock
擦除 FLASH_DRV_Erase
燒錄 FLASH_DRV_Program
其實已經包含了flash的主要操作了。
flash模塊在SDK中沒有pal層,對外的接口都是在flash_c55_driver.c,主要有:
status_t FLASH_DRV_CheckProgramStatus(flash_context_data_t * pCtxData, flash_state_t * opResult);
status_t FLASH_DRV_Init(void);
status_t FLASH_DRV_SetLock(flash_address_space_t lockedBlockSelection,uint32_t lockedBlockState);
status_t FLASH_DRV_GetLock(flash_address_space_t lockedBlockSelection,uint32_t * lockedBlockState);
status_t FLASH_DRV_Erase(flash_erase_option_t eraseOption,flash_block_select_t * blockSelect);
status_t FLASH_DRV_Program(flash_context_data_t * pCtxData, uint32_t dest,uint32_t size,uint32_t source);
status_t FLASH_DRV_ProgramVerify(uint32_t dest,uint32_t size,uint32_t source,uint32_t numOfWordCycle,uint32_t * pFailedAddress,void (*CallBack)(void));
status_t FLASH_DRV_CheckSum(uint32_t dest,uint32_t size,uint32_t numOfWordCycle,uint32_t * pSum,void (*CallBack)(void));
...
...
2.2 參考例程
在網上找到一個在系統接口上又再次封裝的FLash接口,還直接給出了Demo程序,相對系統函數更好調用一些。鏈接可以見文末參考鏈接1,代碼接口可以見4.2.2,代碼解析可以見4.3.2。
lash_block_select_t Flash_GetSelectBlock(uint32_t startAddr, uint32_t endAddr);
status_t Flash_Unlock_g(uint32_t startAddr, uint32_t endAddr);
status_t Flash_Erase_g(uint32_t startAddr, uint32_t endAddr);
status_t Flash_Check_g(uint32_t startAddr, uint32_t endAddr);
status_t Flash_Program_g(uint32_t startAddr, uint32_t endAddr, uint32_t *buffer, uint32_t len);
status_t Flash_Lock_g(uint32_t startAddr, uint32_t endAddr);
3. Mpc5744的flash分區
可以從RM文檔中進行查看,文檔鏈接見末尾。
5744的flash主要分成small、middle、large。
flash操作用的另外一種分類模式,Low、Medium、High、First256K、Second256K,對應flash_block_select_t 結構體。
small、middle、large分類見圖。
4. flash實驗
4.1 實驗環境
軟件環境 : S32DS for power v2.1 (RTM3.0.0)
硬件環境 : DEVKIT-MPC5744P (MPC5744P-BGA257)
4.2 實驗代碼
基于2.2部分的demo做了簡單的修改。
定義了一個buffer數據,初始化為非零值,然后配置到startAddr地址處。demo中startAddr選擇是0x01100000,因為鏈接文件中,flash_rchw是0x00FA0000,m_text是0x1000000,不要和他們沖突就行。
里面的接口主要是調用Flash.c。
除去SDK自帶代碼,和初始化的無關代碼,其實實際的操作代碼就中間一點。
4.2.1 main.c
//開發環境 S32DS for power v2.1
#include "Cpu.h"
volatile int exit_code = 0;
int main(void)
{
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
#ifdef PEX_RTOS_INIT
PEX_RTOS_INIT(); /* Initialization of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/*** End of Processor Expert internal initialization. ***/
CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT,g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_FORCIBLE);
PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);
#define BUF_LEN 10
status_t ret = STATUS_SUCCESS;
uint32_t i;
uint32_t buffer[BUF_LEN] ;
uint32_t startAddr = 0x01100000;
uint32_t endAddr = startAddr+sizeof(buffer)/sizeof(uint32_t)*4-1;
memset(buffer,0xa5,sizeof(buffer));
Flash_Unlock_g(startAddr,endAddr);
while(1)
{
ret = Flash_Erase_g(startAddr,endAddr);
//ret = Flash_Check_g(startAddr,endAddr);
ret = Flash_Program_g(startAddr,endAddr, buffer,sizeof(buffer)/sizeof(uint32_t));
OSIF_TimeDelay(5000);
}
Flash_Lock_g(startAddr,endAddr);
/*** Don't write any code pass this line, or it will be deleted during code generation. ***/
/*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/
#ifdef PEX_RTOS_START
PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/*** End of RTOS startup code. ***/
/*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
for(;;) {
if(exit_code != 0) {
break;
}
}
return exit_code;
/*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/
/* END main */
4.2.2 flash.c
這個接口文件是從參考鏈接里找過來的,是main.c調用的接口實現,是基于SDK自帶的flash_c55_driver.c封裝而成。個人感覺更好用些。
代碼量比較大,就不全文放上了,可以去作者的github鏈接下載。
里面有些小錯誤,比如Flash_GetSelectBlock的return不應該是局部變量,計算endAddr應該再乘4之類的,自己用的時候隨手改下就行,整個接口還是一個很好用的接口文件。
4.2.3 實驗結果
運行之后可以看到
可見已經從0x01100000地址成功 寫了10個int進flash。
4.3 實驗代碼解析
4.3.1 main.c
main.c比較簡單,初始化時鐘,初始化要寫入的buffer,解鎖,擦除,寫入,加鎖,一筆帶過吧。
4.3.2 flash.c
flash.c是主要的接口函數,是在系統接口flash_c55_driver.c上一層實現的。
我們主要用到的接口有:
解鎖接口 Flash_Unlock_g
加鎖接口 Flash_Lock_g
擦除接口 Flash_Erase_g
燒錄接口 Flash_Program_g
4.3.2.1 Flash_Unlock_g
先關閉flash的cache。
再進行初始化FLASH_DRV_Init。這些都和flash_progarm_erase_mpc5744p的官方demo的main.c一致。
下面根據startAddr和endAddr地址,調用Flash_GetSelectBlock接口,獲取 要選中的flashblock(lowBlockSelect、midBlockSelect、highBlockSelect、first256KBlockSelect,second256KBlockSelect)
最后根據置位值,調用FLASH_DRV_SetLock進行對應block的解鎖。
(官方demo中是解鎖了所有flash區域)
status_t Flash_Unlock_g(uint32_t startAddr, uint32_t endAddr)
{
status_t ret = STATUS_SUCCESS;
uint32_t blkLockState; /* block lock status to be retrieved */
flash_block_select_t blockSelect={.lowBlockSelect=0,.midBlockSelect=0,.highBlockSelect=0,.first256KBlockSelect = 0,.second256KBlockSelect=0};
/* Invalidate flash controller cache */
DisableFlashControllerCache(FLASH_PFCR1, FLASH_FMC_BFEN_MASK, &pflash_pfcr1);
DisableFlashControllerCache(FLASH_PFCR2, FLASH_FMC_BFEN_MASK, &pflash_pfcr2);
/* Flash Initialization */
ret = FLASH_DRV_Init();
DEV_ASSERT(ret == STATUS_SUCCESS);
/**************************************************************************/
/* Lock to protect UTest address space */
/**************************************************************************/
ret = FLASH_DRV_GetLock(C55_BLOCK_UTEST, &blkLockState);
if (!(blkLockState & 0x00000001U))
{
ret = FLASH_DRV_SetLock(C55_BLOCK_UTEST, 0x1U);
if (STATUS_SUCCESS != ret)
{
return ret;
}
}
blockSelect = Flash_GetSelectBlock(startAddr, endAddr);
//UnLock all block in range
if(blockSelect.lowBlockSelect!=0)
{
ret = FLASH_DRV_SetLock(0, Flash_Block_UnLock[0]);
if (STATUS_SUCCESS != ret)
return ret;
}
if(blockSelect.midBlockSelect!=0)
{
ret = FLASH_DRV_SetLock(1, Flash_Block_UnLock[1]);
if (STATUS_SUCCESS != ret)
return ret;
}
if(blockSelect.highBlockSelect!=0)
{
ret = FLASH_DRV_SetLock(2, Flash_Block_UnLock[2]);
if (STATUS_SUCCESS != ret)
return ret;
}
if(blockSelect.first256KBlockSelect!=0)
{
ret = FLASH_DRV_SetLock(3, Flash_Block_UnLock[3]);
if (STATUS_SUCCESS != ret)
return ret;
}
return ret;
}
4.3.2.2 Flash_Erase_g
這一部分和之前邏輯一致,根據startAddr和endAddr地址,調用Flash_GetSelectBlock接口,獲取 要選中的flashblock。
然后將對應的block全部擦除。
這里注意一下flash_block_select_t這個結構體。
是根據起始地址和終止地址來判斷所處的block。
我們在第3部分看到5744的flash區域劃分,每個類別都有多個block。
所以這里FLASH_DRV_Erase調用blockSelect之后,并不是某一標志位置位就直接擦除整個類別的flash,它會根據對應的具體值來擦除指定的區域。
eg:
demo中:
uint32_t startAddr = 0x01100000;
uint32_t endAddr = startAddr+sizeof(buffer)/sizeof(uint32_t)*4-1;
使用Flash_GetSelectBlock返回的blockSelect是
再調用FLASH_DRV_Erase會根據first256KBlockSelect的具體值去選擇對應的block來擦,而不是擦除整個first256KBlock區域(多個block)。
status_t Flash_Erase_g(uint32_t startAddr, uint32_t endAddr)
{
status_t ret = STATUS_SUCCESS;
flash_state_t opResult;
flash_block_select_t blockSelect;
blockSelect = Flash_GetSelectBlock(startAddr,endAddr);
g_usrCnt = 0U;
/* Erase block */
ret = FLASH_DRV_Erase(ERS_OPT_MAIN_SPACE, &blockSelect);
if (STATUS_SUCCESS == ret)
{
do
{
/* The user can do any tasks while check status function is still in progress */
UserCallBack();
ret = FLASH_DRV_CheckEraseStatus(&opResult);
}while(ret == STATUS_FLASH_INPROGRESS);
}
if (STATUS_SUCCESS != ret)
{
return ret;
}
return ret;
}
4.3.2.3 Flash_Program_g
這個沒什么,基本上直接調用FLASH_DRV_Program即可。
寫入長度必須是4的倍數。
//every 4 addresses is the same, such 0xFC0000=0xFC0001=0xFC0002=0xFC0003
status_t Flash_Program_g(uint32_t startAddr, uint32_t endAddr, uint32_t *buffer, uint32_t len)
{
status_t ret = STATUS_SUCCESS;
uint32_t dest; /* destination address */
uint32_t size; /* size applicable */
uint32_t source; /* source address for program and verify */
uint32_t numOfWordCycle;
flash_state_t opResult;
uint32_t failedAddress; /* save the failed address in flash */
uint32_t sum; /* check sum result */
flash_context_data_t pCtxData;
/* Program to beginning of block */
dest = startAddr;
size = len*C55_WORD_SIZE;
source = (uint32_t)buffer;
g_usrCnt = 0U;
ret = FLASH_DRV_Program(&pCtxData,
dest,
size,
source);
if (STATUS_SUCCESS == ret)
{
do
{
/* The user can do any tasks while check status function is still in progress */
UserCallBack();
ret = FLASH_DRV_CheckProgramStatus(&pCtxData, &opResult);
}while(ret == STATUS_FLASH_INPROGRESS);
}
if (STATUS_SUCCESS != ret)
{
return ret;
}
numOfWordCycle = NUMBER_OF_WORD_PGM_VERIFY;
/* Program verify */
ret = FLASH_DRV_ProgramVerify(dest,
size,
source,
numOfWordCycle,
&failedAddress,
上一篇:MPC5744P-NXP各個模塊(驅動)示例代碼
下一篇:MPC5744P-時鐘模塊
推薦閱讀
史海拾趣