Code to reduce flash wearout.

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

Code to reduce flash wearout.

1,080件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by micrio on Sun Jun 26 05:58:18 MST 2011
This is a complete set of functions to save persistent parameters in flash and
do it in a way to reduce the flash wearout effect. This also contains
complete routines to access the flash through the IAP interface.

Flash wearout is reduced by writing the data to a new section of flash each time.
The write location moves up through the flash sector on each write.
When the it comes to the end of the sector, the entire sector is erased and the
write process begins again at the beginning of the sector.

In my application I need to save structure that is 0x1c bytes of data.
This is not an even power of 2 and so does not fit evenly in a flash
block of 256 bytes. Thus, 9 will fit in one flash block. Since there are 16
blocks in a sector I get 144 saves before I have to do a sector erase.
The normal wearout of 10,000 cycles is extended to 1,440,000
cycles which is good enough.

This code is tested and seems to work properly. If anyone has any
comments they are welcome. Particularly if I made a mistake with
respect to the wearout issue.

Thanks,
Pete.




/*
* Copyright Micrio Associates Inc. 2011 www.micrio.com
*
* This code can be used without permission or acknowledgement
* as long as this comment block is kept in the code.
*
* Micrio Associates is available for consulting and project
* development. Please contact us at the above web site.
*
*/

// This is the structure definition of the data to be saved.
typedef struct {
int param1;
int param2;
int param3;
} sys_state_t;

[LEFT][COLOR=black]#define FLASH_SECTOR_SIZE 4096[/COLOR]
[COLOR=black]#define FLASH_BLOCK_SIZE 256[/COLOR]
[COLOR=black]#define STRUCTS_PER_BLOCK FLASH_BLOCK_SIZE / sizeof(sys_state_t)[/COLOR]
[COLOR=black]#define BLOCKS_PER_SECTOR FLASH_SECTOR_SIZE / FLASH_BLOCK_SIZE[/COLOR][/LEFT]

[LEFT]/* This is the running copy of the system state information. */
sys_state_t sys_state;
/* These are pointers into flash memory. */
sys_state_t *current_sys_state;
sys_state_t *free_sys_state;[/LEFT]

[LEFT]/* Embedded utility IAP functions. */
#define PREP_WR 50
#define FLASH_WR 51
#define ERASE_SEC 52
#define BLK_CHK 53
/* This is the entry point for IAP calls. */
#define IAP_LOCATION 0x1fff1ff1
/* Call into embedded utility. */
void (*iap_entry)(unsigned long *, unsigned long *) = (void *)IAP_LOCATION;
unsigned long command[5];
unsigned long result[4];[/LEFT]

