Can接口调通之后紧接着调的就是flash接口,因为第一部分工作是准备先做一个5744基于can的bootloader出来。这部分之前在stm32和S32K上都做过,其实就是解锁,加锁,成片区擦除和buf写入,如果有工作量吧,主要应该在上层的接口优化,其实有时间的话,还挺想看看别人flash相关的开源库是怎么做的,比如easyflash。
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));
...
...
在网上找到一个在系统接口上又再次封装的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);
可以从RM文档中进行查看,文档链接见末尾。
5744的flash主要分成small、middle、large。
flash操作用的另外一种分类模式,Low、Medium、High、First256K、Second256K,对应flash_block_select_t 结构体。
small、middle、large分类见图。
基于2.2部分的demo做了简单的修改。
定义了一个buffer数据,初始化为非零值,然后配置到startAddr地址处。demo中startAddr选择是0x01100000,因为链接文件中,flash_rchw是0x00FA0000,m_text是0x1000000,不要和他们冲突就行。
里面的接口主要是调用Flash.c。
除去SDK自带代码,和初始化的无关代码,其实实际的操作代码就中间一点。
//开发环境 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 */
这个接口文件是从参考链接里找过来的,是main.c调用的接口实现,是基于SDK自带的flash_c55_driver.c封装而成。个人感觉更好用些。
代码量比较大,就不全文放上了,可以去作者的github链接下载。
里面有些小错误,比如Flash_GetSelectBlock的return不应该是局部变量,计算endAddr应该再乘4之类的,自己用的时候随手改下就行,整个接口还是一个很好用的接口文件。
运行之后可以看到
可见已经从0x01100000地址成功 写了10个int进flash。
main.c比较简单,初始化时钟,初始化要写入的buffer,解锁,擦除,写入,加锁,一笔带过吧。
flash.c是主要的接口函数,是在系统接口flash_c55_driver.c上一层实现的。
我们主要用到的接口有:
先关闭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;
}
这一部分和之前逻辑一致,根据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;
}
这个没什么,基本上直接调用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,
NULL_CALLBACK);
if (STATUS_SUCCESS != ret)
{
return ret;
}
numOfWordCycle = NUMBER_OF_WORD_CHECK_SUM;
/* Check sum */
ret = FLASH_DRV_CheckSum(dest,
size,
numOfWordCycle,
&sum,
NULL_CALLBACK);
if ((STATUS_SUCCESS != ret) && (sum != 0U))
{
return ret;
}
return ret;
}
这个接口就是Flash_Unlock_g的逆操作。
先根据起始结束地址来进行block选择,然后调用对应的加锁函数,最后回复cache的使用。
status_t Flash_Lock_g(uint32_t startAddr, uint32_t endAddr)
{
status_t ret = STATUS_SUCCESS;
flash_block_select_t blockSelect={.lowBlockSelect=0,.midBlockSelect=0,.highBlockSelect=0,.first256KBlockSelect = 0,.second256KBlockSelect=0};
//UnLock block
blockSelect = Flash_GetSelectBlock(startAddr, endAddr);
//UnLock all block in range
if(blockSelect.lowBlockSelect!=0)
{
ret = FLASH_DRV_SetLock(0, Flash_Block_Lock[0]);
if (STATUS_SUCCESS != ret)
return ret;
}
if(blockSelect.midBlockSelect!=0)
{
ret = FLASH_DRV_SetLock(1, Flash_Block_Lock[1]);
if (STATUS_SUCCESS != ret)
return ret;
}
if(blockSelect.highBlockSelect!=0)
{
ret = FLASH_DRV_SetLock(2, Flash_Block_Lock[2]);
if (STATUS_SUCCESS != ret)
return ret;
}
if(blockSelect.first256KBlockSelect!=0)
{
ret = FLASH_DRV_SetLock(3, Flash_Block_Lock[3]);
if (STATUS_SUCCESS != ret)
return ret;
}
/* Restore flash controller cache */
RestoreFlashControllerCache(FLASH_PFCR1, pflash_pfcr1);
RestoreFlashControllerCache(FLASH_PFCR2, pflash_pfcr2);
return ret;
}
【5744】MPC5744入门笔记(1)开发环境搭建
【5744】MPC5744入门笔记(2)CAN实验