⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eeprom.c

📁 ST公司的upsd dk2000评估板仿真eeprom的源程序。
💻 C
📖 第 1 页 / 共 3 页
字号:
/*--------------------------------------------------------------------------
eeprom.c

Header file for eeprom emulation using boot (secondary) flash
11/2002 Ver 0.1 - Initial Version

Copyright (c) 2002 ST Microelectronics
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*) (&sector_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*) (&sector_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*) (&sector_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*) (&sector_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;
		}
		
	} while ( record.status == SUPERSEDED );

	last_address = address - (WORD)sizeof(record);

	// get next available address
	new_address = Find_Next_Address();
	if( new_address == SECTOR_FULL ) return SECTOR_FULL; // abort if sector is full

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -