RX220 E2データフラッシュ 使い方

RX220のE2データフラッシュを使用するためのコードを書いたので公開します。といってもルネサス公式のサンプルプログラムそのままですが。これにより電源を落としてもE2データフラッシュに書き込んだデータなら保持することができるようになります。

自分の環境ではRXにプログラムを書き込むとROM内が消去されるみたいです。

ROMに書き込みや消去を行うにはそれなりに時間がかかるのでdelay関数をつくる必要があります。

18/3/16追記 E2ROM.cに一部バグがありました。修正済みです。

https://elearning.renesas.com/pluginfile.php/355/mod_folder/content/0/RX_MCU_Japanese/RX62N_FLD.pdf?forcedownload=1

 

E2ROM.h

#ifndef E2ROM_H_
#define E2ROM_H_

#include "iodefine.h"
#include "stdint.h"

enum status {FLD_ERROR,FLD_OK,FLD_TMOUT,FLD_BLANK,FLD_NOBLANK};

int wait_FRDY(unsigned int wait);//処理待ち関数
static void reset_fcu(void);//fcuリセット関数
int32_t fld_init_pclk_notification(void);//クロック通知関数
int32_t fld_blank_check_2KB( uint32_t addr );//ブランクチェック関数
int32_t fld_erase_2KB( uint32_t addr );//消去関数
int32_t fld_program_2byte( uint32_t addr, uint16_t *ram );//2byte書き込み関数
int32_t fld_program_8byte( uint32_t addr, uint16_t *ram );//8byte書き込み関数
int32_t fld_enable_read(void);//読み出し許可関数
int32_t fld_enable_PE(void);//読み出し無効PE有効

#endif /* E2ROM_H_ */

 

E2ROM.c

#include "E2ROM.h"

int32_t fld_init_pclk_notification(void)
{
	// 00100000h is top address of DB00 block
	volatile uint8_t *addr_b = (uint8_t *)0x00100000;
	volatile uint16_t *addr_w = (uint16_t *)0x00100000;
	// change to P/E mode
	if( (FLASH.FENTRYR.WORD & 0x00ff) != 0x0080 ){
		FLASH.FENTRYR.WORD = 0xAA80; // AAh is key
	}
	// set peripheral clock
	FLASH.PCKAR.BIT.PCKA = 32; // PCLK = 32 MHz
	// execute the peripheral clock notification command
	*addr_b = 0xE9;
	*addr_b = 0x03;
	*addr_w = 0x0F0F;
	*addr_w = 0x0F0F;
	*addr_w = 0x0F0F;
	*addr_b = 0xD0;
	// wait for tPCKA time
	if( wait_FRDY( 120 ) == FLD_TMOUT ){ // timeout is 120us
		reset_fcu();
	}
	// error check
	if( FLASH.FSTATR0.BIT.ILGLERR == 1 ){
		return FLD_ERROR;
	}
	return FLD_OK;
}


int32_t fld_blank_check_2KB( uint32_t addr )
{
	volatile uint8_t *addr_b = (uint8_t *)addr;
	// use the blank checking command
	FLASH.FMODR.BIT.FRDMD = 1;
	// set the blank check size (2 KB)
	FLASH.DFLBCCNT.BIT.BCSIZE = 1;
	// execute the Blank checking command
	*addr_b = 0x71;
	*addr_b = 0xD0;
	// wait for tDBC2K time (timeout is 770us)
	if( wait_FRDY( 700*1.1 ) == FLD_TMOUT ){
		reset_fcu();
	}
	// error check
	if( FLASH.FSTATR0.BIT.ILGLERR == 1 ){
		return FLD_ERROR;
	}
	// get result of blank checking command
	if( FLASH.DFLBCSTAT.BIT.BCST == 0 ){
		return FLD_BLANK;
	}
	return FLD_NOBLANK;
}

int32_t fld_erase_2KB( uint32_t addr )
{
	volatile uint8_t *addr_b;
	int32_t ret = FLD_OK;
	int i=0;
	// Unprotect
	FLASH.FWEPROR.BIT.FLWE = 1;
	// enable to erase all blocks
	FLASH.DFLWE0.WORD = 0x1E0F; // 1Eh is Key
	for(i=0;i<16;i++){
		addr_b = (uint8_t *)((uint32_t)addr + (uint32_t)128*i);//消去ブロックを移動
		// execute the block erase command
		*addr_b = 0x20;
		*addr_b = 0xD0;
		// wait for tDE2K time (timeout is 275ms)
		if( wait_FRDY( 250*1000*1.1 ) == FLD_TMOUT ){
			reset_fcu();
		}
		// Error check
		if( (FLASH.FSTATR0.BIT.ILGLERR == 1) ||	(FLASH.FSTATR0.BIT.ERSERR == 1) ){
			ret = FLD_ERROR;
		}
	}
	//protect and disable to erase
	FLASH.FWEPROR.BIT.FLWE = 2;
	FLASH.DFLWE0.WORD = 0x1E00;
	return ret;
}

