The great power and convenience of flash type eeprom is no doubt a major contributing factor to lessening the tedium of working with microcontrollers. Gone are the days of ultraviolet tubes to erase memory; everything is now easily handled rapidly from within the microcontroller itself.
Most PIC microcontrollers contain eeprom for holding both the program which guides the device, as well as data which might change occasionally over time. The program space can typically be erased and rewritten 100,000 times, while the data section might be good for some 1,000,000 cycles.
Data eeprom is generally used to store configuration values, messages to be displayed on an LCD, or perhaps readings logged from an external sensor. In the last case, the numbers can be stockpiled for later, useful for monitoring trends over time. On the other hand, the main purpose of program memory is pretty obvious. But in fact it too can be used as general purpose data storage if desired. You've just got to know how.
While the PIC data sheet is certainly complete (and lengthy) it's also fair to say it doesn't necessarily present its concepts in a friendly piecemeal fashion. That's where this tutorial comes in, reorganizing the material to build from simpler ideas to the increasingly more complex. Moreover, pseudo-code is employed to describe the action, revealing the big picture nicely, making it easy to quickly adapt the procedures to whatever language you prefer. With an experiment thrown in along the way, you should soon find yourself confidently working with PIC program eeprom and data eeprom in your own projects.
Basic Rules of Play
Let's get the initial conditions out of the way. I've selected the ever-popular PIC16F88 for what follows. While there are occasional variations among the various PIC chips, the PIC16F88 is fairly representative. It's easy to adjust for any differences later, once the essential ideas are mastered.
Neither the program space eeprom nor the data eeprom are memory-mapped in the manner so common several decades ago. They are instead manipulated by means of six essential registers, which the manufacturer prefers to call SFRs, short for special function registers. To keep things straight throughout this tutorial, all PIC registers will be indicated in capital letters, which is what your assembler or compiler would probably prefer anyway. User variables and other labels will be shown in lowercase.
Manipulating the Data Eeprom
Let's start to learn about these registers by investigating how the data eeprom is set up and then actually put it through its paces. (It's the simpler of the two eeproms). Naturally, every location has an address and a data value to be stored within it. In the PIC16F88 there are 256 locations; a single 8-bit register is sufficient to designate them.
Similarly, each location may hold a single byte. Therefore, the PIC16F88 sports the following two 8-bit registers for dealing with data eeprom:
EEADR ... 8-bit address of the desired location
EEDATA .. 8-bit contents of the desired location
Two other registers are used to indicate the operation to undertake. The first is called EECON1, but is made up of six bits of interest, each of which has a name as well.
(Most assemblers and higher level languages are aware of these names, so you can use them in your program code directly). Only four of these bits are needed at the moment.
EEPGD is used to select either the data eeprom or the program space eeprom. In the present case, we'll make it a zero to point to data eeprom.
The bit named WREN controls the write-enable. When set, a write to data eeprom is permitted; if cleared, not so. Obviously, this offers a bit of protection from careless mistakes. Bits WR and RD specify whether you are initiating a write or a read, respectively. Note that both of these are cleared in hardware once their operations conclude.
That's all we need from EECON1 at present, so let's turn to EECON2. I like to think of this register as being akin to a combination lock. Once again, its purpose is to keep you from inadvertently doing something disastrous. In particular, before carrying out a write operation, EECON2 is loaded first with 0x55, followed immediately by 0xAA. This is the "open sesame" to the eeprom writing machinery.
With that, we have everything needed to handle reads and writes on the PIC16F88 data eeprom.
Refer to the following now.
This shows the pseudo-code specifying the steps required to read a byte from data eeprom. It should seem pretty straightforward given your prep work from above. Keep in mind that the left-arrow is the assignment symbol; it means to store the designated value in the indicated register.
The next algorithm illustrates how to carry out a write; it's only vaguely more complicated.
The comments should make the steps pretty clear, but here are a couple additional observations. The empty while loop at the very start, simply spins indefinitely until any previous write operation is complete, meaning the data eeprom is ready for another byte.
Immediately before unlocking the chip for a write, you need to disable interrupts should you be using any. This is to ensure that the write isn't disturbed midstream. You can re-enable interrupts at the end if needed.
Getting Set for the Program Space Eeprom
Most high level languages fail to provide means to deal with program space eeprom from within software. That might lead you to suspect you're stuck with learning assembly language. Not to worry! In the experiment coming up, we'll see how to roll our own procedures to read, write and erase without recourse to an assembler.
Program space is considerably larger in size than data eeprom, 4096 words in the case of the PIC16F88. Thus, it's going to take two 8-bit registers to hold a desired address, all the way from 0x000 on up to 0xFFF. (Those are actually l2-bit addresses; the upper 4 bits are stuck on zero). We get to reuse EEADR for the lower 8 bits, but need a new register, EEADRH to hold the upper 4 bits.
What's more, each location in the program space can hold a 14-bit number in the 16F88. So, again, we’ll require an additional register to contain the upper 6 bits of the data value to be read or written. Putting this all together then, we have:
EEADRH + EEADR .... 12-bit address of the desired location
EEDATH + EEDATA .. 14-bit contents of the desired location
There are two further bits within EECON1 to be considered now. FREE is employed to indicate an erase operation is desired. Otherwise if clear, a write will occur.
The bit labeled WRERR flags errors. This is primarily used to catch the problem of a reset occurring in the middle of a write operation. If set, then you'll know something interfered and you can try again.
Enough chatter! You've attained the prerequisites to tackle program space eeprom now.
Reading from Program Eeprom
Here's the pseudo-code for reading from program space eeprom.
It's not much more tricky than that for the data eeprom seen earlier. But there is one hiccup you want to watch out for.
Catch the two NOP operations in the middle. (NOP is a dummy, do-nothing op-code). These are required, but not for the usual timing delays you might expect. In this case, once the read operation has started, apparently the program counter keeps chugging away while memory is accessed. These two one-cycle commands are simply passed over while that's going on. In any event, immediately after the second NOP, the data is available and can be read from EEADRH + EEADATA. Incidentally, most high level languages like C, Basic and Pascal have mechanisms to permit embedding an assembler command like NOP midstream.
Erasing Program Eeprom
Here's where things get a bit more messy. In the PIC16F88, you are only permitted to erase program eeprom in blocks of 32 words at a time. Moreover, those blocks must be aligned. Consider the arithmetic. With 4096 words of program space, there are exactly 128 blocks of 32 words which can be erased. No fair crossing a boundary! So, for example (and in decimal for clarity), you may clear out locations 0 to 31, but not 1 to 32
The FREE bit was mentioned above. Now we get to see it in action. By setting it, the PIC knows that an erase (not a write) is desired. Putting it all together, then, we wind up with the procedure below. Be sure to note how EECON2 is used once more to unlock the chip to keep us from foolishly erasing memory when not intended.
Writing to Program Eeprom
And with that, we come to the final operation on PIC program eeprom. This is by far the most complex, for several reasons.
First, you need to know that the PIC16F88 can only write four words at a time -- no more, no less -- and again, those words must be aligned on binary boundaries. To emphasize, writing to locations 0 to 3 is okay, but 1 to 4 isn't.
Adding to the complexity is that indirect addressing is used to point to the data to be written. You might recall from previous work with the PIC that this is handled by the two registers FSR and INDF. In particular, FSR points to a desired location (an address), but the content of that location (a value) is found in INDF.
With that, let's jump into the final piece of pseudo-code.
You'll recognize quite a lot from before. What's new is the repeat loop counting downward to fetch all four words (eight bytes total) from a RAM array called -- surprise -- array. This is where the indirect addressing scheme described above comes in. The main thing to understand is that all four words must be written. They're actually held within internal buffers, and when the fourth is loaded, the quartet is written in one fell swoop, the only kind of swoop worth having!
A Few Words on Code Protection
If you check out the data sheet for the PIC16F88, you'll notice that there are two configuration bits labeled CP and CPD. These are the code protection fuses for program eeprom and data eeprom, respectively. Beginners are often confused by these. Neither has any bearing on what we've been doing. Rather, they exist simply to protect the two eeproms from your flashing hardware (not the program itself, which always has access).
Finally, configuration bit WRT allows you to disable writing to various portions of the program space eeprom should that be important to you. As a rule, the three bits just mentioned are generally employed by manufacturers concerned with guarding their intellectual property.
And the Experiment
If you've gotten this far, then you're no doubt chomping at the bit to see how it all works, with your own eyes. So, head to the workbench and set up the following experiment to demonstrate what you've leaned. We'll connect the PIC to a microcomputer running terminal software. Then we can read, write and erase both the data eeprom and program eeprom directly from the terminal and monitor the results.
Use the following schematic:
You'll note I'm using a breakout board to generate the RS-232 levels. You can find more information on this part in one of the exercises here.
Here's a photo showing what it looked like when I whipped it together.
Incidentally, I used a $4 USB-to-Serial adapter on the other end, since most computers nowadays don't have COM ports. To complete the demo, you'll need the source code, which you can get here:
The firmware in the PIC actually takes over and guides you through the various demos. The following screen-shot of the terminal program, shows the action in progress. You'll observe that everything is menu-driven.
With that, you should now be well poised to begin using PIC eeproms in your own projects. And though PICs vary somewhat from model to model, you’ve also learned enough to make sense of that dense data sheet.
Next Tutorial: Resets