<<

AN2040 APPLICATION NOTE EEPROM Emulation and Record Storage Using the uPSD32xx

Generally, EEPROM devices are used to store and retain data in the event of power failure. The data may be retrieved whenever required, and can be repeatedly updated (the device ratings usually specify an up- per figure between 100 thousand and 10 million /Erase cycles). One of the main differences, from the user point of view, between EEPROM and a uPSD device (which includes an extremely large array) is the minimum granularity for erasing data. Typically, EEPROM allows the user to modify single locations: that is, data stored at a specific address can be updated individually. In contrast, the uPSD Flash memory provides random-access non-volatile data stor- age, a byte at a time, but can only be erased a sector at a time. However, Flash memory in general, and uPSD in particular, offers so many other advantages to the de- signer that it is often better to emulate the EEPROM in Flash memory, rather than to have a specific EE- PROM device. Emulation is achieved by employing two Boot sectors in the uPSD device: one that starts off erased, and offers byte-at-a-time programmability, and the other ready to take over when the first one needs to be garbage collected. The byte-at-a-time programmability uses a linked-list data storage algorithm to update stored data until the sector is full, at which time the valid data is swapped to a different sector and the orig- inal sector is erased. The EEPROM emulation code (which is listed in the appendices of this ) swaps data between the sectors as they become filled, in a manner that is transparent to the user. The EEPROM emulation driver meets the following requirements: ■ Minimum use of SRAM ■ Simple and easily updateable code model ■ User API consisting of initial format, record, update record ■ Clean-up and internal transparent to the user ■ Background sector erase ■ Code in main Flash memory, in boot Flash memory ■ At least two boot Flash memory sectors to be used, more if possible for wear leveling ■ No timers, interrupts or RTOS The EEPROM size to be emulated is flexible, within the limits and constraints of the sector size, and allows for a maximum EEPROM size of 8KBytes in the current implementation, which is the sector size that is defined by the uPSD32xx architecture. The header and source file, written in C on the Keil IDE for uPSD, are held in .h and eeprom.c (respectively). These can be downloaded with the C code, and use sectors 0 and 1 of the secondary (boot) flash to emulate EEPROM data storage. A sample demonstration program is also supplied to demonstrate and test the EEPROM Emulation using the DK3200 board. This application note describes the EEPROM Emulation driver, and the small demonstration program writ- ten for the DK3200 hardware demonstration kit (which incorporates a uPSD3234A device).

September 2004 1/25 AN2040 - APPLICATION NOTE

TABLE OF CONTENTS

OPERATION ...... 3 User API ...... 3 EEPROM_Format ...... 3 Update_Record ...... 3 Update_Record (BYTE id, BYTE *buf) ...... 4 Read_Record ...... 4 Read_Record (WORD id, BYTE *buffer)...... 4 Eeprom_Init ...... 4 Data Structures and Error Recovery ...... 4 Figure 1. Data Storage Map ...... 5 Interrupted Sector Erase ...... 6 Interrupted Sector Swap ...... 6 Figure 2. Sector Swap Flowchart ...... 7 Table 1. Sector Status Byte Matrix ...... 8 Figure 3. Check Flowchart ...... 9 Lower Level Functions ...... 9 Write_Record (WORD id, BYTE *buffer) ...... 9 Boot_Flash_Write (WORD address, BYTE data_byte) ...... 9 Read_Record_Data_Structure (WORD id_number, BYTE *buffer) ...... 10 Boot_Flash_Read (WORD address) ...... 10 Eeprom_Sector_Erase (BYTE sector)...... 10 Eeprom_Sector_Erase_Start (BYTE sector) ...... 10 Eeprom_Sector_Erase_Suspend (BYTE sector) ...... 10 Eeprom_Sector_Erase_Resume (BYTE sector) ...... 10 Eeprom_Sector_Erase_Status (BYTE sector) ...... 10 Find_Next_Address (void) ...... 10 Find_Active_Sector (BYTE io)...... 10 Eeprom_Sector_Swap (BYTE inn, BYTE *buf) ...... 10 E_andF_Sector (BYTE sector, WORD max_rec) ...... 10 Get_Sector_Status (BYTE sector)...... 10 EEPROM Emulation Demonstration on DK3200...... 11 Figure 4. Startup Screen...... 12 Figure 5. Merging of MCU Firmware with PSD Screen ...... 13

APPENDIX A.UPDATES ENDURANCE COMPUTATION ...... 14 Parameters and Assumptions ...... 14

APPENDIX B.EEPROM EMULATION Demo code ...... 16 Changes to be Made at Compile Time...... 16

APPENDIX C.DK3200 EEPROM DEMONSTRATION PROGRAM ...... 20

REVISION HISTORY...... 24 Table 2. Document Revision History ...... 24

2/25 AN2040 - APPLICATION NOTE

