EEP!

Previously on My Hobbies, I showcased how the Arduino could read from the cardreader. Since then, I added code to save and load cards from EEPROM. What's EEPROM, you ask? Good question!

EEPROM is an unpowered rewritable type of memory. When a program's running, the Arduino stores variables in RAM (Random Access Memory). This memory is durable for many read-write cycles, but zeroes out when power's lost. EEPROM (Electrically Erasable Programable Read Only Memory) is only good for about 100,000 read-write cycles, is fairly slow (3.3ms/read), and only stores bytes (8 bits), but retains data across reboots.

Quick aside: The name EEPROM contains a contradiction. How is memory read only and erasable?

The answer lies more in history than anything. Early PROM (Programmable Read Only Memory) chips were programmed permanently. Programming these chips burned out internal fuses (tiny wires), leaving a physically changed circuit.

The next iteration of the chips, EPROM (Erasable Programmable Read Only Memory; image above), allowed for reprogramming. Exposing the die of the board to a UV light would reset it to an unprogrammed state.

EEPROM is a third iteration of ROMs. The Read Only restriction is long gone, but lives on in the acronym.

I want my circuit to remember a list of accepted keys - my housemates, some friends, and I. Losing the approved keys on reboot would be frustrating, so I need to use the EEPROM. By the same count, overusing and burning out the EEPROM would be useless.

I decided to use both types of memory to store and check keys. Whenever a key is added to the approved list, the Arduino writes all approved keys from RAM to EEPROM. On boot, it reads the list of keys out of EEPROM, back into RAM. When checking keys, it uses the RAM-based list.

As discussed before, the keys are stored internally as a long (32 bits of data). The cards have 35 bits of data on them, but storing only the last 32 is substantially simpler. Writing those keys to the EEPROM, 8 bits at a time, presented issues. I wanted to split the key into four bytes and write those to four consecutive EEPROM addresses:

KEY: 011011001011011110100100001100010101
TRC: 11001011011110100100001100010101
EEP: 11001011 01111010 01000011 00010101
KEY is the original key. TRC is the key, truncated to 32 bits. EEP shows the key split into bytes. Those four bytes need to be stored or read from EEPROM.

Within the Arduino platform, resizing arrays is difficult, if not impossible, so the list of accepted keys needed a fixed size. I chose 255 keys as a nice, round number. The EEPROM is 1kB (1024 bytes) long, so I decided to reserve all addresses from 900 to 900+255*4 for keys. Address 0 is reserved for the number of keys, and is used when loading. (Yes, the EEPROM would overflow if we hit the cap. No, we won't come near the cap.)

Breaking a long into four bytes is surprisingly hard. Order and such become important. And typos are nearly impossible to debug on a microcontroller. The code I wrote exploded at me after a while. Fortunately, someone else wrote code that will store or read a long to EEPROM, saving me the trouble!

The next task was creating a key-entry function. When key-entry mode is triggered by a button, the Arduino commands the reader to blink its LEDs and beep briefly every half second until a key is recieved. As soon as the Arduino recieves the key, it disables the reader (to prevent incoming data from changing the stored key value). The new key is checked against the list of accepted ones to prevent duplicate entries. If the key isn't already accepted, then it's saved to the first zero index of the accepted keys array. (The array is initialized to contain only zeroes. As keys are loaded, the zeroes are replaced with valid keys.) Finally, the entire keys array is saved to EEPROM.

God. This is getting complicated.

When all's said and done, the code reads 1's and 0's from the reader. If the last read key matches an internal list, the Arduino moves a servo, which opens the door. Otherwise, nothing happens. If the unlock button (inside, to let us out) is pressed, the door unlocks. If the add key button is pressed, then the Arduino approves the next key swiped for opening the door. Whenever the list of keys changes, keys are saved to EEPROM - nonvolatile memory.

Current code is attached below.