/**
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ file EEPROM_Emul / Core / eeprom_emul . c
* @ author MCD Application Team
* @ brief This file provides all the EEPROM emulation firmware functions .
@ verbatim
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# #### How to use this driver #####
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[ . . ]
This driver provides functions to initialize EEPROM emulation , to read and
write EEPROM variables , and to cleanup FLASH pages used by EEPROM emulation .
( # ) EEPROM emulation initialization functions :
( + + ) Format the FLASH pages used by EEPROM emulation using EE_Format ( ) .
This function is optionally used , it can be called the very first
time EEPROM emulation is used , to prepare FLASH pages for EEPROM
emulation with empty EEPROM variables . It can also be called at
any time , to flush all EEPROM variables .
( + + ) Initialize EEPROM emulation , and restore the FLASH pages used by
EEPROM emulation to a known good state in case of power loss
using EE_Init ( ) . It must be performed at system start up .
( # ) EEPROM variables access functions :
( + + ) Write EEPROM variable using EE_WriteVariableXbits ( ) functions
A Clean Up request can be raised as return parameter in case
FLASH pages used by EEPROM emulation , are full .
( + + ) Read EEPROM variable using EE_ReadVariableXbits ( ) functions
( # ) Clean up functions of FLASH pages , used by EEPROM emulation :
( + + ) There Two modes of erasing :
( + + + ) Polling mode using EE_CleanUp ( ) function
( + + + ) Interrupt mode using EE_CleanUp_IT ( ) function
( + + ) Callback function called when the clean up operation in interrupt
mode , is finished : EE_EndOfCleanup_UserCallback ( )
@ endverbatim
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ attention
*
* < h2 > < center > & copy ; Copyright ( c ) 2020 STMicroelectronics .
* All rights reserved . < / center > < / h2 >
*
* This software component is licensed by ST under BSD 3 - Clause license ,
* the " License " ; You may not use this file except in compliance with the
* License . You may obtain a copy of the License at :
* opensource . org / licenses / BSD - 3 - Clause
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
/* Includes ------------------------------------------------------------------*/
# include "eeprom_emul.h"
/**
* @ brief EE Find Type structure definition .
*/
/* Type of find requested :
READ - - > page in active state
WRITE - - > page in receive state or active state
ERASE - - > page in erased state */
typedef enum {
FIND_READ_PAGE ,
FIND_WRITE_PAGE ,
FIND_ERASE_PAGE
} EE_Find_type ;
/**
* @ brief EE State Type structure definition .
*/
/* Type of state requested :
ERASED - - > page is erased
RECEIVE - - > page used during data transfer when no more space available in the system
ACTIVE - - > page contains valid data and is not full
VALID - - > page contains valid data and is full
ERASING - - > page used during transfer , should be erased after transfer
INVALID - - > page invalid state */
typedef enum {
STATE_PAGE_ERASED ,
STATE_PAGE_RECEIVE ,
STATE_PAGE_ACTIVE ,
STATE_PAGE_VALID ,
STATE_PAGE_ERASING ,
STATE_PAGE_INVALID
} EE_State_type ;
/**
* @ brief EE Transfer Type structure definition .
*/
/* Definition of the different type of page transfer
NORMAL - > copy data page source to page destination
RECOVER - > resume page transfer that has been interrupted */
typedef enum {
EE_TRANSFER_NORMAL ,
EE_TRANSFER_RECOVER
} EE_Transfer_type ;
/**
* @ brief EE State Reliability structure definition .
*/
/* Reliability of page state:
RELIABLE - > header of page is not corrupted , state is reliable
CORRUPTED - > header of page is corrupted , state is corrupted */
typedef enum {
STATE_RELIABLE ,
STATE_CORRUPTED
} EE_State_Reliability ;
/**
* @ }
*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup EEPROM_Private_Variables EEPROM Private Variables
* @ {
*/
/* Global variables used to store eeprom status */
uint16_t uhNbWrittenElements = 0U ; /*!< Nb of elements written in valid and active pages */
uint8_t ubCurrentActivePage = 0U ; /*!< Current active page (can be active or receive state) */
uint32_t uwAddressNextWrite = PAGE_HEADER_SIZE ; /*!< Initialize write position just after page header */
/* During the cleanup phase in EE_Init, AddressRead is the address being read */
__IO uint32_t AddressRead = 0 ;
/* Flag equal to 1 when the cleanup phase is in progress, 0 if not */
__IO uint8_t CleanupPhase = 0 ;
/**
* @ }
*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup EEPROM_Private_Functions EEPROM Private Functions
* @ {
*/
static EE_Status ReadVariable ( uint16_t VirtAddress , EE_DATA_TYPE * pData ) ;
static EE_Status WriteVariable ( uint16_t VirtAddress , EE_DATA_TYPE Data ) ;
static EE_Status PagesTransfer ( uint16_t VirtAddress , EE_DATA_TYPE Data , EE_Transfer_type type ) ;
uint16_t CalculateCrc ( EE_DATA_TYPE Data , uint16_t VirtAddress ) ;
static EE_Status VerifyPageFullyErased ( uint32_t Address , uint32_t PageSize ) ;
static uint32_t FindPage ( EE_Find_type Operation ) ;
static EE_Status VerifyPagesFullWriteVariable ( uint16_t VirtAddress , EE_DATA_TYPE Data ) ;
static EE_Status SetPageState ( uint32_t Page , EE_State_type State ) ;
static EE_State_type GetPageState ( uint32_t Address ) ;
void ConfigureCrc ( void ) ;
bool EE_NMI_Callback ( )
{
if ( CleanupPhase ) {
EE_DeleteCorruptedFlashAddress ( AddressRead ) ;
return true ;
}
return false ;
}
/**
* @ }
*/
/* Exported functions -------------------------------------------------------*/
/** @addtogroup EEPROM_Exported_Functions
* @ {
*/
/**
* @ brief Restore the pages to a known good state in case of power loss .
* If a page is in RECEIVE state , resume transfer .
* Then if some pages are ERASING state , erase these pages .
* @ param EraseType : Type of erase to apply on page requiring to be erased .
* This parameter can be one of the following values :
* @ arg @ ref EE_FORCED_ERASE pages to erase are erased unconditionnally
* @ arg @ ref EE_CONDITIONAL_ERASE pages to erase are erased only if not fully erased
* @ retval EE_Status
* - EE_OK in case of success
* - EE error code in case of error
*/
EE_Status EE_Init ( EE_Erase_type EraseType )
{
EE_State_type pagestatus = STATE_PAGE_INVALID ;
uint32_t page = 0U , pageaddress = 0U , varidx = 0U ,
nbactivepage = 0U , nbactivereceivepage = 0U , nbvalidpage = 0U ,
lastvalidpage = 0U , firstvalidpage = 0U ,
recoverytransfer = 0U ;
EE_ELEMENT_TYPE addressvalue = 0U ;
EE_State_Reliability pagestate = STATE_RELIABLE ;
EE_Status status = EE_OK ;
/***************************************************************************/
/* Step 0: Perform initial configuration */
/***************************************************************************/
/* Configure CRC peripheral for eeprom emulation usage */
ConfigureCrc ( ) ;
/***************************************************************************/
/* Step 1: Read all lines of the flash pages of eeprom emulation to */
/* delete corrupted lines detectable through NMI */
/***************************************************************************/
/* We set the flag indicating the cleanup phase is operating to 1 */
CleanupPhase = 1 ;
for ( page = START_PAGE ; page < ( START_PAGE + PAGES_NUMBER ) ; page + + ) {
pageaddress = PAGE_ADDRESS ( page ) ;
for ( varidx = 0U ; varidx < PAGE_SIZE ; varidx + = EE_ELEMENT_SIZE ) {
/*
During the cleanup phase and only during it ,
we save the address read to set its content to 0 in case it triggered an NMI ( see NMI_Handler in stm32lxxx_it . c ) .
In the rest of the program , we do nothing in case a NMI is triggers by a reading because no NMI should be triggered
since we have cleanup the EEPROM emulated . By the way , there is still the CRC code associated to each EEPROM line
that allows to verify its valid state .
*/
AddressRead = pageaddress + varidx ;
addressvalue = ( * ( __IO EE_ELEMENT_TYPE * ) ( pageaddress + varidx ) ) ;
}
}
/* We set the flag indicating the cleanup phase is operating to 0 because it just ended */
CleanupPhase = 0 ;
/***************************************************************************/
/* Step 2: Handle case of reset during transfer with no receive page */
/* present, by setting missing receive page state */
/***************************************************************************/
/* Check if no active page and no receive page present */
/* Browse all pages */
for ( page = START_PAGE ; page < ( START_PAGE + PAGES_NUMBER ) ; page + + ) {
pageaddress = PAGE_ADDRESS ( page ) ;
pagestatus = GetPageState ( pageaddress ) ;
/* Search for active and receive page */
if ( ( pagestatus = = STATE_PAGE_ACTIVE ) | | ( pagestatus = = STATE_PAGE_RECEIVE ) ) {
nbactivereceivepage + + ;
}
/* Keep index of first valid page, and last valid page */
else if ( pagestatus = = STATE_PAGE_VALID ) {
if ( nbvalidpage = = 0U ) {
firstvalidpage = page ;
}
lastvalidpage = page ;
nbvalidpage + + ;
}
}
/* Check if no active and no receive page have been detected */
if ( nbactivereceivepage = = 0U ) {
/* Check if valid pages have been detected */
if ( nbvalidpage > 0U ) {
/* Check state of page just before first valid page.
If it is erasing page , then page after last valid page shall be set
to receiving state */
if ( GetPageState ( PAGE_ADDRESS ( PREVIOUS_PAGE ( firstvalidpage ) ) ) = = STATE_PAGE_ERASING ) {
if ( SetPageState ( FOLLOWING_PAGE ( lastvalidpage ) , STATE_PAGE_RECEIVE ) ! = EE_OK ) {
return EE_WRITE_ERROR ;
}
}
}
/* Format flash pages used for eeprom emulation in case no active, no receive, no valid pages are found */
else {
return EE_Format ( EE_FORCED_ERASE ) ;
}
}
/*********************************************************************/
/* Step 3: Handle case of reset during transfer, by performing */
/* transfer recovery */
/*********************************************************************/
/* Browse all pages */
for ( page = START_PAGE ; page < ( START_PAGE + PAGES_NUMBER ) ; page + + ) {
pageaddress = PAGE_ADDRESS ( page ) ;
pagestatus = GetPageState ( pageaddress ) ;
/* Check if there is receive page, meaning transfer has been interrupted */
if ( pagestatus = = STATE_PAGE_RECEIVE ) {
/* Verify that receive page is a true one, not a corrupted page state */
/* Check if page is not the first page of a bloc */
if ( ( page ! = START_PAGE ) & & ( page ! = ( uint32_t ) ( START_PAGE + ( PAGES_NUMBER / 2U ) ) ) ) {
/* Check that previous page is valid state */
if ( GetPageState ( PAGE_ADDRESS ( PREVIOUS_PAGE ( page ) ) ) = = STATE_PAGE_VALID ) {
/* The receive page is a true receive page */
pagestate = STATE_RELIABLE ;
} else /* Previous page is not valid state */
{
/* The receive page is false receive page due to header corruption */
pagestate = STATE_CORRUPTED ;
}
} else /* The receive page is the first page of a bloc */
{
/* Check that following page is erased state */
if ( GetPageState ( PAGE_ADDRESS ( FOLLOWING_PAGE ( page ) ) ) = = STATE_PAGE_ERASED ) {
/* The receive page is a true receive page */
pagestate = STATE_RELIABLE ;
} else /* Following page is not erased state */
{
/* The receive page is false receive page due to header corruption */
pagestate = STATE_CORRUPTED ;
}
}
/* If the receive page is a true receive page, resume pages transfer */
if ( pagestate = = STATE_RELIABLE ) {
/* Initialize current active page */
ubCurrentActivePage = page ;
/* Resume the interrupted page transfer, using dummy new data */
if ( PagesTransfer ( 0U , 0U , EE_TRANSFER_RECOVER ) ! = EE_CLEANUP_REQUIRED ) {
return EE_TRANSFER_ERROR ;
}
/* Memorize transfer recovery occured */
recoverytransfer = 1U ;
/* transfer recovery is done, then stop searching receive page */
break ;
}
}
}
/*********************************************************************/
/* Step 4: Verify presence of one unique active page */
/* If more than one active page, raise error */
/* If no active page present, set missing active page */
/*********************************************************************/
/* Browse all pages to search for active pages */
nbactivepage = 0U ;
for ( page = START_PAGE ; page < ( START_PAGE + PAGES_NUMBER ) ; page + + ) {
pageaddress = PAGE_ADDRESS ( page ) ;
pagestatus = GetPageState ( pageaddress ) ;
/* Search for active page */
if ( pagestatus = = STATE_PAGE_ACTIVE ) {
/* Verify that active page is a true one, not a corrupted page state */
/* Check if page is not the first page of a bloc */
if ( ( page ! = START_PAGE ) & & ( page ! = ( uint32_t ) ( START_PAGE + ( PAGES_NUMBER / 2U ) ) ) ) {
/* Check that previous page is valid state */
if ( GetPageState ( PAGE_ADDRESS ( PREVIOUS_PAGE ( page ) ) ) = = STATE_PAGE_VALID ) {
/* The active page is a true active page */
pagestate = STATE_RELIABLE ;
} else /* Previous page is not valid state */
{
/* The active page is false active page due to header corruption */
pagestate = STATE_CORRUPTED ;
}
} else /* The active page is the first page of a bloc */
{
/* Check that following page is erased state */
if ( GetPageState ( PAGE_ADDRESS ( FOLLOWING_PAGE ( page ) ) ) = = STATE_PAGE_ERASED ) {
/* The active page is a true active page */
pagestate = STATE_RELIABLE ;
} else /* Following page is not erased state */
{
/* The active page is false active page due to header corruption */
pagestate = STATE_CORRUPTED ;
}
}
/* If the active page is a true active page, initialize global variables */
if ( pagestate = = STATE_RELIABLE ) {
if ( nbactivepage = = 0U ) {
ubCurrentActivePage = page ;
nbactivepage + + ;
} else {
/* Error: More than one reliable active page is present */
return EE_INVALID_PAGE_SEQUENCE ;
}
}
}
/* Keep index of last valid page, will be required in case no active page is found */
else if ( pagestatus = = STATE_PAGE_VALID ) {
lastvalidpage = page ;
}
}
/* In case no active page is found, set page after last valid page to active state */
if ( nbactivepage = = 0U ) {
ubCurrentActivePage = FOLLOWING_PAGE ( lastvalidpage ) ;
if ( SetPageState ( ubCurrentActivePage , STATE_PAGE_ACTIVE ) ! = EE_OK ) {
return EE_WRITE_ERROR ;
}
}
/*********************************************************************/
/* Step 5: Initialize eeprom emulation global variables relative */
/* to active page */
/*********************************************************************/
/* Initialize global variables, with elements detected in active page */
uhNbWrittenElements = 0U ;
uwAddressNextWrite = PAGE_HEADER_SIZE ;
for ( varidx = PAGE_HEADER_SIZE ; varidx < PAGE_SIZE ; varidx + = EE_ELEMENT_SIZE ) {
/* Check elements present in active page */
addressvalue = ( * ( __IO EE_ELEMENT_TYPE * ) ( PAGE_ADDRESS ( ubCurrentActivePage ) + varidx ) ) ;
if ( addressvalue ! = EE_MASK_FULL )
{
/* Then increment uhNbWrittenElements and uwAddressNextWrite */
uhNbWrittenElements + + ;
uwAddressNextWrite + = EE_ELEMENT_SIZE ;
} else /* no more element in the page */
{
break ;
}
}
/*********************************************************************/
/* Step 6: Finalize eeprom emulation global variables relative */
/* to valid pages, and check consistency of pages sequence */
/*********************************************************************/
/* Check consistency of pages sequence: one active page, optionnally some valid pages before */
/* Update global variable uhNbWrittenElements if valid pages are found */
page = ubCurrentActivePage ;
firstvalidpage = ubCurrentActivePage ;
while ( ( page ! = START_PAGE ) & & ( page ! = ( uint32_t ) ( START_PAGE + ( PAGES_NUMBER / 2U ) ) ) ) {
/* Decrement page index among circular pages list */
page = PREVIOUS_PAGE ( page ) ;
pagestatus = GetPageState ( PAGE_ADDRESS ( page ) ) ;
/* Check if page is valid state */
if ( pagestatus = = STATE_PAGE_VALID ) {
/* Update uhNbWrittenElements with number of elements in full page */
uhNbWrittenElements + = NB_MAX_ELEMENTS_BY_PAGE ;
/* Keep index of first valid page */
firstvalidpage = page ;
} else {
/* Error: Pages sequence is not consistent */
return EE_INVALID_PAGE_SEQUENCE ;
}
}
/*********************************************************************/
/* Step 7: Ensure empty pages are erased */
/*********************************************************************/
/* Ensure all pages after active page, until first valid page, are erased */
page = FOLLOWING_PAGE ( ubCurrentActivePage ) ;
pageaddress = PAGE_ADDRESS ( page ) ;
while ( page ! = firstvalidpage ) {
/* Check if page erase has to be forced unconditionally (default case) */
if ( EraseType = = EE_FORCED_ERASE ) {
/* Force page erase independently of its content */
if ( FI_PageErase ( page , 1U ) ! = EE_OK ) {
return EE_ERASE_ERROR ;
}
} else /* EraseType == EE_CONDITIONAL_ERASE */
{
/* Check if page is fully erased */
if ( VerifyPageFullyErased ( pageaddress , PAGE_SIZE ) = = EE_PAGE_NOTERASED ) {
/* Erase pages if not fully erased */
if ( FI_PageErase ( page , 1U ) ! = EE_OK ) {
return EE_ERASE_ERROR ;
}
}
}
/* Increment page index among circular pages list, to get first page to erased */
page = FOLLOWING_PAGE ( page ) ;
pageaddress = PAGE_ADDRESS ( page ) ;
}
/* To keep their coherency, flush the caches if needed depending on the product */
FI_CacheFlush ( ) ;
/*********************************************************************/
/* Step 8: Perform dummy write '0' to get rid of potential */
/* instability of line value 0xFFFFFFFF consecutive to a */
/* reset during write here */
/* Only needed if recovery transfer did not occured */
/*********************************************************************/
if ( recoverytransfer = = 0U ) {
status = VerifyPagesFullWriteVariable ( 0U , 0U ) ;
// The dummy write can be skipped in case pages are full
// because in this case potential instability can not happen
if ( ( status ! = EE_OK ) & & ( status ! = EE_PAGE_FULL ) ) {
return EE_WRITE_ERROR ;
}
}
return EE_OK ;
}
/**
* @ brief Erases all flash pages of eeprom emulation , and set first page
* header as ACTIVE .
* @ note This function can be called the very first time eeprom emulation is
* used , to prepare flash pages for eeprom emulation with empty eeprom
variables . It can also be called at any time , to flush all eeprom
* variables .
* @ param EraseType : Type of erase to apply on page requiring to be erased .
* This parameter can be one of the following values :
* @ arg @ ref EE_FORCED_ERASE pages to erase are erased unconditionnally
* @ arg @ ref EE_CONDITIONAL_ERASE pages to erase are erased only if not fully erased
* @ retval EE_Status
* - EE_OK : on success
* - EE error code : if an error occurs
*/
EE_Status EE_Format ( EE_Erase_type EraseType )
{
uint32_t page = 0U ;
/* Erase All Pages */
for ( page = START_PAGE ; page < ( START_PAGE + PAGES_NUMBER ) ; page + + ) {
/* Check if page erase has to be forced unconditionally (default case) */
if ( EraseType = = EE_FORCED_ERASE ) {
/* Force page erase independently of its content */
if ( FI_PageErase ( page , 1U ) ! = EE_OK ) {
return EE_ERASE_ERROR ;
}
} else /* EraseType == EE_CONDITIONAL_ERASE */
{
/* Check if Page is not yet fully erased */
if ( VerifyPageFullyErased ( PAGE_ADDRESS ( page ) , PAGE_SIZE ) = = EE_PAGE_NOTERASED ) {
/* Erase the page */
/* If Erase operation was failed, a Flash error code is returned */
if ( FI_PageErase ( page , 1U ) ! = EE_OK ) {
return EE_ERASE_ERROR ;
}
}
}
}
/* To keep their coherency, flush the caches if needed depending on the product */
FI_CacheFlush ( ) ;
/* Set first Page in Active State */
/* If program operation was failed, a Flash error code is returned */
if ( SetPageState ( START_PAGE , STATE_PAGE_ACTIVE ) ! = EE_OK ) {
return EE_WRITE_ERROR ;
}
/* Reset global variables */
uhNbWrittenElements = ( uint16_t ) 0U ;
ubCurrentActivePage = START_PAGE ;
uwAddressNextWrite = PAGE_HEADER_SIZE ; /* Initialize write position just after page header */
return EE_OK ;
}
/**
* @ brief Returns the last stored variable data , if found , which correspond to
* the passed virtual address
* @ param VirtAddress Variable virtual address on 16 bits ( can ' t be 0x0000 or 0xFFFF )
* @ param pData Variable containing the 32 bits read variable value
* @ retval EE_Status
* - EE_OK : if variable was found
* - EE error code : if an error occurs
*/
EE_Status EE_ReadVariable32bits ( uint16_t VirtAddress , uint32_t * pData )
{
if ( ( VirtAddress ! = 0x0000 ) & & ( VirtAddress ! = 0xFFFF ) ) {
EE_DATA_TYPE datatmp = 0U ;
EE_Status status = EE_OK ;
/* Read variable of size EE_DATA_TYPE, then cast it to 32bits */
status = ReadVariable ( VirtAddress , & datatmp ) ;
* pData = ( uint32_t ) datatmp ;
return status ;
} else {
return EE_INVALID_VIRTUALADDRESS ;
}
}
/**
* @ brief Returns the last stored variable data , if found , which correspond to
* the passed virtual address
* @ param VirtAddress Variable virtual address on 16 bits ( can ' t be 0x0000 or 0xFFFF )
* @ param pData Variable containing the 16 bits read variable value
* @ retval EE_Status
* - EE_OK : if variable was found
* - EE error code : if an error occurs
*/
EE_Status EE_ReadVariable16bits ( uint16_t VirtAddress , uint16_t * pData )
{
if ( ( VirtAddress ! = 0x0000 ) & & ( VirtAddress ! = 0xFFFF ) ) {
EE_DATA_TYPE datatmp = 0U ;
EE_Status status = EE_OK ;
/* Read variable of size EE_DATA_TYPE, then cast it to 16bits */
status = ReadVariable ( VirtAddress , & datatmp ) ;
* pData = ( uint16_t ) datatmp ;
return status ;
} else {
return EE_INVALID_VIRTUALADDRESS ;
}
}
/**
* @ brief Returns the last stored variable data , if found , which correspond to
* the passed virtual address
* @ param VirtAddress Variable virtual address on 16 bits ( can ' t be 0x0000 or 0xFFFF )
* @ param pData Variable containing the 8 bits read variable value
* @ retval EE_Status
* - EE_OK : if variable was found
* - EE error code : if an error occurs
*/
EE_Status EE_ReadVariable8bits ( uint16_t VirtAddress , uint8_t * pData )
{
if ( ( VirtAddress ! = 0x0000 ) & & ( VirtAddress ! = 0xFFFF ) ) {
EE_DATA_TYPE datatmp = 0U ;
EE_Status status = EE_OK ;
/* Read variable of size EE_DATA_TYPE, then cast it to 8bits */
status = ReadVariable ( VirtAddress , & datatmp ) ;
* pData = ( uint8_t ) datatmp ;
return status ;
} else {
return EE_INVALID_VIRTUALADDRESS ;
}
}
/**
* @ brief Writes / updates variable data in EEPROM .
* Trig internal Pages transfer if half of the pages are full .
* @ warning This function is not reentrant
* @ param VirtAddress Variable virtual address on 16 bits ( can ' t be 0x0000 or 0xFFFF )
* @ param Data 32 bits data to be written
* @ retval EE_Status
* - EE_OK : on success
* - EE_CLEANUP_REQUIRED : success and user has to trig flash pages cleanup
* - EE error code : if an error occurs
*/
EE_Status EE_WriteVariable32bits ( uint16_t VirtAddress , uint32_t Data )
{
if ( ( VirtAddress ! = 0x0000 ) & & ( VirtAddress ! = 0xFFFF ) ) {
return WriteVariable ( VirtAddress , ( EE_DATA_TYPE ) Data ) ;
} else {
return EE_INVALID_VIRTUALADDRESS ;
}
}
/**
* @ brief Writes / updates variable data in EEPROM .
* Trig internal Pages transfer if half of the pages are full .
* @ warning This function is not reentrant
* @ param VirtAddress Variable virtual address on 16 bits ( can ' t be 0x0000 or 0xFFFF )
* @ param Data 16 bits data to be written
* @ retval EE_Status
* - EE_OK : on success
* - EE_CLEANUP_REQUIRED : success and user has to trig flash pages cleanup
* - EE error code : if an error occurs
*/
EE_Status EE_WriteVariable16bits ( uint16_t VirtAddress , uint16_t Data )
{
if ( ( VirtAddress ! = 0x0000 ) & & ( VirtAddress ! = 0xFFFF ) ) {
return WriteVariable ( VirtAddress , ( EE_DATA_TYPE ) Data ) ;
} else {
return EE_INVALID_VIRTUALADDRESS ;
}
}
/**
* @ brief Writes / updates variable data in EEPROM .
* Trig internal Pages transfer if half of the pages are full .
* @ warning This function is not reentrant
* @ param VirtAddress Variable virtual address on 16 bits ( can ' t be 0x0000 or 0xFFFF )
* @ param Data 8 bits data to be written
* @ retval EE_Status
* - EE_OK : on success
* - EE_CLEANUP_REQUIRED : success and user has to trig flash pages cleanup
* - EE error code : if an error occurs
*/
EE_Status EE_WriteVariable8bits ( uint16_t VirtAddress , uint8_t Data )
{
if ( ( VirtAddress ! = 0x0000 ) & & ( VirtAddress ! = 0xFFFF ) ) {
return WriteVariable ( VirtAddress , ( EE_DATA_TYPE ) Data ) ;
} else {
return EE_INVALID_VIRTUALADDRESS ;
}
}
/**
* @ brief Erase group of pages which are erasing state , in polling mode .
* Could be either first half or second half of total pages number .
* @ note This function should be called when EE_WriteVariableXXbits has
* returned EE_CLEANUP_REQUIRED status ( and only in that case )
* @ retval EE_Status
* - EE_OK : in case of success
* - EE error code : if an error occurs
*/
EE_Status EE_CleanUp ( void )
{
uint32_t firstpage = 0U , page = 0U ;
uint32_t firstpageaddress = 0U , pageaddress = 0U ;
EE_State_type firstpagestatus = STATE_PAGE_INVALID , pagestatus = STATE_PAGE_INVALID ;
/* Check first half and second half page group */
for ( firstpage = START_PAGE ; firstpage < ( START_PAGE + PAGES_NUMBER ) ; firstpage + = ( PAGES_NUMBER / 2U ) ) {
/* Check status of first page of the group */
firstpageaddress = PAGE_ADDRESS ( firstpage ) ;
firstpagestatus = GetPageState ( firstpageaddress ) ;
/* If first page of the group is erasing state, check that all other pages
of the group are also erasing state */
if ( firstpagestatus = = STATE_PAGE_ERASING ) {
for ( page = ( firstpage + 1U ) ; page < ( firstpage + ( PAGES_NUMBER / 2U ) ) ; page + + ) {
pageaddress = PAGE_ADDRESS ( page ) ;
pagestatus = GetPageState ( pageaddress ) ;
/* If page is not erasing, return error */
if ( pagestatus ! = STATE_PAGE_ERASING ) {
return EE_ERROR_NOERASING_PAGE ;
}
}
/* Erase all the pages of the group */
/* If erase operation fails, a Flash error code is returned */
if ( FI_PageErase ( firstpage , PAGES_NUMBER / 2U ) ! = EE_OK ) {
return EE_ERASE_ERROR ;
} else {
/* To keep their coherency, flush the caches if needed depending on the product */
FI_CacheFlush ( ) ;
return EE_OK ;
}
}
}
/* Error if no erasing pages group is found */
return EE_ERROR_NOERASING_PAGE ;
}
/**
* @ brief Delete corrupted Flash address , can be called under NMI .
* @ param Address Address of the FLASH Memory to delete
* @ retval EE_Status
* - EE_OK : on success
* - EE error code : if an error occurs
*/
EE_Status EE_DeleteCorruptedFlashAddress ( uint32_t Address )
{
return FI_DeleteCorruptedFlashAddress ( Address ) ;
}
/**
* @ }
*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @ {
*/
/**
* @ brief Returns the last stored variable data , if found , which correspond to
* the passed virtual address
* @ param VirtAddress Variable virtual address on 16 bits ( can ' t be 0x0000 or 0xFFFF )
* @ param pData Variable containing the EE_DATA_TYPE read variable value
* @ retval EE_Status
* - EE_OK : if variable was found
* - EE error code : if an error occurs
*/
static EE_Status ReadVariable ( uint16_t VirtAddress , EE_DATA_TYPE * pData )
{
EE_ELEMENT_TYPE addressvalue = 0U ;
uint32_t page = 0U , pageaddress = 0U , counter = 0U , crc = 0U ;
EE_State_type pagestate = STATE_PAGE_INVALID ;
/* Get active Page for read operation */
page = FindPage ( FIND_READ_PAGE ) ;
/* Check if there is no active page */
if ( page = = EE_NO_PAGE_FOUND ) {
return EE_ERROR_NOACTIVE_PAGE ;
}
pageaddress = PAGE_ADDRESS ( page ) ;
pagestate = GetPageState ( pageaddress ) ;
/* Search variable in active page and valid pages until erased page is found
or in erasing pages until erased page is found */
while ( ( pagestate = = STATE_PAGE_ACTIVE ) | | ( pagestate = = STATE_PAGE_VALID ) | | ( pagestate = = STATE_PAGE_ERASING ) ) {
/* Set counter index to last element position in the page */
counter = PAGE_SIZE - EE_ELEMENT_SIZE ;
/* Check each page address starting from end */
while ( counter > = PAGE_HEADER_SIZE ) {
/* Get the current location content to be compared with virtual address */
addressvalue = ( * ( __IO EE_ELEMENT_TYPE * ) ( pageaddress + counter ) ) ;
if ( addressvalue ! = EE_PAGESTAT_ERASED ) {
/* Compare the read address with the virtual address */
if ( EE_VIRTUALADDRESS_VALUE ( addressvalue ) = = VirtAddress ) {
/* Calculate crc of variable data and virtual address */
crc = CalculateCrc ( EE_DATA_VALUE ( addressvalue ) , EE_VIRTUALADDRESS_VALUE ( addressvalue ) ) ;
/* if crc verification pass, data is correct and is returned.
if crc verification fails , data is corrupted and has to be skip */
if ( crc = = EE_CRC_VALUE ( addressvalue ) ) {
/* Get content of variable value */
* pData = EE_DATA_VALUE ( addressvalue ) ;
return EE_OK ;
}
}
}
/* Next address location */
counter - = EE_ELEMENT_SIZE ;
}
/* Decrement page index circularly, among pages allocated to eeprom emulation */
page = PREVIOUS_PAGE ( page ) ;
pageaddress = PAGE_ADDRESS ( page ) ;
pagestate = GetPageState ( pageaddress ) ;
}
/* Variable is not found */
return EE_NO_DATA ;
}
/**
* @ brief Writes / updates variable data in EEPROM
* Trig internal Pages transfer if half of the pages are full
* @ param VirtAddress Variable virtual address on 16 bits ( can ' t be 0x0000 or 0xFFFF )
* @ param Data EE_DATA_TYPE data to be written
* @ retval EE_Status
* - EE_OK : on success , without page transfer
* - EE_CLEANUP_REQUIRED : on success , with page transfer occured
* - EE_FLASH_USED : flash currently used by CPU2
* - EE error code : if an error occurs
*/
static EE_Status WriteVariable ( uint16_t VirtAddress , EE_DATA_TYPE Data )
{
EE_Status status = EE_OK ;
/* Write the variable virtual address and value in the EEPROM, if not full */
status = VerifyPagesFullWriteVariable ( VirtAddress , Data ) ;
if ( status = = EE_PAGE_FULL ) {
/* In case the EEPROM pages are full, perform Pages transfer */
return PagesTransfer ( VirtAddress , Data , EE_TRANSFER_NORMAL ) ;
}
/* Return last operation status */
return status ;
}
/**
* @ brief Verify if specified page is fully erased .
* @ param Address page address
* @ param PageSize page size
* @ retval EE_Status
* - EE_PAGE_NOTERASED : if Page not erased
* - EE_PAGE_ERASED : if Page erased
*/
static EE_Status VerifyPageFullyErased ( uint32_t Address , uint32_t PageSize )
{
EE_Status readstatus = EE_PAGE_ERASED ;
uint32_t counter = 0U ;
/* Check each element in the page */
while ( counter < PageSize ) {
/* Compare the read address with the virtual address */
if ( ( * ( __IO EE_ELEMENT_TYPE * ) ( Address + counter ) ) ! = EE_PAGESTAT_ERASED ) {
/* In case one element is not erased, reset readstatus flag */
readstatus = EE_PAGE_NOTERASED ;
}
/* Next address location */
counter = counter + EE_ELEMENT_SIZE ;
}
/* Return readstatus value */
return readstatus ;
}
/**
* @ brief Find suitable page for read / write / erase operation .
* It also update pages state if current page is full .
* And it force cleanup if all pages are full .
* @ param Operation Type of page to be requested .
* This parameter can be one of the following values :
* @ arg @ ref FIND_READ_PAGE return the active page index
* @ arg @ ref FIND_WRITE_PAGE return the write page index
* @ arg @ ref FIND_ERASE_PAGE return the erase page index
* @ retval Page_Index
* - Page Index : on success
* - @ ref EE_NO_PAGE_FOUND : if an error occurs
*/
static uint32_t FindPage ( EE_Find_type Operation )
{
EE_State_type currentpagestatus = STATE_PAGE_INVALID , followingpagestatus = STATE_PAGE_INVALID ;
uint32_t currentpage = 0U , followingpage = 0U , previouspage = 0U ;
/* Get currentpage status */
currentpage = ubCurrentActivePage ;
currentpagestatus = GetPageState ( PAGE_ADDRESS ( currentpage ) ) ;
/* Get followingpage status */
followingpage = FOLLOWING_PAGE ( currentpage ) ;
followingpagestatus = GetPageState ( PAGE_ADDRESS ( followingpage ) ) ;
/* Get previouspage status */
previouspage = PREVIOUS_PAGE ( currentpage ) ;
/* Write, read or erase operation */
switch ( Operation ) {
case FIND_WRITE_PAGE : /* ---- Write operation ---- */
/* Normal operation, no page transfer on going */
if ( currentpagestatus = = STATE_PAGE_ACTIVE ) {
/* Check if active page is not full */
if ( uwAddressNextWrite < PAGE_SIZE ) {
/* Return current Active page */
return currentpage ;
} else
/* No more space in current active page */
{
/* Check if following page is erasing state */
if ( followingpagestatus = = STATE_PAGE_ERASING ) {
/* Force Cleanup, as not yet performed by user */
if ( EE_CleanUp ( ) ! = EE_OK ) {
return EE_NO_PAGE_FOUND ;
}
}
/* Set current active page in valid state */
if ( SetPageState ( currentpage , STATE_PAGE_VALID ) ! = EE_OK ) {
return EE_NO_PAGE_FOUND ;
}
/* Set following page as active */
if ( SetPageState ( followingpage , STATE_PAGE_ACTIVE ) ! = EE_OK ) {
return EE_NO_PAGE_FOUND ;
}
uwAddressNextWrite = PAGE_HEADER_SIZE ; /* Skip page header */
return followingpage ; /* Following page is now active one */
}
}
/* Transfer is on going, page receiving data */
else {
if ( currentpagestatus = = STATE_PAGE_RECEIVE ) {
/* Check if receive page is not full */
if ( uwAddressNextWrite < PAGE_SIZE ) {
/* Return current receive page */
return currentpage ;
} else
/* No more space in current receive page */
{
/* Check if following page is erasing state */
if ( followingpagestatus = = STATE_PAGE_ERASING ) {
/* Force Cleanup, as not yet performed by user */
if ( EE_CleanUp ( ) ! = EE_OK ) {
return EE_NO_PAGE_FOUND ;
}
}
/* Set current receive page in valid state */
if ( SetPageState ( currentpage , STATE_PAGE_VALID ) ! = EE_OK ) {
return EE_NO_PAGE_FOUND ;
}
/* Set following page as receive */
if ( SetPageState ( followingpage , STATE_PAGE_RECEIVE ) ! = EE_OK ) {
return EE_NO_PAGE_FOUND ;
}
uwAddressNextWrite = PAGE_HEADER_SIZE ; /* Skip page header */
return followingpage ; /* Following page is now active one */
}
} else {
return EE_NO_PAGE_FOUND ; /* No active Page */
}
}
case FIND_READ_PAGE : /* ---- Read operation ---- */
if ( currentpagestatus = = STATE_PAGE_ACTIVE ) {
return currentpage ;
} else {
if ( currentpagestatus = = STATE_PAGE_RECEIVE ) {
return previouspage ;
} else {
return EE_NO_PAGE_FOUND ; /* No active Page */
}
}
case FIND_ERASE_PAGE : /* ---- Return the erased page */
if ( followingpagestatus = = STATE_PAGE_ERASED ) {
return followingpage ;
} else {
return EE_NO_PAGE_FOUND ; /* No erased Page */
}
default : ;
}
return EE_NO_PAGE_FOUND ;
}
/**
* @ brief Writes a new variable data in fresh new page in case of normal
* transfer , and transfers last updated elements from full pages to
* empty pages in any cases .
* @ param VirtAddress 16 bit virtual address of the new variable data
* @ param Data @ ref EE_DATA_TYPE data value of the new variable data
* @ param Type Type of transfer .
* This parameter can be one of the EE_Transfer_type enum values .
* @ arg @ ref EE_TRANSFER_NORMAL Pages transfer during normal processing
* @ arg @ ref EE_TRANSFER_RECOVER Recovering pages transfer at Init
* @ retval EE_Status
* - EE_CLEANUP_REQUIRED : on success
* - EE error code : if an error occurs
*/
static EE_Status PagesTransfer ( uint16_t VirtAddress , EE_DATA_TYPE Data , EE_Transfer_type Type )
{
EE_State_type pagestatus = STATE_PAGE_INVALID ;
uint32_t pageaddress = 0U ;
uint32_t page = 0U ;
uint32_t varidx = 0U ;
EE_ELEMENT_TYPE addressvalue = 0U ;
EE_Status status = EE_OK ;
EE_DATA_TYPE DataValue = 0U ;
/* Get receive Page for transfer operation */
page = FindPage ( ( Type = = EE_TRANSFER_NORMAL ? FIND_ERASE_PAGE : FIND_WRITE_PAGE ) ) ;
if ( page = = EE_NO_PAGE_FOUND ) {
return EE_ERROR_NOERASE_PAGE ;
}
/* Reinitialize number of data written in the pages, and current active page */
uhNbWrittenElements = 0U ;
ubCurrentActivePage = page ;
uwAddressNextWrite = PAGE_HEADER_SIZE ;
/* Mark the erased page at receive state in case of normal transfer */
/* It is already the case in recover transfer case */
/* If program operation was failed, a Flash error code is returned */
if ( Type = = EE_TRANSFER_NORMAL ) {
if ( SetPageState ( page , STATE_PAGE_RECEIVE ) ! = EE_OK ) {
return EE_WRITE_ERROR ;
}
}
/* Set the previous active page and all previous valid pages to erasing state */
/* In case of recover transfer, some of these pages may already be marked erasing */
page = PREVIOUS_PAGE ( page ) ;
pageaddress = PAGE_ADDRESS ( page ) ;
pagestatus = GetPageState ( pageaddress ) ;
if ( ( pagestatus = = STATE_PAGE_ACTIVE ) | | ( pagestatus = = STATE_PAGE_ERASING ) ) {
/* Set active page to erasing */
if ( pagestatus = = STATE_PAGE_ACTIVE ) {
if ( SetPageState ( page , STATE_PAGE_ERASING ) ! = EE_OK ) {
return EE_WRITE_ERROR ;
}
}
/* Inspect the previous pages to set all valid pages to erasing state */
/* In case of recover, some valid pages may be already erasing state */
page = PREVIOUS_PAGE ( page ) ;
pageaddress = PAGE_ADDRESS ( page ) ;
pagestatus = GetPageState ( pageaddress ) ;
while ( ( pagestatus = = STATE_PAGE_VALID ) | | ( pagestatus = = STATE_PAGE_ERASING ) ) {
/* Set valid page to erasing */
if ( pagestatus = = STATE_PAGE_VALID ) {
if ( SetPageState ( page , STATE_PAGE_ERASING ) ! = EE_OK ) {
return EE_WRITE_ERROR ;
}
}
/* decrement page index */
page = PREVIOUS_PAGE ( page ) ;
pageaddress = PAGE_ADDRESS ( page ) ;
pagestatus = GetPageState ( pageaddress ) ;
}
} else {
if ( ( Type = = EE_TRANSFER_RECOVER ) & & ( pagestatus = = STATE_PAGE_VALID ) ) {
/* This can happen in case of recover transfer. It indicates that previous */
/* transfer goes far enough to fill a complete receive page at least */
/* (valid state). Then erasing state marking was already completed */
} else {
/* Inconsistent previous page state */
return EE_INVALID_PAGE_SEQUENCE ;
}
}
/* In case of recover transfer, transfer must be resumed where it has been stopped */
/* Update global variables to reflect current transfer status */
if ( Type = = EE_TRANSFER_RECOVER ) {
/* Count number of elements already transferred in current receive page */
for ( varidx = PAGE_HEADER_SIZE ; varidx < PAGE_SIZE ; varidx + = EE_ELEMENT_SIZE ) {
/* Get next element in receive page */
addressvalue = ( * ( __IO EE_ELEMENT_TYPE * ) ( PAGE_ADDRESS ( ubCurrentActivePage ) + varidx ) ) ;
if ( addressvalue ! = EE_PAGESTAT_ERASED ) {
/* Update global variables accordingly */
uhNbWrittenElements + + ;
uwAddressNextWrite + = EE_ELEMENT_SIZE ;
} else {
break ;
}
}
/* Count number of elements already transferred in previous valid pages */
page = ubCurrentActivePage ;
for ( varidx = 0U ; varidx < PAGES_NUMBER ; varidx + + ) {
/* Decrement page index among circular pages list */
page = PREVIOUS_PAGE ( page ) ;
pagestatus = GetPageState ( PAGE_ADDRESS ( page ) ) ;
/* Check if page is valid state */
if ( pagestatus = = STATE_PAGE_VALID ) {
/* Update uhNbWrittenElements with number of elements in page */
uhNbWrittenElements + = NB_MAX_ELEMENTS_BY_PAGE ;
} else {
break ;
}
}
}
// Write the variable passed as parameter in the new active page
// If program operation was failed, a Flash error code is returned
if ( VerifyPagesFullWriteVariable ( VirtAddress , Data ) ! = EE_OK ) {
return EE_WRITE_ERROR ;
}
/* Transfer process: transfer variables from old to the new active page */
/* First element in receive page can be any one, the following elements are */
/* ordered from the beginning. */
/* In case of recovery, Pre-Last element in receive page could be */
/* corrupted if reset occured during write of this element, */
/* and last element is dummy value that we have just written. */
/* Transfer shall then resume from (uhNbWrittenElements-3) variable index */
for ( varidx = ( uhNbWrittenElements > = 3U ? ( uhNbWrittenElements - 3U + 1U ) : 1U ) ; varidx < NB_OF_VARIABLES + 1 ; varidx + + ) {
/* Check each variable except the one passed as parameter */
if ( varidx ! = VirtAddress ) {
/* Read the last variable updates */
status = ReadVariable ( varidx , & DataValue ) ;
if ( status = = EE_OK ) {
/* In case variable corresponding to the virtual address was found */
/* Transfer the variable to the new active page */
/* If program operation was failed, a Flash error code is returned */
status = VerifyPagesFullWriteVariable ( varidx , DataValue ) ;
if ( status ! = EE_OK ) {
return status ;
}
} else {
if ( status ! = EE_NO_DATA ) {
/* In case variable is not found , do nothing */
/* Any other status is error code occurs during variable read */
return status ;
}
}
}
}
/* Transfer is now done, mark the receive state page as active */
if ( SetPageState ( ubCurrentActivePage , STATE_PAGE_ACTIVE ) ! = EE_OK ) {
return EE_WRITE_ERROR ;
}
/* Return last operation flash status */
return EE_CLEANUP_REQUIRED ;
}
/**
* @ brief Verify if pages are full
* then if not the case , writes variable in EEPROM .
* @ param VirtAddress 16 bit virtual address of the variable
* @ param Data @ ref EE_DATA_TYPE data to be written as variable value
* @ param Write_type Type of writing on going ( see EE_Write_type )
* @ retval EE_Status
* - EE_OK : on success
* - EE_FULL : if half pages are full
* - EE_FLASH_USED : flash currently used by CPU2
* - EE error code : if an error occurs
*/
static EE_Status VerifyPagesFullWriteVariable ( uint16_t VirtAddress , EE_DATA_TYPE Data )
{
uint32_t crc = 0U ;
/* Check if pages are full, i.e. max number of written elements achieved */
if ( uhNbWrittenElements > = NB_MAX_WRITTEN_ELEMENTS ) {
return EE_PAGE_FULL ;
}
/* Get active Page for write operation */
uint32_t activepage = FindPage ( FIND_WRITE_PAGE ) ;
uint32_t activepageaddress = 0U ;
/* Check if there is no active page */
if ( activepage = = EE_NO_PAGE_FOUND ) {
return EE_ERROR_NOACTIVE_PAGE ;
}
activepageaddress = PAGE_ADDRESS ( activepage ) ;
/* Force crc to 0 in case of Data/VirtAddress are 0*/
if ( ( Data = = 0U ) & & ( VirtAddress = = 0U ) ) {
crc = 0U ;
} else {
/* Calculate crc of variable data and virtual address */
crc = CalculateCrc ( Data , VirtAddress ) ;
}
/* Program variable data + virtual address + crc */
/* If program operation was failed, a Flash error code is returned */
if ( FI_WriteDoubleWord ( activepageaddress + uwAddressNextWrite , EE_ELEMENT_VALUE ( VirtAddress , Data , crc ) ) ! = 0 ) {
return EE_WRITE_ERROR ;
}
/* Increment global variables relative to write operation done*/
uwAddressNextWrite + = EE_ELEMENT_SIZE ;
uhNbWrittenElements + + ;
return EE_OK ;
}
/**
* @ brief Set page state in page header
* @ param Page Index of the page
* @ param State State of the page
* @ retval EE_Status
* - EE_OK : on success
* - EE error code : if an error occurs
*/
static EE_Status SetPageState ( uint32_t Page , EE_State_type State )
{
uint32_t header1 = 0U , header2 = 0U , header3 = 0U , header4 = 0U ;
header1 = PAGE_ADDRESS ( Page ) ;
header2 = PAGE_ADDRESS ( Page ) + EE_ELEMENT_SIZE ;
header3 = PAGE_ADDRESS ( Page ) + ( EE_ELEMENT_SIZE * 2U ) ;
header4 = PAGE_ADDRESS ( Page ) + ( EE_ELEMENT_SIZE * 3U ) ;
switch ( State ) {
case STATE_PAGE_RECEIVE : {
/* Set new Page status to STATE_PAGE_RECEIVE status */
if ( FI_WriteDoubleWord ( header1 , EE_PAGESTAT_RECEIVE ) ! = SUCCESS ) {
return EE_WRITE_ERROR ;
}
ubCurrentActivePage = Page ;
}
break ;
case STATE_PAGE_ACTIVE : {
/* Set new Page status to STATE_PAGE_ACTIVE status */
if ( FI_WriteDoubleWord ( header2 , EE_PAGESTAT_ACTIVE ) ! = SUCCESS ) {
return EE_WRITE_ERROR ;
}
ubCurrentActivePage = Page ;
}
break ;
case STATE_PAGE_VALID : {
/* Set new Page status to STATE_PAGE_VALID status */
if ( FI_WriteDoubleWord ( header3 , EE_PAGESTAT_VALID ) ! = SUCCESS ) {
return EE_WRITE_ERROR ;
}
}
break ;
case STATE_PAGE_ERASING : {
/* Set new Page status to STATE_PAGE_ERASING status */
if ( FI_WriteDoubleWord ( header4 , EE_PAGESTAT_ERASING ) ! = SUCCESS ) {
return EE_WRITE_ERROR ;
}
}
break ;
default :
break ;
}
/* Return last operation flash status */
return EE_OK ;
}
/**
* @ brief Get page state in page header
* @ param Address Address of the FLASH Memory page
* @ retval State State of the page
*/
static EE_State_type GetPageState ( uint32_t Address )
{
EE_ELEMENT_TYPE status1 = 0U , status2 = 0U , status3 = 0U , status4 = 0U ;
/* Get page state information from page header (3 first elements) */
status1 = ( * ( __IO EE_ELEMENT_TYPE * ) Address ) ;
status2 = ( * ( __IO EE_ELEMENT_TYPE * ) ( Address + EE_ELEMENT_SIZE ) ) ;
status3 = ( * ( __IO EE_ELEMENT_TYPE * ) ( Address + ( EE_ELEMENT_SIZE * 2U ) ) ) ;
status4 = ( * ( __IO EE_ELEMENT_TYPE * ) ( Address + ( EE_ELEMENT_SIZE * 3U ) ) ) ;
/* Return erasing status, if element4 is not EE_PAGESTAT_ERASED value */
if ( status4 ! = EE_PAGESTAT_ERASED ) {
return STATE_PAGE_ERASING ;
}
/* Return valid status, if element3 is not EE_PAGESTAT_ERASED value */
if ( status3 ! = EE_PAGESTAT_ERASED ) {
return STATE_PAGE_VALID ;
}
/* Return active status, if element2 is not EE_PAGESTAT_ERASED value */
if ( status2 ! = EE_PAGESTAT_ERASED ) {
return STATE_PAGE_ACTIVE ;
}
/* Return receive status, if element1 is not EE_PAGESTAT_ERASED value */
if ( status1 ! = EE_PAGESTAT_ERASED ) {
return STATE_PAGE_RECEIVE ;
}
/* Return erased status, if 4 first elements are EE_PAGESTAT_ERASED value */
return STATE_PAGE_ERASED ;
}
/**
* @ brief This function configures CRC Instance .
* @ note This function is used to :
* - 1 - Enable peripheral clock for CRC .
* - 2 - Configure CRC functional parameters .
* @ note Peripheral configuration is minimal configuration from reset values .
* Thus , some useless LL unitary functions calls below are provided as
* commented examples - setting is default configuration from reset .
* @ param None
* @ retval None
*/
void ConfigureCrc ( void )
{
/* (1) Enable peripheral clock for CRC */
LL_AHB1_GRP1_EnableClock ( LL_AHB1_GRP1_PERIPH_CRC ) ;
}
/**
* @ brief This function performs CRC calculation on Data and Virtual Address .
* @ param Data value of the eeprom variable .
* @ param VirtAddress address of the eeprom variable .
* @ retval 16 - bit CRC value computed on Data and Virtual Address .
*/
uint16_t CalculateCrc ( EE_DATA_TYPE Data , uint16_t VirtAddress )
{
/* Reset CRC calculation unit */
LL_CRC_ResetCRCCalculationUnit ( CRC ) ;
/* Feed Data and Virtual Address */
LL_CRC_FeedData32 ( CRC , Data ) ;
LL_CRC_FeedData32 ( CRC , VirtAddress ) ;
/* Return computed CRC value */
uint32_t crc32 = LL_CRC_ReadData32 ( CRC ) ;
return ( crc32 & 0xFFFF ) ^ ( ( crc32 & 0xFFFF0000 ) > > 16 ) ; // get 16 bit from 32bit
}
/**
* @ }
*/
/**
* @ }
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/