[LEFT]/*
* Write the sys_state structure to a free location in the flash.
* Advance up the page each time using the next free location.
* When we run out of locations then erase the entire sector.
* This reduces wear on the flash memory.
* A sector is the minimum erasable size which is 4K.
* A block is the minimum writable size which is 256 bytes.
*
* Parameters (global):
* sys_state A global RAM resident structure to be saved in flash
* state_flash_sec The sector in flash to use for saving sys_state data.
*
* Return data:
* 0 sys_state saved.
* -1 Save failed..
*/
int
do_write_state(void){
char sys_buf[FLASH_BLOCK_SIZE];
int i;
char *s_ptr;
int offset;
char *free_sys_block;
find_state_ptrs (); // Find the first free sys_state structure.
// If there are no free sys_state locations then erase the entire sector.
if (free_sys_state == 0) {
/* First we must erase the page before we can write the data. */
if (erase_flash(((long)state_flash_sec) >> 12, ((long)state_flash_sec) >> 12) != 0) {
return (-1);
}
// This is needed because we have we just erased and the pointers need updating.
find_state_ptrs (); // Find the first free sys_state structure.
}
// Get the block that contains the free sys_state location.
free_sys_block = (char *)((int)free_sys_state & (~(FLASH_BLOCK_SIZE - 1)));
// Copy the entire block from flash into the local buffer.
for (i = 0; i < FLASH_BLOCK_SIZE; i++) {
sys_buf = free_sys_block;
}
// Copy the sys_state data into the local buffer with the correct offset.
// We want to change the minimum amount of data to save wear.
s_ptr = (char *)&sys_state;
offset = (int)free_sys_state & (FLASH_BLOCK_SIZE - 1);
for (i = 0; i < sizeof(sys_state_t); i++) {
sys_buf[offset + i] = s_ptr;
}
/* Prepare the sector for write. */
command[0] = PREP_WR;
command[1] = ((long)state_flash_sec) >> 12;
command[2] = ((long)state_flash_sec) >> 12;
iap_entry (command, result);
if (result[0] != 0) {
return (-1);
}
/* Then we will write the sector. */
command[0] = FLASH_WR;
command[1] = (long)free_sys_block;
command[2] = (long)&sys_buf;
command[3] = FLASH_BLOCK_SIZE;
command[4] = SystemFrequency / 1000; /* Must be in terms of cycles per millisecond. */
iap_entry (command, result);
if (result[0] != 0) {
return (-1);
}
return (0);
}
/*
* Erase if the specified sectors in flash, set to all FF's.
*
* Parameters:
* start Starting sector.
* end Ending sector for check.
*
* Return value:
* 0 Sectors are erased.
* -1 Sectors not erased.
*/
int
erase_flash(long start, long end){
/* First we will prepare the sector for erase. */
command[0] = PREP_WR;
command[1] = start;
command[2] = end;
command[3] = 0;
command[4] = 0;
iap_entry (command, result);
if (result[0] != 0) {
return (-1);
}
/* Next we will erase the sector. */
command[0] = ERASE_SEC;
command[1] = start;
command[2] = end;
command[3] = SystemFrequency / 1000; /* Must be in terms of cycles per millisecond. */
command[4] = 0;
iap_entry (command, result);
if (result[0] != 0) {
return (-1);
}
// Check if the flash is really cleared.
if (blank_check(start, end)) {
return (-1);
}
return (0);
}
/*
* Check if the specified sectors in flash are erased, set to all FF's.
*
* Parameters:
* start Starting sector.
* end Ending sector for check.
*
* Return value:
* 0 Sectors are erased.
* -1 Sectors not erased.
*/
int
blank_check(long start, long end){
/* First we will prepare the sector for erase. */
command[0] = BLK_CHK;
command[1] = start;
command[2] = end;
command[3] = 0;
command[4] = 0;
iap_entry (command, result);
if (result[0] != 0) {
return (-1);
}
return (0);
}
/*
* Copy the saved sys_state parameters from the flash memory into RAM.
*
* Return value (global):
* sys_state The system state structure is filled out from the saved flash location.
*/
void
read_state(void){
int i;
char *s_ptr, *d_ptr;
find_state_ptrs (); // Find the current system state structure.
s_ptr = (char *)current_sys_state;
d_ptr = (char *)&sys_state;
for (i = 0; i < sizeof(sys_state_t); i++) {
d_ptr = s_ptr;
}
}[/LEFT]
0 件の賞賛
返信
3 返答(返信)

1,040件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by frame on Wed Apr 18 05:36:02 MST 2012
This method basically works fine. We had used it with success for other controllers years ago.
You should only accept that your have (or might have) the following problems:

1.
The time for writing one block of data is hardly predictable. If it involves a block erase, it takes --much-- longer.

2.
You might get problem when trying to save under timing constraints, i.e. when the power of the device is switched off, and saving must be done with the remaining charge of capacitors.
With byte-erasable EEPROM, only one byte might getting corrupted. With this flash cycling method, you've got to deal with possibly corrupted blocks.
0 件の賞賛
返信

1,040件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gopikrishnan47 on Tue Apr 17 23:11:40 MST 2012
Could you please provide the full project for LPCXpresso-> LPC11C24.
0 件の賞賛
返信

1,040件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by micrio on Sun Jun 26 06:01:36 MST 2011
I had to cut off the last and perhaps the most important routine to get
under the 10,000 character posting limit. Anyway here it is.

Pete.



/*
* Find the newest system state entry in the flash.
* Find the first free system state entry.
* If free_sys_state is set to NULL then the sector is full and needs to be erased.
* The last page of flash memory is used for parameter saving.
*
* Parameters:
* num_pages The total number of pages of flash memory.
*
* Return values (global):
* current_sys_state The current saved system state structure.
* free_sys_state The next available system state structure.
*/
void
find_state_ptrs () {
int i, j;
char *flash_blk_ptr;
sys_state_t *flash_state_ptr;
current_sys_state = 0; // Flag pointers as not found.
free_sys_state = 0;
/*
* First loop through each block in the sector.
*/
for (i = 0; i < BLOCKS_PER_SECTOR; i++) {
// Get the pointer to this block.
flash_blk_ptr = (char *)((num_pages - 1) * 0x1000) + (i * FLASH_BLOCK_SIZE);
/*
* Within each block loop through each sys_state structure.
*/
for (j = 0; j < STRUCTS_PER_BLOCK; j++) {
// Get the pointer to this sys_state structure.
flash_state_ptr = (sys_state_t *)(flash_blk_ptr + (j * sizeof(sys_state_t)));
// Is this structure empty? That is filled with FF's.
// This depends on FF being an illegal value in normal operation.
if (flash_state_ptr->vert_cursor_pos == -1) {
free_sys_state = flash_state_ptr; // We found an empty state structure.
return;
}
// This state structure is used.
current_sys_state = flash_state_ptr;
}
}
}
0 件の賞賛
返信