【5744】MPC5744入门笔记(3)Flash实验

1. 起因

Can接口调通之后紧接着调的就是flash接口,因为第一部分工作是准备先做一个5744基于can的bootloader出来。这部分之前在stm32和S32K上都做过,其实就是解锁,加锁,成片区擦除和buf写入,如果有工作量吧,主要应该在上层的接口优化,其实有时间的话,还挺想看看别人flash相关的开源库是怎么做的,比如easyflash。

2. 借鉴

2.1 官方demo

调试第一步还是上demo。
在这里插入图片描述
简单看了一下,主要接口:

  1. 上锁 FLASH_DRV_SetLock
  2. 解锁 FLASH_DRV_SetLock
  3. 擦除 FLASH_DRV_Erase
  4. 烧录 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上一层实现的。
我们主要用到的接口有:

  1. 解锁接口 Flash_Unlock_g
  2. 加锁接口 Flash_Lock_g
  3. 擦除接口 Flash_Erase_g
  4. 烧录接口 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,
								  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;
}

4.3.2.4 Flash_Lock_g

这个接口就是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;

}

5. 参考链接

  1. 参考的flash代码 github (bootloader实现)
  2. NXP官方文档 MPC5744PRM.pdf
  3. 写的很好的博客(5744的flash)

6. 系列文章

【5744】MPC5744入门笔记(1)开发环境搭建
【5744】MPC5744入门笔记(2)CAN实验

发布了25 篇原创文章 · 获赞 7 · 访问量 5115

猜你喜欢

转载自blog.csdn.net/tao475824827/article/details/103317167