?? eeprom.c
字號:
/*--------------------------------------------------------------------------
eeprom.c
Version:
10/2004 Ver 0.2 - Corrected Eeprom_Sector_Swap to properly handle smaller
sized records.
11/2002 Ver 0.1 - Initial Version
Description:
Device driver for EEPROM emulation using boot (secondary) flash.
*****************************************************************************
Important Note:
XDATA must be initialized to 0 in the startup file for this driver to work
properly. This will be investigated and corrected in future releases.
*****************************************************************************
Copyright (c) 2004 STMicroelectronics
This example demo code is provided as is and has no warranty,
implied or otherwise. You are free to use/modify any of the provided
code at your own risk in your applications with the expressed limitation
of liability (see below) so long as your product using the code contains
at least one uPSD products (device).
LIMITATION OF LIABILITY: NEITHER STMicroelectronics NOR ITS VENDORS OR
AGENTS SHALL BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF USE, LOSS OF DATA,
INTERRUPTION OF BUSINESS, NOR FOR INDIRECT, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES OF ANY KIND WHETHER UNDER THIS AGREEMENT OR
OTHERWISE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
--------------------------------------------------------------------------*/
#include "eeprom.h"
#include "upsd3200.h" // special function register declarations for UPSD
/***** EEPROM_Format *****/
// Formats sectors 0 and 1 to accept record data
// Accepts maximum number of records allowed.
// Returns 0 on success. If error, returns 1.
// ********** WARNING ********** //
// This function erases any existing data in both sectors
// ********** WARNING ********** //
BYTE EEPROM_Format(WORD max_records)
{
xdata struct record_entry xdata record;
// Verify data will fit into half of sector
if ( (sizeof(record) * max_records) > (SECTOR_SIZE/2) )
return ILLEGAL_RECORD_NUMBER;
// Format sector 0
if ( E_andF_Sector(SECTOR_0, max_records) ) return FORMAT_FAILED;
// Erase sector 1
if ( Eeprom_Sector_Erase(SECTOR_1) ) return SECTOR_ERASE_ERROR;
return 0;
}
/***** Eeprom_Init *****/
// Verifies database integrity after power loss.
// Attempts to recover data corruption after power loss.
// Re-formats database if corrupted.
BYTE Eeprom_Init(void)
{
xdata struct sector_header xdata sector_header_0;
xdata struct sector_header xdata sector_header_1;
xdata struct record_entry xdata record;
WORD i, j;
BYTE *ptr;
WORD xdata max_rec;
WORD xdata last_address;
WORD xdata base_address;
WORD xdata new_address;
BYTE xdata valid_sector;
// Get both sector headers
ptr = (BYTE*) (§or_header_0);
base_address = SECTOR_0_BASE_ADDRESS;
for ( i=0; i < sizeof(sector_header_0); i++ )
{
ptr[i] = Boot_Flash_Read( base_address++ );
}
ptr = (BYTE*) (§or_header_1);
base_address = SECTOR_1_BASE_ADDRESS;
for ( i=0; i < sizeof(sector_header_1); i++ )
{
ptr[i] = Boot_Flash_Read( base_address++ );
}
// Check for corrupted sectors
// This would occur if a sector erase was interrupted by a power loss
// In this case, the sector must be re-erased
if ( ~(sector_header_0.sector ^ sector_header_0.sector_checksum) )
{
if ( Eeprom_Sector_Erase(SECTOR_0) ) return SECTOR_ERASE_ERROR;
sector_header_0.sector_status = ERASED;
}
if ( ~(sector_header_1.sector ^ sector_header_1.sector_checksum) )
{
if ( Eeprom_Sector_Erase(SECTOR_1) ) return SECTOR_ERASE_ERROR;
sector_header_1.sector_status = ERASED;
}
// Get maximum number of records from header
// If unable, return error
if ( sector_header_0.max_records != 0xFFFF )
max_rec = sector_header_0.max_records;
else if ( sector_header_1.max_records != 0xFFFF )
max_rec = sector_header_1.max_records;
else
return ILLEGAL_RECORD_NUMBER;
// Check for invalid header states and repair
switch(sector_header_0.sector_status)
{
case ERASED:
if( sector_header_1.sector_status == VALID__SECTOR ) // sector 1 is valid
{
if ( Eeprom_Sector_Erase(SECTOR_0) ) return SECTOR_ERASE_ERROR;
}
else // invalid state re-format database
{
if ( Eeprom_Sector_Erase(SECTOR_1) ) return SECTOR_ERASE_ERROR;
if ( E_andF_Sector(SECTOR_0, max_rec) ) return FORMAT_FAILED;
return INVALID_SECTOR_STATE;
}
break;
case RECEIVE_DATA:
if ( sector_header_1.sector_status == VALID__SECTOR ) // use sector 1
{
if ( Eeprom_Sector_Erase(SECTOR_0) ) return SECTOR_ERASE_ERROR;
}
else if(sector_header_1.sector_status == TRANSFER_COMPLETE) //use sector 0
{
if ( Eeprom_Sector_Erase(SECTOR_1) ) return SECTOR_ERASE_ERROR;
// update sector 0 header to valid data
sector_header_0.sector_status = VALID__SECTOR;
ptr = (BYTE*) (§or_header_0);
base_address = SECTOR_0_BASE_ADDRESS;
for ( i=0; i < sizeof(sector_header_0); i++ )
{
if ( Boot_Flash_Write( base_address++, ptr[i] ) ) return FLASH_WRITE_ERROR;
}
}
else // invalid state erase both sectors
{
if ( Eeprom_Sector_Erase(SECTOR_1) ) return SECTOR_ERASE_ERROR;
if ( E_andF_Sector(SECTOR_0, max_rec) ) return FORMAT_FAILED;
return INVALID_SECTOR_STATE;
}
break;
case VALID__SECTOR:
if ( sector_header_1.sector_status == VALID__SECTOR ) // invalid state erase both sectors
{
if ( Eeprom_Sector_Erase(SECTOR_1) ) return SECTOR_ERASE_ERROR;
if ( E_andF_Sector(SECTOR_0, max_rec) ) return FORMAT_FAILED;
return INVALID_SECTOR_STATE;
}
else // sector 0 is valid sector, erase sector 1
{
if ( Eeprom_Sector_Erase(SECTOR_1) ) return SECTOR_ERASE_ERROR;
}
break;
case TRANSFER_COMPLETE:
if ( sector_header_1.sector_status == VALID__SECTOR ) // erase sector 0
{
if ( Eeprom_Sector_Erase(SECTOR_0) ) return SECTOR_ERASE_ERROR;
}
else if (sector_header_1.sector_status == RECEIVE_DATA) // erase sector 0, use sector 1
{
if ( Eeprom_Sector_Erase(SECTOR_0) ) return SECTOR_ERASE_ERROR;
// mark sector 1 as valid sector
sector_header_1.sector_status = VALID__SECTOR;
ptr = (BYTE*) (§or_header_1);
base_address = SECTOR_1_BASE_ADDRESS;
for ( i=0; i < sizeof(sector_header_1); i++ )
{
if ( Boot_Flash_Write( base_address++, ptr[i] ) ) return FLASH_WRITE_ERROR;
}
}
else // invalid state, format both sectors
{
if ( Eeprom_Sector_Erase(SECTOR_1) ) return SECTOR_ERASE_ERROR;
if ( E_andF_Sector(SECTOR_0, max_rec) ) return FORMAT_FAILED;
return INVALID_SECTOR_STATE;
}
break;
default: // any other state, erase both sectors
if ( Eeprom_Sector_Erase(SECTOR_1) ) return SECTOR_ERASE_ERROR;
if ( E_andF_Sector(SECTOR_0, max_rec) ) return FORMAT_FAILED;
return INVALID_SECTOR_STATE;
break;
}
// Check for corrupted data
// This would happen if a data write/update was interrupted by a power loss
for ( i=0; i<max_rec; i++ )
{
// get address of last entry of each record
last_address = Read_Record_Data_Structure( i, (BYTE*) (&record) );
// repair record entry if necessary
if ( record.status == UPDATE_DATA )
{
// get sector
valid_sector = Find_Active_Sector(F_WRITE);
if ( valid_sector == SECTOR_ID_ERROR ) return SECTOR_ID_ERROR;
// get base address of sector
base_address = SECTOR_0_BASE_ADDRESS + ((WORD)valid_sector * SECTOR_SIZE);
// get address for repaired entry
new_address = Find_Next_Address();
if( new_address == SECTOR_FULL ) return SECTOR_FULL; // abort if sector is full
// set status and pointer to next data
record.status = VALID_DATA;
record.last_record_update = 0xFFFF;
// write new record with old data
ptr = (BYTE*) (&record);
for ( j=0; j<sizeof(record); j++ )
{
if ( Boot_Flash_Write(new_address++, ptr[j]) ) return FLASH_WRITE_ERROR;
}
// fix status and pointer of old record
record.status = SUPERSEDED;
record.last_record_update = new_address - sizeof(record);
for ( j=0; j < sizeof(record); j++ )
{
if ( Boot_Flash_Write( last_address++, ptr[j] ) ) return FLASH_WRITE_ERROR;
}
}
}
return 0;
}
/***** Update_Record *****/
// Update record in EEPROM.
// Accepts record id and new record data.
// Swaps to empty sector if current sector is full
BYTE Update_Record(WORD id, BYTE xdata *buf)
{
BYTE i;
BYTE xdata status;
BYTE xdata bufover[EEPROM_RECORD_SIZE];
status = Write_Record(id, buf);
// when the sector is full, save the new record to ram and transfer to a blank sector
if( status == SECTOR_FULL )
{
// store new data in temporary buffer
for ( i=0; i < sizeof(bufover); i++ )
{
bufover[i] = buf[i];
}
// perform sector swap
status = Eeprom_Sector_Swap(id, &bufover);
}
return status;
}
/***** Read_Record *****/
// Reads a data element from EEPROM.
// Accepts record id number.
// Returns record data byte. If error, returns error code.
BYTE Read_Record(WORD id_number, BYTE* buffer)
{
BYTE xdata valid_sector = 0xFF;
xdata struct sector_header xdata header;
xdata struct record_entry xdata record;
WORD i;
BYTE *ptr;
BYTE xdata *data_buf;
WORD xdata address;
WORD xdata base_address;
WORD xdata last_address;
// get active sector
valid_sector = Find_Active_Sector(F_READ);
if ( valid_sector == SECTOR_ID_ERROR ) return SECTOR_ID_ERROR;
// get pointer to data
data_buf = buffer;
// calculate base address of data
base_address = SECTOR_0_BASE_ADDRESS + ((WORD)valid_sector * SECTOR_SIZE) +
(WORD)sizeof(header) + ( id_number * (WORD)sizeof(record) );
// get base record
ptr = (BYTE*) (&record);
address = base_address;
for ( i=0; i<sizeof(record); i++ )
{
ptr[i] = Boot_Flash_Read( address++ );
}
// get last record
if ( record.last_record_update != 0xFFFF )
{
address = base_address;
do
{
ptr = (BYTE*) (&record);
last_address = address;
for ( i=0; i<sizeof(record); i++ )
{
ptr[i] = Boot_Flash_Read( address++ );
}
address = record.last_record_update;
} while ( record.last_record_update != 0xFFFF );
}
else
{
last_address = base_address;
}
if( record.status == UNINITIALIZED ) return UNINITIALIZED;
// Set data buffer
for ( i=0; i<EEPROM_RECORD_SIZE; i++ )
{
data_buf[i] = record.record_data[i];
}
return 0;
}
/***** Write_Record *****/
// Write or update record in EEPROM.
// Accepts record id and new record data.
// If error, returns error code.
BYTE Write_Record(WORD id, BYTE xdata *buffer)
{
xdata struct sector_header xdata header;
xdata struct record_entry xdata record;
WORD i;
BYTE xdata valid_sector;
WORD xdata last_address;
WORD xdata base_address;
WORD xdata new_address;
WORD address;
BYTE *ptr;
BYTE xdata *data_buf;
// get active sector
valid_sector = Find_Active_Sector(F_WRITE);
if ( valid_sector == SECTOR_ID_ERROR ) return SECTOR_ID_ERROR;
// get pointer to data
data_buf = buffer;
// calculate base address of data
base_address = SECTOR_0_BASE_ADDRESS + ((WORD)valid_sector * SECTOR_SIZE) +
(WORD)sizeof(header) + ( id * (WORD)sizeof(record) );
// get base record
ptr = (BYTE*) (&record);
address = base_address;
for ( i=0; i<sizeof(record); i++ )
{
ptr[i] = Boot_Flash_Read( address++ );
}
// write data if record not initialized
if ( record.status == UNINITIALIZED )
{
record.status = VALID_DATA;
record.last_record_update = 0xFFFF;
for ( i=0; i < EEPROM_RECORD_SIZE; i++ )
{
record.record_data[i] = data_buf[i]; // set data byte
}
// write record to flash
ptr = (BYTE*) (&record);
address = base_address;
for ( i=0; i < sizeof(record); i++ )
{
if ( Boot_Flash_Write( address++, ptr[i] ) ) return FLASH_WRITE_ERROR;
}
return 0;
}
// find last entry if record initialized
address = base_address;
do
{
ptr = (BYTE*) (&record);
for ( i=0; i<sizeof(record); i++ )
{
ptr[i] = Boot_Flash_Read( address++ );
}
if ( record.status == SUPERSEDED )
{
address = record.last_record_update;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -