An2040 Eeprom Emulation and Data Record Storage Using The Upsd32xx Stmicroelectronics
An2040 Eeprom Emulation and Data Record Storage Using The Upsd32xx Stmicroelectronics
APPLICATION NOTE
EEPROM Emulation and Data 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 Write/Erase cycles).
One of the main differences, from the user point of view, between EEPROM and a uPSD device (which
includes an extremely large Flash memory array) is the minimum granularity for erasing data. Typically,
EEPROM allows the user to modify single byte 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 Block 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 document)
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, read record, update record
■ Clean-up and internal data management transparent to the user
■ Background sector erase
■ Code in main Flash memory, database 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 eeprom.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).
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. Data Integrity 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
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 bytes).
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 data structure 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 data recovery 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
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
Update Record
Request
Sector No
Full? Update Record
Yes
Get Sector
Headers
New
Sector No
Erase Sector
Erased?
Yes
Transfer Data
to New Sector
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).
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
Read
Record
Update No
Data?
Yes
Get Next
Available Address
No Yes
Finished
AI10248
9/25
AN2040 - APPLICATION NOTE
10/25
AN2040 - APPLICATION NOTE
11/25
AN2040 - APPLICATION NOTE
■ Click “Specify project” in “design flow”. In the drop down menu, select the “Open a exist project” item.
Point to the PSDsoft directory 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 path 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
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
Emulated Record Size = 3 + N bytes (Where N is the number of Bytes stored per record)
While
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:
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
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:
15/25
AN2040 - APPLICATION NOTE
// 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
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)
};
17/25
AN2040 - APPLICATION NOTE
/***** 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);
18/25
AN2040 - APPLICATION NOTE
19/25
AN2040 - APPLICATION NOTE
/*------------------------------------------------------------------------------
DK3200_1_demo.c
#pragma optimize(8,size)
#pragma SYMBOLS
#pragma NOAREGS
#include <stdlib.h>
xdata PSD_REGS PSD8xx_reg _at_ PSD_REG_ADDR; // Define PSD registers at address "csiop"
space
20/25
AN2040 - APPLICATION NOTE
BYTE xdata tmpbuf[1]; //Buffer which holds data read back from the flash
if (status ==0x86)
{
printfLCD("EEPROM_INIT\n");//display on LCD
printfLCD("FAILED\n");
delay_1sec();
while(1);
}
/* 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++;
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();
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
}
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
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.
25/25