OPERATION This section describes the key features, functions and basic operation of the driver code. The algorithm used, in the supplied driver code, makes use of the robustness of the Flash memory device. By organizing the data and record entry in the particular structure that it does, provides for maximum data integrity as well as allowing for virtually unlimited updating of the data (APPENDIX A.). The EEPROM Emulation code requires input from the user, for it to determine the allocation and formatting of the memory sectors. Required parameters are explained in the User API. (The sample demonstration program, for example, uses 1 record of 128 ). Based on this input, the driver code reserves enough memory immediately after the sector header to hold one instance of each data record. Id numbers that correspond to those memory locations identify the data records. The id numbers are not part of the record themselves. Several low-level functions are provided that per- form the management of the read/write and maintenance of the database, based on the number of records and record size. Some error codes are generated that can be called by users in their application codes. (The demonstration program shows some of the error checks in use). The and error recovery as well as the low-level functions are described later. User API The EEPROM Emulation code is also provided with a sample demonstration program, which is used to input the user parameters to the main code. Four functions are provided to the user for EEPROM data management in this implementation. They are: ■ EEPROM_Format ■ Update_Record ■ Read_Record ■ EEPROM_Init Overall the algorithm performs the data management, in a way that is completely transparent to the appli- cation, using many low-level functions that augment this mechanism. The user is also responsible for defining the data record size (in bytes), and the maximum number of records allowed. Valid values are 0 to 65535 (0 to 0xFFFF) for the current implementation. These param- eters have to be defined at compile- and run-time The data record size is defined in eeprom.h prior to compile-time. For the supplied demonstration program it has been set to 128 bytes. (APPENDIX B.) The maximum number of records is defined at run time via an argument to EEPROM_Format. (In the sup- plied demonstration program it has been set to one record only (APPENDIX C.) A brief description and usage of the four functions, that are available to the user as input, are as follows: EEPROM_Format. This writes a sector header to sector 0, and erases sector 1. Note that a call to this function will erase any existing data. Part of the formatting process involves verifying that the maximum number of records and the record size are compatible with the sector size. (The demonstration program provides an error check to test if this is not met). The user needs to correlate id numbers to data entries based on the application. Update_Record. Data is written using this function. (The demonstration program uses this function to write the contents of a buffer) The function accepts an id number and a pointer to a data buffer. The user is responsible for initializing the data buffer to the correct number of data bytes. Data is updated using the same function. The program will create a linked list of data updates until the sector is full. At that point, only the valid data is written to a new sector, along with the sector header. This is transparent to the user.

3/25 AN2040 - APPLICATION NOTE

Update_Record (BYTE id, BYTE *buf). This function adds/updates a record entry with new data. The id number corresponds to the location in memory of the initial data entry. The user can correlate the id num- ber with the data in any way he or she chooses. The user must provide a pointer to a data array in xdata containing the data for the record. This function passes the id number and data pointer to Write_Record. Write_Record will either update the parameter or return an error saying that the sector is full. In the case of a full sector, the data is saved to an intermediate buffer and Eeprom_Sector_Swap is called. Eeprom_Sector_Swap transfers all valid data entries to a new sector, including the current update. Read_Record. This function is used to read any record. (In the demonstration program, it read backs the record written by update record). This function accepts the id number of the record and a pointer to a buffer to receive the data. Once again, it is the users’ responsibility to set up a data buffer of the appropriate type and size. (For the demonstration program, this buffer is set to size 1) Read_Record (WORD id, BYTE *buffer). This function reads record data into a buffer provided by the user. Only the last update is read. The record is retrieved as follows: First, the active sector is retrieved using the function Find_Active_Sector. The base address of the record is then determined from the active sector number. The base record corresponding to the id is then read. If the base record is not the last up- date, the function enters a loop in which it reads the record entries until the last one is found. The data is then copied into the buffer pointed to by *buffer. Eeprom_Init. This function is provided for and repair in the event of a power loss. This function should be called prior to accessing the database after each power-down. It accepts no parame- ters. It simply verifies the integrity of the database and repairs any interrupted data updates. In the event of an aborted data update, the last known good data is written to the record. In the event of a power inter- ruption during a sector swap, the Eeprom_Init function will attempt to restore the database to a known good state. This process is described in more detail later. Data Structures and Error Recovery Two data structures are used for the project; a sector header structure and a record entry structure. The sector header contains the number of data elements (maximum), data size (in bytes) and status informa- tion. The record entry contains the data itself, a pointer to the next data element and update status. (See the eeprom.h header file for the definitions and mapping for the data structures). struct sector_header { BYTE sector_status; BYTE sector; BYTE sector_checksum; WORD max_records; WORD rec_length; } struct record_entry { BYTE status; BYTE record_data[EEPROM_RECORD_SIZE]; struct record_entry *last_record_update; }

Each sector is 8KBytes in size. The sector header is written to the top of the sector during the format or sector swap operation. Space for one entry of each record is reserved immediately following the sector header. Updates to existing records are stored in the remaining space until the sector is full (Figure 1.).

4/25 AN2040 - APPLICATION NOTE

Figure 1. Data Storage Map

Sector0 0x8000 sector_status

sector status sector_checksum Record_data[0] max records

RecordEntry record (EEPROM_RECORD_SIZE) length 0x8006 Record_data[n] 0x8007 status Last_record_update contains the absolute *last address of record update Record_data[0] record_entry(0) update status byte status

Record Record_data[0] Entry 0

Record_data[n] Record Entry *last Update* record update Record_data[n] 0x8007+ sizeof(record_entry) *last record update

status

Record_data[0]

Last Record Entry Update Record_data[n]

*last record update

AI10246

Note: 1. * For the purposes of illustration purposes, the first record entry update corresponds to record0. In practice, though, this update could correspond to any record. Data and/or sector header corruption is possible in the event of power loss during data update or sector erase/swap. A power recovery routine called EEPROM_Init is provided to perform a sector header and data integrity check immediately after power on. This routine uses the data and sector status bytes to check data integrity and, if necessary, to perform repair and recovery of data records. This routine also checks the sector number and checksum for an interrupted sector erase. The recovery operations are as follows.

5/25 AN2040 - APPLICATION NOTE

Interrupted Sector Erase. Sector erase is performed during sector format, initialization, and after sector swap. The sector erase operations during format and initialization are completed prior to any further EE- PROM access, but the sector erase following sector swap is performed in the “background” – that is, erase is started, and then control is returned to the user. In the event of the user trying to perform an EEPROM read or write, while an erase is in progress, the erase is suspended, and the read/write is performed. The erase is then resumed. Note that read/write op- erations can only be performed on a sector that is not being erased. In the event of a sector erase being interrupted by a power loss, the EEPROM_Init routine checks the sec- tor header for the sector number and sector number checksum. The sector number is either 0 or 1, corre- sponding to sectors 0 and 1, respectively. The sector checksum is the complement of the sector number. For example, if sector 1 is used, then the sector number is 0x01, and the checksum is 0xFE. These two values are XORed by the initialization routine. If the result is not 0xFF, the sector is erased. This has the effect of erasing any partially or fully erased sectors. It is somewhat inefficient in that the unused sector is erased upon power-up whether it needed it or not, but the alternative is to verify each byte in the sector, which takes much longer. Interrupted Sector Swap. Sector swap is performed when one sector gets too full to accept a requested data update. The sector status byte is used to keep track of sector swap progress. In the case of a power interruption during a sector swap, the state of the sector status byte is used to determine the best recovery procedure. The sector status byte can have four possible states: ■ ERASED – the sector has not yet been initialized ■ RECEIVE_DATA – the sector has been marked for swapping into ■ VALID_SECTOR – the sector contains valid data ■ TRANSFER_COMPLETE – the program has finished transferring data to another sector The sector status byte is updated during the sector swap process, as shown in Figure 2..

6/25 AN2040 - APPLICATION NOTE

Figure 2. Sector Swap Flowchart

Update Record Request

Sector No Full? Update Record

Yes

Get Sector Headers

New No Sector Erase Sector Erased?

Yes

Mark New Sector Header RECEIVE_DATA

Transfer Data to New Sector

Mark Old Sector Header TRANSFER_COMPLETE

Mark New Sector Header VALID_DATA

Erase Old Sector AI10247

7/25 AN2040 - APPLICATION NOTE

After power loss, EEPROM_Init is used to check sector the header status. If the current status indicates that a sector swap was in progress, the last known good data is saved to the new sector. Table 1. shows the matrix of valid and invalid sates as well as the action taken based on the sector status state upon pow- er up. Sixteen possible sector status combinations are possible, half of which are invalid (shown in italics).

Table 1. Sector Status Byte Matrix Sector0 Erased Receive Data Valid Data Transfer Complete Invalid state. Erase Invalid state. Erase Invalid state. Erase Use sector0 as valid Erased both sectors and both sectors and both sectors and data. Erase sector1 format sector0 format sector0 format sector0 Invalid state. Erase Invalid state. Erase Receive Use sector0 as valid Use sector1 as valid both sectors and both sectors and Data data. Erase sector1 data. Erase sector0 format sector0 format sector0 Sector1 Invalid state. Erase Use sector1 as valid Use sector1 as valid Use sector1 as valid Valid Data both sectors and data. Erase sector0 data. Erase sector0 data. Erase sector0 format sector0 Invalid state. Erase Invalid state. Erase Transfer Use sector0 as valid Use sector0 as valid both sectors and both sectors and Complete data. Erase sector1 data. Erase sector1 format sector0 format sector0

A sector swap interruption during a data transfer can result in a corrupted data-record structure. In this case, the last known good value (the value prior to the interrupted update) needs to be restored to the last record update in the database. This function is also performed by EEPROM_Init. When EEPROM_Init is run, the last thing it does is check for corrupted data entries. Each record data entry contains a status byte similar to the status byte that is used by the sector header. The record entry status byte can have four possible states: ■ UNITIALIZED – if the data is not initialized, it means that no data has been written to this record ■ VALID_DATA – this entry contains valid data and has not been updated ■ UPDATE_DATA – this entry is in the process of being updated ■ SUPERSEDED – this entry has been modified and is no longer valid Each data entry is read, and if the last data entry status byte is UPDATE_DATA (indicating a data update in progress), the previous entry is recovered and a new update is performed. Figure 3. shows this process.

8/25 AN2040 - APPLICATION NOTE

Figure 3. Data Integrity Check Flowchart

Read Record

Update No Data?

Yes

Get Next Available Address

Sector Yes Last No Full? Record?

No Yes

Write Old Record Swap to New Address Sectors

Update Status Byte and Last Record Update Pointer of Old Record

Finished

AI10248

Lower Level Functions The data management for the emulation process requires several lower level functions that allow the user control over the read/write and data management. These functions are listed next, along with a brief de- scription. Write_Record (WORD id, BYTE *buffer). This function writes a data record into the database. If the base data record is not initialized, the record is written, and the function returns. If it is initialized, the next available memory block is found using Find_Next_Address. The last valid record is then marked for up- date, and the new data is then written. Finally, the previous entry is marked as having been superseded. Boot_Flash_Write (WORD address, BYTE data_byte). This function writes a single byte of data to an address in Flash memory. It accepts a single byte of data and the absolute address to be written to. It is used by Write_Record to do the actual of the data. Prior to any Flash memory operations, two con- ditions are checked. One is whether or not the function was re-entered, perhaps from an interrupt service routine. The other is whether or not a Flash memory erase is in progress. If the function was re-entered, it is aborted with an error message. If an erase is in progress, it is suspend- ed for the actual write sequence. Interrupts are then disabled, and the write sequence begins. Following the write sequence, interrupts are enabled again, and the Flash memory data byte is polled until a suc- cessful write is indicated. The data is then read back and compared to the original data byte to verify a successful write. Finally, any suspended erase is resumed.

9/25 AN2040 - APPLICATION NOTE

Read_Record_Data_Structure (WORD id_number, BYTE *buffer). This function is used by the EEPROM_Init routine to return an entire record data structure instead of just the data. It is similar to Read_Record, except that the buffer pointed to must be sizeof(record). It also returns the address of the last valid record corresponding to the id number. Boot_Flash_Read (WORD address). This function returns a single byte of data read from an absolute address in Flash memory. Re-entrant calls and Flash memory erase in progress are checked in a similar fashion to Boot_Flash_Write. Eeprom_Sector_Erase (BYTE sector). This function performs the complete, uninterrupted erase of an entire sector. It accepts the sector number. The erase sequence is performed, and then the status byte is polled until the erase is complete. Eeprom_Sector_Erase_Start (BYTE sector). This function starts the sector erase, but does not wait for completion. It is called by the sector swap routine. Eeprom_Sector_Erase_Suspend (BYTE sector). This function suspends a sector erase that is in progress. Eeprom_Sector_Erase_Resume (BYTE sector). This function resumes a sector erase that has been suspended. Eeprom_Sector_Erase_Status (BYTE sector). This function polls the status register to detect if a sec- tor erase is in progress. If bit 7 of the data byte is 0, an erase is in progress. This is why the first byte of the header sector needs to be the status byte (the only byte in which bit 7 is always 1). Find_Next_Address (void). This function finds the next available address for a record entry. First, it finds the valid sector. It then retrieves the header sector. This is necessary to determine the maximum number of records. It then calculates the base address of available memory based on the sector number, the size of the sector header, and the amount of memory required for the initial entries for each record. It then sim- ply reads record entry size blocks of memory until it finds one that is not being used. Finally, it verifies that there is enough room left for another entry. If not, it returns an error. If there is enough memory, the base address for the record update is returned. Find_Active_Sector (BYTE io). This function reads both sector headers and returns the sector number containing a valid header. It accepts a byte that indicates whether it is being used in conjunction with read or write. This is necessary for sector swapping. An error from this routine would indicate a corrupted da- tabase. Eeprom_Sector_Swap (BYTE inn, BYTE *buf). This function transfers data from a full sector to an empty one. First, it determines the currently active sector. This is the sector where the data is being trans- ferred from. Two sector headers are created in RAM to hold the header for both sectors. The new sector number and address is determined from the old sector number. The old sector header is then retrieved. The new sector is then erased to guarantee data integrity. The new sector header fields are de- fined and then written. At this point, the new sector status is RECEIVE_DATA because no data has been written yet. The data is now copied to the new sector one record at a time. Read_Record is used to retrieve only the most recent data. Once the data transfer is complete, the new sector header is marked VALID_DATA. The old sector header is then updated to TRANSFER_COMPLETE. Finally, an erase is started on the old sector. Note that this erase takes place in the background – the user may initiate other tasks while the erase is in progress. Figure 2. shows a flowchart of the sector swap routine. E_andF_Sector (BYTE sector, WORD max_rec). This routine simply erases a sector, and then writes a VALID_SECTOR sector header to it. It is used by the format and initialization routines. Get_Sector_Status (BYTE sector). This function was written primarily for testing purposes, but may also be useful to determine sector status following power-on. It can be used, for example, to determine whether the database needs to be formatted or just initialized.

10/25 AN2040 - APPLICATION NOTE

EEPROM Emulation Demonstration on DK3200 All the latest codes for the EEPROM Emulation demonstration program, and the associated drivers, are available for download from http://www.st.com/stonline/products/families/memories/psm/soft_c2.htm. This is usually supplied as a zip file EEMUL.Zip Download the Code and required tools like PSDsoft Express and ensure that you have tools for recom- piling the files, in case you want to change parameters for testing or developing your own applications us- ing the supplied driver codes. It is assumed that the user is familiar with the DK3200 board, and has operating knowledge of the PSDsoft Express tools and a integrated development environment such as Raisonance RIDE or Keil’s IDE. It is recommended that, before loading and executing the EEPROM Emulation demonstration program, a check of all required hardware and inventory is taken. To be able to run and operate the tools and DK3200: Follow the detailed Design flow in the PSDsoft Express User guide which can be downloaded from the ST website. The following brief procedure (Load Firmware/Application code in uPSD-DK3200) outlines this process when the PSDsoft project files and their associated C code and Hex files are supplied. ■ Find and copy the latest PSDsoft Express tool after downloading from the web. (In case it is not already installed, always use the latest version. The current release is 8.21). ■ Install the tool on your ■ Unzip and copy all the demonstration program, and associated drivers code, in their respective folders. (Normally you should have a -c folder and a –p folder) ■ Make sure that the JTAG dongle (RLINK-ST or Flashlink) is connected to the appropriate port: RLINK-ST connects to USB on the PC; Flashlink connects to a Parallel Port on the PC ■ Make sure that the Dongle is connected via the flat cable to the shrouded JTAG port connector on the DK3200 Board. (Note: the connector may be labeled as Flashlink on some boards) ■ Start PSDsoft Express. You will get the startup screen as shown in Figure 4.

11/25 AN2040 - APPLICATION NOTE

Figure 4. Startup Screen

■ Click “Specify project” in “design flow”. In the drop down menu, select the “ a exist project” item. Point to the PSDsoft where the application and driver code was copied ■ Identify the correct project file and open it. (This will have the extension ‘ini’: that is, xxxx.ini where xxx is the unique project name for the PSDsoft Project) ■ The next step requires merging of the project with the Correct Hex file from the _C directory provided with the demonstration program. Follow the instructions that a given on the screen, as shown in Figure 5., and point to the correct in the merge data ■ Ensure that the sectors, and their associated hexadecimal data, are mapped correctly for the application and demonstration program ■ Finally, click “OK” to complete the operation ■ Next click box “STMicroelectronics JTAG/ISP” ■ Make sure that you have select the correct paths for your project and device for the DK3200 board ■ Click the “Execute” button to finish the programming of the uPSD.

12/25 AN2040 - APPLICATION NOTE

Figure 5. Merging of MCU Firmware with PSD Screen

This will load the desired firmware/ application code into the correct mapping of the uPSD memory. The LCD will display “EEPROM Emulation”, and then execute the EEPROM Emulation demonstration. This performs a series of Writes and updates, based on the parameters provided in the demonstration pro- gram code, and the algorithm used. The parameters can be modified using Keil, and then recompiled and run again. Ensure that you select the correct hardware link. The default is RLink. Perform the RLink test, and then click on Execute to perform the JTAG Programming. Your applications and demonstration will be loaded in the DK3200. It should auto-start. Check that the demonstration program runs without errors. NOTE: this is very simple application, and demonstration of the functionality of the uPSD boot sectors as an EEPROM via this EEPROM Emulation algorithm and drivers. The example can be modified and insert- ed into other applications by the users. The demonstration program will display “EEPROM Emulation” on the LCD, and will do an update for a set number of times, and will end with the display showing the total count of updates done during the emulation. Users can modify the various inputs and header files for their own particular needs, and then recompile and run their applications. APPENDIX B. and APPENDIX C. show the sample demonstration program’s header and application codes.

13/25 AN2040 - APPLICATION NOTE

APPENDIX A. UPDATES ENDURANCE COMPUTATION uPSD products are specified at 100,000 erase cycles. A cycle being defined as an operation when each of the Sectors (in our case 8KBytes) are successfully programmed and then the sector is erased. However, the following computation shows that, during EEPROM emulation, the actual erase cycle endur- ance is vastly improved as compared to EEPROM. The various parameters and assumptions, as well as sample computations, are given below: Parameters and Assumptions It must be noted that byte updates can be affected by the parameters relating to record size and the da- tabase size. The Emulation algorithm requires the number of bytes per element of the EEEPROM Emulated record (Record Size) to be

Emulated Record Size = 3 + N bytes (Where N is the number of Bytes stored per record)

While

Database Size = {Number of Records * Record Size} + (Header)

[The header is a constant 7 bytes] The number of updates available in a sector is computed as:

Total Updates = [(Sector Size - Database Size) / Record Size] x 100000 cycles

Where 100000 cycles are the specified erase cycles for uPSD. Example computation for following requirements:

Number of bytes to be stored in EEPROM = 1 Number of Record to be stored in EEPROM = 128

Based upon the equations above:

Record size = 3 + 1 = 4 Number of bytes to be stored per record (N) = 1 Hence the Database size = (128* 4) + 7 = 519 bytes.

Therefore the total number of updates available as computed from above for 8K sector = [(8192 -519) /4] x 100K = 191.8 M cycles.

However, 1 Byte Record size is inefficient and typical usage of EEPROM usually would require 8 to 16 bytes per record.

Assuming that the following Parameters would be applicable for a typical application

Number of bytes per typical record = 16 Number of Records to store = 2 (that is, Previous and Current).

Database Size = (2* 19) +7 = 45

Hence Total number of updates for 8K sectors

= [(8192-45) /19] X100000 = 42.87M

14/25 AN2040 - APPLICATION NOTE

Thus it has been shown that the EEPROM Emulation update endurance cycle is dependent upon the record size and the Database size. For a typical application it can easily provide greater that 40M updates cycles. The above formula applied to the supplied demonstration program would be computed as follows:

Number of bytes per typical record = 128 Number of Records to store = 1

Database Size = (1* 131) +7 = 138

Hence Total number of updates for 8K sectors

= [(8192-138) /131] X100000 = 6.148M

15/25 AN2040 - APPLICATION NOTE

APPENDIX B. EEPROM EMULATION DEMO CODE The two files, that would require modifications by the user to change the parameters to the algorithm are: eeprom.h eeprom.c Changes to be Made at Compile Time The current code provides the following definitions to the eeprom emulation C code and the mapping used for the demonstration program and the driver code implementation. Users may modify and then recompile these to match their needs.

// EEPROM Sector size is 8192 bytes // EEPROM_RECORD_SIZE and max_records (entered by application programmer) // must be defined such that // (max_records * EEPROM_RECORD_SIZE) + header size (7 bytes) <= 8192/2 #define EEPROM_RECORD_SIZE 0x0080 // size in bytes of each record-128Byte - #define SECTOR_SIZE0x2000// number of bytes per sector

// Addresses to use to invoke embedded algorithm in FLASH memory. Modify for your memory map. #defineBOOT_FLASH_SECTOR_0_XAAA (volatile unsigned char xdata *) 0x8AAA #defineBOOT_FLASH_SECTOR_1_XAAA (volatile unsigned char xdata *) 0xAAAA #defineBOOT_FLASH_SECTOR_2_XAAA (volatile unsigned char xdata *) 0xCAAA #defineBOOT_FLASH_SECTOR_3_XAAA (volatile unsigned char xdata *) 0xEAAA

#defineBOOT_FLASH_SECTOR_0_X555 (volatile unsigned char xdata *) 0x8555 #defineBOOT_FLASH_SECTOR_1_X555 (volatile unsigned char xdata *) 0xA555 #defineBOOT_FLASH_SECTOR_2_X555 (volatile unsigned char xdata *) 0xC555 #defineBOOT_FLASH_SECTOR_3_X555 (volatile unsigned char xdata *) 0xE555

// Sector base addresses. Modify for your memory map. #define SECTOR_0_BASE_ADDRESS 0x8000 #define SECTOR_1_BASE_ADDRESS 0xA000 #define SECTOR_2_BASE_ADDRESS 0xC000 #define SECTOR_3_BASE_ADDRESS 0xE000 // Secondary flash sector definitions #define SECTOR_00x00 #define SECTOR_10x01 #define SECTOR_20x02 #define SECTOR_30x03

// EEPROM error codes #define SECTOR_FULL0x80 #define FORMAT_FAILED0x81 #define ILLEGAL_RECORD_NUMBER0x82 #define INVALID_COMMAND0x83 #define INVALID_STATUS0x84 #define SECTOR_ID_ERROR0x85 #define EEPROM_INIT_FAILED0x86 #define SECTOR_ERASE_ERROR0x87 #define FLASH_WRITE_ERROR0x88 #define ADDRESS_ERROR0x89 #define INVALID_SECTOR_STATE0x8A #define FLASH_ACCESS_ERROR0x8B

// Direction indicators for sector swap #define F_READ0x00 #define F_WRITE 0x01 // Data Structures for EEPROM Emulation

16/25 AN2040 - APPLICATION NOTE struct record_entry { BYTE status; BYTE record_data[EEPROM_RECORD_SIZE];// data record byte struct record_entry xdata *last_record_update;// Pointer to next update. If 0xFFFF, this is the valid record. };

// The parameter table holds the data record information for the active sector. // Only one sector can be active at a time. struct sector_header { BYTE sector_status;// see sector status definitions for usage of this byte // this must be the first byte in the sector to facilitate erase checking BYTE sector;// sector number BYTE sector_checksum;// complement of sector - used to verify block is not corrupted WORD max_records;// set by application programmer when calling Init. WORD rec_length;// number of data bytes in each record (set to EEPROM_RECORD_SIZE in Init) };

// ******** User API Function Prototypes ********//

/***** 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);

/***** Eeprom_Init *****/ // Polls secondary flash for valid sector status byte and // Initializes boot flash sector containing data records after power up. // Restores any incomplete operations to last known good status. // Returns 0 on success. If error, returns 1. BYTE Eeprom_Init(void);

/***** Update_Record *****/ // Update record in EEPROM. // Accepts record id and new record data. // Returns 0 on success. If error, returns 1. // Will swap parameters to new sector when full. BYTE Update_Record(WORD id, BYTE xdata *buf);

/***** Read_Record_Data *****/ // Reads record data into a buffer. // Accepts record id number and buffer pointer. // Returns 0 on success. If error, returns 1. BYTE Read_Record(WORD id_number, BYTE* buffer);

// ******** Low Level Function Prototypes ********//

// Flash write routines

/***** Write_Record *****/ // Update record in EEPROM. // Accepts record id and new record data.

17/25 AN2040 - APPLICATION NOTE

// Returns 0 on success. If error, returns 1. BYTE Write_Record(WORD id, BYTE xdata *buffer);

/***** Boot_Flash_Write *****/ // Writes data to secondary flash. // Accepts address in flash to write, data byte. // Returns 0 for successful write. If error, returns 1. BYTE Boot_Flash_Write(WORD address, BYTE data_byte);

//Flash read routines

/***** Read_Record_Data_Structure *****/ // Reads an entire record structure from memory. // Accepts record id number. // Returns 0 on valid read. If error, returns 1. WORD Read_Record_Data_Structure(WORD id_number, BYTE* buffer);

/***** Boot_Flash_Read *****/ // Reads data from secondary flash. // Accepts flash address to read from. // Returns data. BYTE Boot_Flash_Read(WORD address);

// Flash erase routines

/***** Eeprom_Sector_Erase *****/ // Erases one boot flash sector. // Accepts sector number (0-3). // Returns 0 for successful erasure. If error, returns 1. BYTE Eeprom_Sector_Erase(BYTE sector);

/***** Eeprom_Sector_Erase_Start*****/ // Start Erases one boot flash sector. // Accepts sector number (0-3). // Returns 0 for successful erasure. If error, returns 1. BYTE Eeprom_Sector_Erase_Start(BYTE sector);

/***** Eeprom_Sector_Erase_Suspend*****/ // Susupend Erases one boot flash sector. // Accepts sector number (0-3). // Returns 0 for success. If error, returns 1. BYTE Eeprom_Sector_Erase_Suspend(BYTE sector);

/***** Eeprom_Sector_Erase Resume*****/ // Resume Erases one boot flash sector. // Accepts sector number (0-3). // Returns 0 for successful erasure. If error, returns 1. BYTE Eeprom_Sector_Erase_Resume(BYTE sector);

/***** Eeprom_Sector_Erase_Status *****/ // Gets status of sector erase. // Accepts sector number (0-3). // Returns 1 for erase in progress. If OK, returns 0. BYTE Eeprom_Sector_Erase_Status(BYTE sector);

// Database management routines

/***** Find_Next_Address *****/ // Finds next available address for data record.

18/25 AN2040 - APPLICATION NOTE

// Returns address. If error, returns error code. WORD Find_Next_Address(void);

/***** Find_Active_Sector *****/ // Finds active sector. // Returns sector number. // If error, returns error code. BYTE Find_Active_Sector(BYTE io);

/***** Eeprom_Sector_Swap *****/ // Transfers data from full sector to empty one. BYTE Eeprom_Sector_Swap(WORD inn, BYTE xdata *buf);

/***** ERASE and FORMAT SECTOR *****/ // Update record in EEPROM. // Accepts sector id, command, and max record size. // If error, returns error code. BYTE E_andF_Sector(BYTE sector, WORD max_rec);

/***** Get_Sector_Status *****/ // Returns sector status. // If error, returns INVALID_STATUS. BYTE Get_Sector_Status(BYTE sector);

19/25 AN2040 - APPLICATION NOTE

APPENDIX C. DK3200 EEPROM DEMONSTRATION PROGRAM The supplied demonstration program, with the drivers code for the EEPROM Emulation, is a simple C pro- gram that is used to provide arguments to the driver code. It sets up a counter to perform a number of writes to fill up the sector using the update function, as described earlier in this document. The driver sends an error code if it computes that the total number of records has exceeded the database size for which the sector has been formatted. The user can make changes to this code, or develop the application to call the functions described earlier in the driver code. In the sample application code, the run time argument sets input for 1 record of 128 bytes.

/*------DK3200_1_demo.c

Simple EE Emulation Demo code for uPSD

06/2002 Ver 0.1 - Initial Version 8/24/2004 - Modified for Checks and errors for 128- Byte Record size

Copyright 2002, 2004 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. ------*/

#pragma optimize(8,size) #pragma SYMBOLS #pragma NOAREGS

#include "upsd_hardware.h"// environment hardware specific defines #include "upsd3200.h"// special function register declarations for UPSD #include "lcd_io.h"// prototype declarations and defines for uPSD IP drivers #include "upsd_timer.h" #include "eeprom.h"

#include xdata PSD_REGS PSD8xx_reg _at_ PSD_REG_ADDR; // Define PSD registers at address "csiop" space

void main (void) { unsigned int i; // Counters for Emulation Total Count unsigned int j; // Counter unsigned char status; BYTE xdata buf[1]; //Buffer that holds data to write

20/25 AN2040 - APPLICATION NOTE

BYTE xdata tmpbuf[1]; //Buffer which holds data read back from the flash

// WDKEY = 0x55; // Turn off the Watch Dog Timer tmpbuf[0] = 0; // Initialize the temp buffer buf[0] = 0xAA; // Load the data pattern to write i=0; // Counter initialization -

PSD8xx_reg.VM |= 0x80; // enable peripheral I/O mode for LCD display

timer0_init(); // initialize timer0 interrupt lcd_init(); // initialize LCD. 8 bits, 2 lines, 5x7 font, // no blink, cursor off, clear printfLCD("EEPROM Emulation\n");//display on LCD printfLCD("DK3200 Sample \n"); delay_2sec(); // delay_2sec(); lcd_clear();

Eeprom_Init(); // EEPROM Routine Initialization if (status ==0x86) { printfLCD("EEPROM_INIT\n");//display on LCD printfLCD("FAILED\n"); delay_1sec(); while(1); }

status = EEPROM_Format(0x0001); // Format one record

/* Error Checks */ if (status ==0x82) { printfLCD("Illegal records\n");//display on LCD printfLCD("reduce number\n"); delay_2sec(); while(1); } if (status ==0x81) { printfLCD("Format Failed\n");//display on LCD printfLCD("Reset\n"); delay_1sec(); while(1); } if (status ==0x87) { printfLCD("Sector Erase\n");//display on LCD printfLCD("Error;Reset:\n"); delay_1sec(); while(1); }

21/25 AN2040 - APPLICATION NOTE j = 0;

{ while (i <=0x0030) { i++;

{ lcd_clear(); status = Get_Sector_Status(SECTOR_0); printfLCD("Rec Status:%x\n", status); printfLCD("#i=:%w\n", i ); delay_1sec(); // while(1);

}

buf[0] = j++;

// Update_Record(0, &buf); // Write record one with the content in buf[0] status = Update_Record(0, &buf); // Write record one with the content in buf[0] if (status) { lcd_clear(); printfLCD("WR.Error =%x\n",status); printfLCD("# i= %w\n",i); delay_1sec(); // lcd_clear(); while(1); } lcd_clear(); printfLCD("Write_Record\n");//display on LCD printfLCD("%x\n",buf[0]); delay_2sec(); lcd_clear();

Read_Record(0,&tmpbuf); // read the records status = Read_Record(0,&tmpbuf[0]); // read the records if (status) { lcd_clear(); printfLCD("RD.Error =%x\n",status); printfLCD("#i=%w\n",i); delay_1sec(); // lcd_clear(); while(1); }

22/25 AN2040 - APPLICATION NOTE if (tmpbuf[0] == buf[0]) // Compare the record { printfLCD("Read & Compare \n"); printfLCD("Compared_OK: %x\n",tmpbuf[0]); delay_2sec(); // delay_2sec(); status = 0; // lcd_clear(); } else { printfLCD("Read & Compare \n"); printfLCD("Miscompared \n"); delay_2sec(); lcd_clear(); status = Get_Sector_Status(SECTOR_0); printfLCD("Rec Status: %x\n", status); printfLCD("#i= %w\n",i); delay_2sec(); } // while(1);

} lcd_clear(); printfLCD("Status:%x\n", status); printfLCD("TOT #= %w\n",i); delay_2sec(); // status = 0; while(1); } } // End main

23/25 AN2040 - APPLICATION NOTE

REVISION HISTORY

Table 2. Document Revision History Date Version Revision Details 24-Sep-2004 1.0 First Issue

24/25 AN2040 - APPLICATION NOTE

If you have any questions or suggestions concerning the matters raised in this document, please refer to the MPG request support web page: http://www.st.com/askmemory

Information furnished is believed to be accurate and reliable. However, STMicroelectronics assumes no responsibility for the consequences of use of such information nor for any infringement of patents or other rights of third parties which may result from its use. No license is granted by implication or otherwise under any patent or patent rights of STMicroelectronics. Specifications mentioned in this publication are subject to change without notice. This publication supersedes and replaces all information previously supplied. STMicroelectronics products are not authorized for use as critical components in life support devices or systems without express written approval of STMicroelectronics.

The ST logo is a registered trademark of STMicroelectronics.

All other names are the property of their respective owners

© 2004 STMicroelectronics - All rights reserved

STMicroelectronics group of companies Australia - Belgium - Brazil - Canada - China - Czech Republic - Finland - France - Germany - Hong Kong - India - Israel - Italy - Japan - Malaysia - Malta - Morocco - Singapore - Spain - Sweden - Switzerland - United Kingdom - United States of America www.st.com

25/25