Mitigate Power Failure Programming Issues Using EERAM
In this how-to article, we explore the use of I2C EERAM to save critical program variables when power fails and restore them when power returns to easily preserve program continuity.
In this how-to article, we explore the use of I2C EERAM to save critical program variables when power fails and restore them when power returns to easily preserve program continuity.
Power failures are inevitable. When power returns, your program restarts, but with the contents of all of the variables lost. Often times, it would be advantageous to have critical values saved and made available when power returns. EERAM makes it easy to do just that.
In this article, we will explore the use of EERAM and build a simple demonstration project that will automatically save a program variable when power fails and then restore it when power returns.
What is EERAM?
Simply put, EERAM, manufactured by Microchip, is an I2C static RAM (SRAM) with a shadow EEPROM backup. The user's program does not directly access the EEPROM but freely uses SRAM, which offers fast access and near-permanent endurance.
Storage of SRAM to EEPROM can occur through software or a hardware signal. Most notably, however, is that with the addition of a simple capacitor, the entire SRAM array can be automatically saved to EEPROM when power is lost. In all three cases, when power returns, the contents of the EEPROM are automatically transferred to SRAM.
|47L04||2.7-3.6V||4kbits (512 bytes)||0x000-0x1FF|
|47C04||4.5-5.5V||4kbits (512 bytes)||0x000-0x1FF|
|47L16||2.7-3.6V||16kbits (2 kB)||0x000-0x7FF|
|47C16||4.5-5.5V||16kbits (2 kB)||0x000-0x7FF|
From the table above, two densities are available and each comes in two voltage and temperature ranges. All devices have an I2C serial interface with speeds of up to 1 MHz.
Be sure to consult the following EERAM reference PDFs:
For all of our examples, we will use an Intel Quark Microcontroller D2000. For more reference material on the D2000 board and applications, including how to use GPIO and the I2C interface, the following All About Circuits articles are available:
C source code (QMSI 1.40, ISSM_2016.2.094) for the examples and the project are available for download at the end of the article.
While our example programs and circuits use the D2000, they should be easy to adapt to any microcontroller that has an I2C interface and GPIO.
Basic EERAM Interface
Schematic for the basic EERAM interface to a D2000.
The schematic above illustrates a typical microcomputer interface for EERAM and can be used with the included software examples.
**Note that GPIO_3 only needs to be connected if you are using the hardware store (HS) feature.
|Component||Description||Source / Price|
|IC1||47L04 EERAM||Digi-Key 47L04-I/P / $0.92|
|C1||6.8 µF tantalum capacitor||Digi-Key 478-1918 / $0.31|
|C2||0.1 µF ceramic capacitor||Digi-Key 399-14001 / $0.32|
|R1,R2||10 kΩ resistor||Digi-Key CF18JT10K0CT / $0.10|
IC1 is an ‘L’ device EERAM with a Vcc range of 2.7-3.6V. Since the D2000 is a 3.3V board, it is the appropriate version and the same connections can be used for the 47L16. If you were using a 5V board, then the ‘C’ versions (i.e., 47C04 or 47C16) would be appropriate.
SDA/SCL. These two lines are the usual I2C clock and data signals accommodating transmission speeds up to 1 MHz. Note that R1 and R2 are the required pull-up resistors. Microchip recommends a typical value of 10 kΩ at 100 kHz. While the D2000 board’s software can accommodate 100 kHz, 400 kHz and 1 MHz speeds, all of our software examples use the 100 kHz speed, and, thus, the 10 kΩ resistors.
A1 and A2 address lines. Unlike a typical I2C serial EEPROM, EERAM devices have two device addresses (see figure below). There is an address to access a control register and another to read and write the SRAM array.
EERAM I2C device addressing. Figure courtesy of Microchip, EERAM data sheet.
The 8-bit I2C addresses are formed by a fixed opcode for bits 4-7 (either binary 1010 for SRAM or binary 0011 for the Control register), and bits 2-3 correspond to the state of pins A1 and A2. If these pins are grounded, the associated address bits have a value of ‘0’ and if tied to Vcc, they have a value of ‘1’. Bit 1 of the address is always ‘0’.
The 8-bit I2C address includes the least significant bit as a ‘1’ for read and a ‘0’ for write. Since the operating system routines for I2C communications handle the latter bit, we can treat the device addresses as a 7-bit value for programming considerations.
In our schematic (and for all included programs) A1 and A2 are at ground; the Control register is addressed with binary 1010000 (0x18), and the SRAM array is addressed with binary 1010000 (0x50). Note that access to the A1 and A2 pins allows the use of up to four EERAM chips on the same system.
Hardware Store (HS) pin.The HS line is attached to the D2000 GPIO 3. This connection is only needed if you want to use the hardware store feature. That is, the HS line can be brought ‘high’ to initiate storage of SRAM to EEPROM. If you do not want to use this feature, the line can be left unconnected.
Vcap. If you want to use the automatic storage of SRAM to EEPROM upon a power failure, you need to attach a capacitor from the Vcap pin to GND. The choice of the capacitor is important and Microchip offers an application note precisely to address that issue (see AN2257A).
EERAM auto storage and recall voltages. Figure courtesy of Microchip AN2257A.
This capacitor must provide the necessary energy to automatically store and recall the contents of the SRAM to and from EEPROM. The capacitor must be large enough for the Vcap voltage to be maintained above VPOR (power-on reset voltage) level throughout the entire storage cycle.
Microchip has conveniently provided the minimum Vcap values in a table (see Table 3, AN2257A). Note that the minimum values depend upon the voltage and density of the device. For the 47L04 device we are using, the minimum value for Vcap is 5 µF.
To meet the minimum value, we have to consider the tolerance of the capacitor which is listed in the component’s data sheet. For the capacitor we chose for C1, the value is 6.8 µF with a tolerance of ±20%. Thus, at the low end of the tolerance, we have a value of 5.44 µF and remain above the minimum capacitance required. In many cases, there is no need to minimize cost or component area, and thus you can ensure robust operation by simply choosing a larger capacitor (say, 10 µF).
It is possible to use EERAM without the auto-store feature and the external capacitor on Vcap. In that case, the Vcap pin should be tied to Vcc and the Auto-Store feature must be disabled by writing the ASE bit in the STATUS register to a ‘ 0’ (see Control Registers section below) to prevent data corruption.
Bypass capacitor.The final component in the schematic is C2, the bypass capacitor. The typical and recommended value is 0.1 µF.
Programming the Control Registers
EERAM programming can be divided into two parts, control register programming and SRAM access programming. Each uses a different I2C device address.
Furthermore, EERAM has two control registers: a status register and a command register. The status register can be read from or written to. The command register is write-only and has two commands, one to save SRAM to EEPROM and the other to restore SRAM from EEPROM.
Each of these registers (status and command) has its own address: 0x00 for the status register and 0x55 for the command register. These addresses are not to be confused with the I2C device addresses. Instead, they are sent as a secondary address after the I2C device address, but only when writing to a control register. When reading from a control register, the register address is not used since only the status register can be read.
EERAM status register bit definitions. Figure courtesy of Microchip, EERAM data sheet.
Consultation with the data sheet will provide details on the register bits, but a few points to note are the following:
- The ASE bit must be set if you want to automatically save (auto-store) SRAM to EEPROM on a power failure.
- If the AM bit is not set, then auto-store and hardware store (using the HS pin) are not enabled. This makes sense since the AM bit, which is read-only, is automatically set when you change the contents of the SRAM array.
- See TABLE 2-7 of the EERAM data sheet for the complete storage/restoration truth table with regard to the ASE and AM bits.
- Some, or all, of the array can be write-protected by setting bits in the status register that correspond to memory blocks (see data sheet for details).
The included program, EERAM_CNTRL_STATUS_REG.C, will display, and optionally write, to the status register. This program makes it easy to configure the EERAM chip for your particular application.
The three program variables shown in the program fragment below should be configured by the user before running the program.
/* ---> NOTE: User should set the next THREE variables <--- */ bool Hdensity=NO; /* chip density, either NO/0=47x04 or YES/1=47x16 */ bool WriteStatus=NO; /* If YES, write newval to STATUS register if NO skip the write */ /* uint8_t newval=0b00000010; no blocks protected, enable auto store, clear EVENT bit if set */ uint8_t newval=0b00000000; /* no blocks protected, disable auto store, clear EVENT bit if set */
Set the Hdensity variable to ‘NO’ if using the 47x04 chip or to ‘YES’ for the higher density 47x16 chip. If you only want to read the status register, set WriteStatus to ‘NO’. If you want to both read and write the status register, set WriteStatus to ‘YES’ and set newval to the 8-bit value that you want to write to the status register.
The figure below shows the screen output to a serial terminal after running the programming and setting the ASE bit.
Screenshot from output of EERAM_CNTRL_STATUS_REG.C.
The second control register is the command register. It is write-only at a secondary address of 0x55. The command can be either a store (0x33) which copies SRAM to EEPROM or a recall (0xdd) which copies EEPROM to SRAM.
Two bytes are written to the I2C device address to use either command:
- Byte 1 is the command register address (0x55).
- Byte 2 is the command (either 0x33 for a store or 0xdd for a recall).
After sending the sequence you have to delay for an interval that is defined in the AC characteristics in the data sheet. The interval includes the status register write cycle time (Twc) which is 1 ms, plus either a recall delay (Trecall) or a store delay (Tstore) depending upon which command you execute. Trecall and Tstore depend on the device density: for the 47x04 devices, Tstore=8 ms and Trecall=2 ms; for the 47x16 devices, Tstore=25 ms and Trecall=5 ms.
One caveat to consider is whether you use blocking or non-blocking calls for I2C. In all of the included programs, we use blocking calls for I2C communications. Thus, we begin the delays after the I2C transfer blocking call knowing that the I2C transfer completes before the call returns. If, however, you use non-blocking calls, then you must explicitly begin the delay after your program has acknowledged completion of the transfer—normally in the associated callback routine. Otherwise, you may unknowingly be delaying less than the required interval after sending the command.
The included program, EERAM_CMD_SR.C, demonstrates the uses of the software save and recall commands.
To write a byte at a specific address, write to the I2C device address for SRAM (0x50 for our implementation) as described earlier, sending the high byte of the address followed by the low byte of the address and, finally, the data byte.
Reading a byte from the SRAM array is a two-step process. First, set the address to the location in the array that you want to read in the same way as with a write byte. Without sending a stop bit, read the byte from the I2C device address and the EERAM transmits the data byte at the address selected.
The included program, EERAM_RW.C, demonstrates the process by reading and writing a single byte. If you examine the two functions readbyteC(uint16_t address) and writebyteC(uint16_t address, uint8_t byte), you can see the coded implementation of the steps outlined above. Note that both routines use error checking and return a variable of type int. If the return value is negative, it is either -999 if the address is not valid or a negated errno value. If the returned value is a non-negative number, it is the valid value from the addressed memory in the case of a read or a 0 in the case of a valid write.
We can also read or write the SRAM sequentially (i.e., multiple consecutive bytes). The details of the procedure are given in the EERAM data sheet and the included program, EERAM_S_RW.C, which will read and then write the entire SRAM memory array using the sequential access procedures. To use the program, the user should first set two program variables, Hdensity and bytevalue (the byte value to be written to all locations).
When attached to a serial terminal, the program will output the entire memory array before and after setting the memory locations (see screen output below) and also report any discrepancies between values written and subsequently read.
Screen output from running EERAM_S_RW.C. All memory values were changed from '255' to '170'.
Using the HS Pin
To initiate a hardware store, simply take the HS pin to logic high for at least Thspw (150ns, see EERAM data sheet). This will automatically cause a write to the status register to set the Event bit and will require a delay of Twc (1 ms) to complete, independent of whether storage takes place (see below).
For storage of SRAM to EEPROM, the AM status register bit needs to be set, meaning that the SRAM array has been modified. When storage takes place, a delay (Tstore) is required for completion. The included program, EERAM_HS_Save.C, demonstrates the procedure and assumes that the HS pin is connected to GPIO_3 as per the schematic.
Note also that the Event bit in the status register will be set whenever the HS line is activated, regardless of whether the AM bit is set and storage actually takes place. The Event bit is nonvolatile (meaning it retains its state even if power is removed) and must be reset by specifically writing a ‘0’ to that bit in the status register.
With a modest toolset of programs to explore EERAM, we are ready for an example application project. This simple demonstration will use a standard 7-segment display connected to GPIO pins on the D2000.
The BOM for the circuit consists of just two components:
- DIS1 – LSHD-A103 common cathode 7-segment display (Mouser, $0.66)
- RN – 330 Ω resistor network (14-pin) (Mouser, $0.80)
The schematic below details the circuit:
Circuit schematic for the D2000 to 7-segment display.
This circuit along with the basic EERAM circuit makes up the entire project.
Many examples of using a 7-segment display exist and rather than go into the details of the basic operation of the display, you can read up on the background of the interface in this previous AAC project and in the AAC textbook.
In our project, the display will simply cycle through the digits 0-9 continuously, with a 3-second delay between changes. Normally, after a power failure, the program would reinitialize when power returned and begin the cycle at the initial programmed value.
What makes this project different, however, is that we will use EERAM to automatically save the digit value upon a power failure. When power returns, the digit value will be restored and the count will continue with the value that was present when the power failed.
The complete program for the project, EERAM_7_segment.C, is liberally commented and the following narrative is offered for further explanation.
You must set the ASE bit in the status register to enable auto storage before running the program (see the section describing EERAM_CNTRL_STATUS_REG.C). The demonstration program only uses the auto-storage function and not the software or hardware storage capabilities explained previously.
The program uses the global variables LOC1pre and LOC2post to designate two addresses in EERAM to hold the digit value. We have arbitrarily chosen addresses 200 and 202.
The program’s main() function first delays for the appropriate interval to allow the EEPROM to be transferred to SRAM on power-up. Subsequently, GPIO and I2C are initialized and the SRAM locations in LOC1pre and LOC2post are read to determine the value of the digit before entering the counting and display loop.
The basic approach is to execute a counting and display loop that
- reads the current value of the digit from SRAM (LOC1pre and LOC2post),
- updates that value,
- saves the value in SRAM (LOC1pre),
- changes the value on the display,
- updates the value in SRAM (LOC2post), and
- then waits three seconds before doing it again.
When the previous value is ‘9’ it is updated to ‘0’. That is simple enough, but there are some wrinkles.
First, we are saving the value of the digit twice, once (LOC1pre) immediately before changing the display, and once (LOC2post) immediately after changing the display. This scheme is implemented because it is possible that power could be interrupted after updating the display variable but before completing the update of the display. (Admittedly, this is unlikely, and I have never seen it occur during testing.) Such an occurrence could be detected, and it is conceivable that you may want to handle updating in a particular fashion if it does occur. In the included program, we simply call a dummy routine (mismatch(void)) if the situation is detected, but we assume the value of LOC1pre as the digit count.
The program also needs to be able to detect when it is first run to set the initial value of the digit count. In this case, an assumption is that the first time that the program is run, the value of LOC1pre and LOC2post are ‘255’. Thus, these locations must have a starting value of 255, which can be accomplished using either of the utility programs EERAM_S_RW.C or EERAM_RW.C. If those locations are read as ‘255’, then the count is initialized to ‘0’.
We also check for an invalid value for the count, which is any value greater than 9 and less than 255. This would only be expected to happen if the values read were corrupted or there was some kind of unintentional programming error. In this case, a terminal error occurs and a function that flashes ‘E’ on the display is entered. The function is also called in the event of I2C transmission errors. Except when explicitly testing the function, I have never observed this occurrence during testing.
At this point in the program flow, a valid count value has been found and it is displayed. That count is the saved value from EERAM, restored from EEPROM if there was a power failure, or it is the initial value when the program is first executed. After a delay of 3 seconds, the program enters the main counting and display loop.
The rest of the program contains support functions that should be easily understood through the comments in the code.
The completed project on breadboards (left: the EERAM circuit; right: the 7-digit display circuit).
You can turn the power off as you like and, when power returns, the display will show the value when power was removed and continue on from there.
While the program is a simple demonstration, it should be easy to see how the procedure could be expanded to save and restore multiple program variables, as well as other data.
EERAM provides a relatively easy and economical way to address problems related to the loss of variables and data following a power failure. It does require some programming overhead—but, in my opinion, it is simpler and more easily implemented than constructing the circuitry required to maintain power long enough to write the same content to a separate EEPROM.
Because the user program only interacts with SRAM, issues of EEPROM endurance are minimized since writing to the EEPROM only takes place after a power failure or an explicit action under program control. The additional features of hardware-initiated storage, software storage/recall, and memory block protection provide additional flexibility.
Program files for the project can be downloaded by clicking the link below:
Give this project a try for yourself! Get the BOM.