int32_t fld_program_2byte( uint32_t addr, uint16_t *ram )
{
	volatile uint8_t *addr_b = (uint8_t *)addr;
	volatile uint16_t *addr_w = (uint16_t *)addr;
	int32_t ret = FLD_OK;
	// Unprotect and enable to write all blocks
	FLASH.FWEPROR.BIT.FLWE = 1;
	FLASH.DFLWE0.WORD = 0x1EFF; // 1Eh is Key
	//FLASH.DFLWE1.WORD = 0xE1FF; // E1h is Key
	// execute the 2-byte programming command
	*addr_b = 0xE8;
	*addr_b = 0x01;
	*addr_w = *ram;
	*addr_b = 0xD0;
	// wait for tDP8 time (timeout is 2.2ms)
	if( wait_FRDY( 2*1000*1.1 ) == FLD_TMOUT ){
		reset_fcu();
	}
	// error check
	if( (FLASH.FSTATR0.BIT.ILGLERR == 1) ||	(FLASH.FSTATR0.BIT.PRGERR == 1) ){
		ret = FLD_ERROR;
	}
	//protect and disable to write
	FLASH.FWEPROR.BIT.FLWE = 2;
	FLASH.DFLWE0.WORD = 0x1E00;
	//FLASH.DFLWE1.WORD = 0xE100;
	return ret;
}

int32_t fld_program_8byte( uint32_t addr, uint16_t *ram )
{
	volatile uint8_t *addr_b = (uint8_t *)addr;
	volatile uint16_t *addr_w = (uint16_t *)addr;
	int32_t i,ret = FLD_OK;
	// Unprotect and enable to write all blocks
	FLASH.FWEPROR.BIT.FLWE = 1;
	FLASH.DFLWE0.WORD = 0x1EFF; // 1Eh is Key
	//FLASH.DFLWE1.WORD = 0xE1FF; // E1h is Key
	// execute the 8-byte programming command
	*addr_b = 0xE8;
	*addr_b = 0x04;
	for(i=0; i<4; i++){ // 8-byte is 4 word size
		*addr_w = *ram++;
	}
	*addr_b = 0xD0;
	// wait for tDP8 time (timeout is 2.2ms)
	if( wait_FRDY( 2*1000*1.1 ) == FLD_TMOUT ){
		reset_fcu();
	}
	// error check
	if( (FLASH.FSTATR0.BIT.ILGLERR == 1) ||	(FLASH.FSTATR0.BIT.PRGERR == 1) ){
		ret = FLD_ERROR;
	}
	//protect and disable to write
	FLASH.FWEPROR.BIT.FLWE = 2;
	FLASH.DFLWE0.WORD = 0x1E00;
	//FLASH.DFLWE1.WORD = 0xE100;
	return ret;
}

int32_t fld_enable_read(void)
{
	// change to read mode
	if( FLASH.FENTRYR.WORD & 0x00ff ){
		FLASH.FENTRYR.WORD = 0xAA00; // AAh is key
	}
	// enable to read all blocks
	FLASH.DFLRE0.WORD = 0x2DFF; // 2Dh is Key
	//FLASH.DFLRE1.WORD = 0xD2FF; // D2h is Key
	return FLD_OK;
}

int32_t fld_enable_PE(void)
{
	//change to PE mode
	if( (FLASH.FENTRYR.WORD & 0x00ff) != 0x0080 ){
		FLASH.FENTRYR.WORD = 0xAA80; // AAh is key
	}
	//disabled to read all blocks
	FLASH.DFLRE0.WORD = 0x2D00; // 2Dh is Key
	return FLD_OK;

}

int wait_FRDY(unsigned int wait){
	unsigned int cnt=0;
	while(FLASH.FSTATR0.BIT.FRDY==0){
		delay_us(1);
		cnt++;
		if(cnt==wait) return FLD_TMOUT;
	}
	return FLD_OK;
}

static void reset_fcu(void)
{
	volatile int32_t w;
	// FCU reset
	FLASH.FRESETR.BIT.FRESET = 1;
	// wait for tRESW2 time (tRESW2 is 35us)
	delay_us(35);
	// clear FCU reset
	FLASH.FRESETR.BIT.FRESET = 0;
}

使用例

E2データフラッシュ領域の先頭へ0xFFFFを書き込み、その後読み出す。

	// 00100000h is top address of DB00 block
	uint32_t top_addr_db00 = 0x00100000;
	volatile uint16_t *read;

	unsigned short int test =0xFFFF;
	unsigned short int *test_data=&test;

	fld_init_pclk_notification();
	// change to P/E mode
	fld_enable_PE();
	// blank check (2 KB)
	if( fld_blank_check_2KB( top_addr_db00 ) !=FLD_BLANK ){
	// block erase
	fld_erase_2KB( top_addr_db00 );
	}
	// 2byte programming
	fld_program_2byte( top_addr_db00, test_data );
	// set enable to read
	fld_enable_read();
	read = (uint16_t *)top_addr_db00;