cancel
Showing results for 
Search instead for 
Did you mean: 

EEPROM emulation in STM32F4x family

harinath
Associate III
Posted on July 29, 2014 at 08:32

I have come across the following ST application note and sample.

http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/CD00165693.pdf

I guess this works for STM32F4x family too, am I correct ?

#eeprom-emulation
12 REPLIES 12
harinath
Associate III
Posted on August 02, 2014 at 09:55

Read the STM32F40xxx and STM32F41xxxFlash programming manual (PM0081)

Page 13 helped me to do the following modifications. It works now 🙂. Hope this helps others. Flush the caches ( Instruction, Data ) by setting DCRST and ICRST bits in FLASH_CR register. Again, restore the old settings. Introduced code into

EE_PageTransfer

function is

/* Flush the caches by setting the DCRST and ICRST bits in the FLASH_CR register.
Note: The I/D cache should be flushed only when it is disabled (I/DCEN = 0).*/
FLASH->ACR &= ~(FLASH_ACR_ICEN |FLASH_ACR_DCEN);
FLASH->ACR = (FLASH_ACR_ICRST |FLASH_ACR_DCRST); 
/* Now restore ( Enable I/D caches, clear the DCRST and ICRST bits */
FLASH->ACR = (FLASH_ACR_ICEN |FLASH_ACR_DCEN);
FLASH->ACR = ~(FLASH_ACR_ICRST |FLASH_ACR_DCRST);


static
uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data)

{

FLASH_Status FlashStatus = FLASH_COMPLETE;

uint32_t NewPageAddress = EEPROM_START_ADDRESS;

uint16_t OldPageId=0;

uint16_t ValidPage = PAGE0, VarIdx = 0;

uint16_t EepromStatus = 0, ReadStatus = 0;


/* Get active Page for read operation */

ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);


if
(ValidPage == PAGE1) 
/* Page1 valid */

{

/* New page address where variable will be moved to */

NewPageAddress = PAGE0_BASE_ADDRESS;


/* Old page ID where variable will be taken from */

OldPageId = PAGE1_ID;

}

else
if
(ValidPage == PAGE0) 
/* Page0 valid */

{

/* New page address where variable will be moved to */

NewPageAddress = PAGE1_BASE_ADDRESS;


/* Old page ID where variable will be taken from */

OldPageId = PAGE0_ID;

}

else

{

return
NO_VALID_PAGE; 
/* No valid Page */

}


/* Set the new Page status to RECEIVE_DATA status */

FlashStatus = FLASH_ProgramHalfWord(NewPageAddress, RECEIVE_DATA);

/* If program operation was failed, a Flash error code is returned */

if
(FlashStatus != FLASH_COMPLETE)

{

return
FlashStatus;

}


/* Write the variable passed as parameter in the new active page */

EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddress, Data);

/* If program operation was failed, a Flash error code is returned */

if
(EepromStatus != FLASH_COMPLETE)

{

return
EepromStatus;

}


/* Transfer process: transfer variables from old to the new active page */

for
(VarIdx = 0; VarIdx < NB_OF_VAR; VarIdx++)

{

if
(VirtAddVarTab[VarIdx] != VirtAddress) 
/* Check each variable except the one passed as parameter */

{

/* Read the other last variable updates */

ReadStatus = EE_ReadVariable(VirtAddVarTab[VarIdx], &DataVar);

/* In case variable corresponding to the virtual address was found */

if
(ReadStatus != 0x1)

{

/* Transfer the variable to the new active page */

EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddVarTab[VarIdx], DataVar);

/* If program operation was failed, a Flash error code is returned */

if
(EepromStatus != FLASH_COMPLETE)

{

return
EepromStatus;

}

}

}

}




/* Erase the old Page: Set old Page status to ERASED status */

FlashStatus = FLASH_EraseSector(OldPageId, VOLTAGE_RANGE);

/* If erase operation was failed, a Flash error code is returned */

if
(FlashStatus != FLASH_COMPLETE)

{

return
FlashStatus;

}


/* Set new Page status to VALID_PAGE status */

FlashStatus = FLASH_ProgramHalfWord(NewPageAddress, VALID_PAGE);

/* If program operation was failed, a Flash error code is returned */

if
(FlashStatus != FLASH_COMPLETE)

{

return
FlashStatus;

}

/* Flush the caches by setting the DCRST and ICRST bits in the FLASH_CR register.

Note: The I/D cache should be flushed only when it is disabled (I/DCEN = 0).*/

FLASH->ACR &= ~(FLASH_ACR_ICEN |FLASH_ACR_DCEN);

FLASH->ACR = (FLASH_ACR_ICRST |FLASH_ACR_DCRST); 

/* Now restore ( Enable I/D caches, clear the DCRST and ICRST bits */

FLASH->ACR = (FLASH_ACR_ICEN |FLASH_ACR_DCEN);

FLASH->ACR = ~(FLASH_ACR_ICRST |FLASH_ACR_DCRST);

/* Return last operation flash status */

return
FlashStatus;

}

clive1, thanks for watching my thread constantly ( I always expected something from you). people here have a great respect for you. Good day. Now, I will try to code the same using STM32cube library package( hope to see ST sample).
harinath
Associate III
Posted on August 03, 2014 at 07:00

Just finished porting this sample for STM32cube library package. It works without the fix proposed above.

info239955_stm1_st
Associate II
Posted on February 10, 2016 at 23:47

Hi guys,

thanks for the great information you were sharing in this post!

So, I just also want to share some maybe useful informations regarding the ST EEPROM-emulation:

1. some hints to the old version (''standalone'' solution, based on STSW-STM32066):

Here I encountered the problem that every time my code was calling the EE_INIT() function on startup this function was completely erasing the page which was already marked as ERASED.

This erase process takes more than 1 second for my 128k page (I used sectors 10 and 11).

But besides that timing issue, I encountered that when loosing power while the erase process was ongoing, the next time I started the code and invoked EE_INIT(), this routineformats both pages because the erase process seems to set all bits to 0 and then backwards to 1 for the whole page which can leave the page in the state VALID.

So when interrupted the erased page had a lot of 0s at the beginning and 1s at the end! In this way this page was marked as VALID (0000) and so EE_INIT() get confused with two valid pages and formatted the whole EEPROM memory...

2. some hints on an error on the new version from the STM32Cube:

Here they implemented a new funtionality called ''EE_VerifyPageFullyErased'' to overcome the problem described before, so that is great. But anyway - it seems to me that this function just seems to work for Page0, but not for Page1:

So I think you should keep that in mind and correct the code when using this functionality...

best regards, Markus See attachments for some more details...

________________

Attachments :

STM32-EEPROM-Case1.pdf : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I1GM&d=%2Fa%2F0X0000000bkS%2FOndQ7lUtS1loCIvxYEu2fsLExik.Q9CfpUqrbyHOSac&asPdf=false

STM32-EEPROM-Case2.pdf : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I1GH&d=%2Fa%2F0X0000000bkR%2F1F7KaV35U9alHduvSbp7pzd3AHTVYAXmqrCEMpf7308&asPdf=false