Once in a while I start out with the intention of doing something specific and then get totally distracted by other things. Ok, so it happens a lot. The good news is that it has nothing to do with my advancing age. As I like to say “I was ADD before ADD was cool”. Microcontrollers have memory issues of their own because any data they may have generated gets lost when power goes away. But there is hope because many micros, like the PIC, also have some non-volatile data memory if you can only figure out how to get to it. Well, in this post that’s exactly what we will figure out. Now, where did I leave my glasses?
As many of you already know, the acronym EEPROM stands for Electrically Erasable Programmable Read Only Memory. I know it sounds contradictory because part of what we will do here is to write data to the memory. Technically, however, the write process is not like simple writes of RAM that we normally do in the software. What we actually do is to go through several specific steps to program data into the memory. The reads are a little bit simpler but are still more difficult than reading RAM. That limits the reasonable applications for this type of memory, but don’t forget the big benefit of having the PIC retain the data after power shuts down.
As we will see later in the software discussion, the specific steps involved require that we set up an address register and the appropriate flags for each byte we want to read or write. We also need to maintain our own address pointer if we plan to write several locations. Finally, we need to ensure that the write operation has sufficient time to complete before we do other stuff. That last part also means that we need to make sure that interrupts don’t hijack the write operation. Reads are not as timing critical because the data is transferred immediately to the data buffer after the Read command is issued.
As you can see in the diagram, there really isn’t any hardware added to the PIC other than the LCD serial shift register interface that was detailed in earlier posts. What this gives us, however, is a good platform for another post where we actually do something useful with what we learn here. In particular, we combine a couple of interesting features to make a simple data collection system.
The software link is listed below. While it is targeted for the 16F688, it is easily ported to other versions of the PIC. You will need to change the line that identifies the PIC version (LIST=) and the INCLUDE file but those are intuitive changes. The __CONFIG line may also need tweaking just because one or two of the labels used are spelled differently in some of the INCLUDE files.
Most of the software pertains to the LCD handling and the delay routines so those parts should be familiar if you looked at some of the previous episodes. One thing to note up front is that the variable declaration section (UDATA) is a little different. Because the EEPROM control registers are all in Bank 1 memory, I decided to also place the variables EE_Addr and EE_Data in Bank 1. That required the use of labels as part of the UDATA start address statements. Bank 0 data starts at address 20 hex while Bank 1 data starts at address A0 hex. We also need to be mindful throughout the program as to what memory bank we are in when reading and writing. My general rule, as stated in the header, is to always exit a subroutine in Bank 0.
Because we are using registers specific to the EEPROM for reads and writes, there is no need for us to worry about where in the address map the EEPROM is located. That makes life a bit easier because we basically just provide an index from 00 to FF hex. Many of the PICs have 256 bytes of EEPROM but some only have 128 bytes (for instance the 16F627/8) so be aware of that for your applications.
The code for reading and writing the EEPROM is derived from what is listed in the datasheet but there are a couple of important differences, particularly in the Write section. For a read, we simply set up the desired address in EEADR, point to data memory (as opposed to program memory in flash), command a read, and then read the data from register EEDAT. The write process follows some of the same steps but with some notable differences in the middle of the sequence. Again, we start by setting the desired address in EEADR and then fill EEDAT with the data byte we want to write. Next we have to set a “write enable” flag. You can think of that like the R/W pin on memory chips or the LCD display. As mentioned earlier, we must allow the write process to complete without interruption so this is the point at which we would clear the GIE flag. If you look in the datasheet, there is code there that actually clears GIE and then loops until GIE is clear. That is put there because of the possibility that an interrupt may occur before the clear of GIE actually takes effect (four clock cycles or one instruction cycle). Because the return from the interrupt handler re-enables GIE automatically, our clear command may get superseded. So what is recommended is to just loop on the clear command until we actually complete a read of GIE and verify that it is clear.
Now comes the code to perform the secret handshake needed for writes. Really, all we do is to first write 55 hex and then write AA hex to EECON2. I’ll leave it as an exercise for the student to calculate the probability of that sequence happening by accident. After the secret handshake, we set the actual write command flag and then wait for the PIC to clear the flag. It will do so when the write has completed. Since we can’t do anything else during the write time, polling this flag is really the easiest way to accomplish this task. The datasheet example shows a SLEEP command with the assumption being that we will wake up and continue when we get an interrupt (EEIR) at the completion of the write. What it doesn’t show, however, is the setup for that interrupt and the handling of the interrupt prior to continuing execution. Once again, the lazy way triumphs.
The Test_EEPROM routine just sends three data bytes to EEPROM and then reads them back. Each byte that is written or read is sent to the LCD for display. Nothing too useful at this point but it shows how we can access the EEPROM for future projects.
Here is a picture of the expected results for this program. That’s it for this post. Check out my other electronics projects.