EEPROM

reads, writes, and erases a 256-byte serial EEPROM.

One of the best features of the BASIC Stamp hardware is the 93LC56 serial EEPROM. The Stamp uses this device for program space, lookup tables, and nonvolatile data storage.

The program listing presents a series of subroutines that read, write, erase, write-protect, and write-enable the 93LC56. These routines are not port- and pin-independent. The program is based on the circuit shown in the illustration. If you need to change this circuit, make sure to change both the equates for D, CLK and CS, and the data-direction settings for the EEPROM port (mov !ra,x). These are at the start of the program, and in the subroutines EEread and Busy.

The program, which originally appeared in Parallax PIC Application Note #11, writes a rotating bit pattern to the EEPROM, then plays it back on a bank of eight LEDs connected to port RB. Not very exciting, but it verifies every storage cell of the EEPROM with a minimum of programming. Not all programs require the entire set of subroutines. Some are included just for the sake of demonstrating all the EEPROM's capabilities. For example, most programs can do without the routine that erases individual bytes, since a write accomplishes the same thing. And very few programs need to completely erase the EEPROM, or write a single value to all cells. So you should be able to remove EErase, EEwipe, and EEwrall to conserve program-memory space.

For more information on the EEPROM's characteristics and capabilities, please see the current edition of the Microchip Embedded Control Handbook.

Demonstrating EEPROM.

To see EEPROM in operation, connect the circuit below to an erasable PIC or PIC emulator, such as the Parallax downloader. Assemble and run EEPROM.SRC. When you apply power to the PIC, it will write a scanning pattern to the bits of the EEPROM, then read this pattern back onto the LEDs.


; EEPROM (related subroutines)
; This is a collection of subroutines for reading, writing, and
; erasing the 93LC56 (or 'C56) serial EEPROM. As a demonstration, it 
; writes a scanning pattern to the 256 bytes of the EEPROM, and then
; reads it back to eight LEDs connected to port rb. 

D       =       ra.0    ; Pins DI and DO of the EEPROM
CLK     =       ra.1    ; Clock pin--data valid on rising edge
CS      =       ra.2    ; Chip select--high = active
ROP     =       192     ; Opcode for read
WROP    =       160     ; Opcode for write
EWEN    =       152     ; Opcode to enable erase and write
EWDS    =       128     ; Opcode to disable erase and write
ERAS    =       224     ; Opcode to erase a byte
ERAL    =       144     ; Opcode to erase all bytes
WRAL    =       136     ; Opcode to write all bytes

        org     8
temp    ds      1       ; Temporary variable for EE routines
EEdata  ds      1       ; Data to EEwrite/wrall, from EEread
EEaddr  ds      1       ; Address to EErase, EEwrite, EEread
clocks  ds      1       ; Number of clock cycles for SHiftOUT
tick1   ds      1       ; Timer for demo. 
tick2   ds      1       ; Timer for demo. 

        device  pic16c54,xt_osc,wdt_off,protect_off
        reset   start
        org     0
start   mov     ra,#0   ; Clear ports
        mov     rb,#0   
        mov     !ra,#0  ; Make all ra pins outputs initially. 
        mov     !rb,#0  ; Output for LEDs. 
        call    EEnable ; Turn off write/erase protection. 
        mov     EEdata,#1       ; EEdata = 1. 
        mov     EEaddr,#0       ; Start at address 0. 
:loop   call    EEwrite         ; Write pattern to EEPROM
        call    Busy    ; Wait until done writing. 
        rr      EEdata  ; Rotate the pattern right. 
        ijnz    EEaddr,:loop    ; FOR EEaddr = 0 to 255...
        call    EEdisbl         ; Turn write/erase protection back on. 
:loop2  call    EEread  ; Now read back contents of EEPROM. 
        mov     rb,EEdata       ; Display the EEPROM data on LEDs. 
        inc     EEaddr  ; Set up for next address. 
        call    delay   ; Delay to slow down the scanning. 
        goto    :loop2  ; Do forever. 

; Shout shifts out the bits of the variable temp to the EEPROM data line. 
; All of the other EEPROM routines call Shout. 
Shout   rl      temp    ; Rotate bit7 of temp into carry
        movb    D,c     ; Move carry bit to input of EEPROM
        setb    CLK     ; Clock the bit into EEPROM
        nop             ; Clock must be high > 500 ns
        clrb    CLK
        djnz    clocks,Shout    ; FOR I = 1 TO clocks...
        ret

; Read the byte in EEaddr into EEdata. 
EEread  mov     temp,#ROP       ; Move the read opcode into temp        
        mov     clocks,#4       ; Number of bits to shift out (op+1)
        setb    CS      ; Select the EEPROM. 
        call    Shout   ; Shift the read opcode out. 
        mov     clocks,#8       ; Number of bits to output (8 addr bits).
        mov     temp,EEaddr     ; Set up to send the address. 
        call    Shout   ; Shift out the address. 
        mov     !ra,#1  ; Now, change D to input. 
        mov     clocks,#8       ; Number of bits to input (8 data bits).
:read   setb    CLK     ; Data valid on rising edge of clock. 
        movb    c,D     ; Data bit into carry. 
        rl      temp    ; Rotate carry into temp. 
        clrb    CLK     ; Falling edge of clock. 
        djnz    clocks,:read    ; FOR I = 1 TO 8...
        mov     EEdata,temp     ; Move temp into EEdata
        mov     !ra,#0  ; Restore D to output. 
        clrb    CS      ; Deselect the EEPROM. 
        ret

; Call to unprotect after EEdisbl or power up or any time EEPROM
; has been write protected. 
EEnable setb    CS      ; Select the EEPROM. 
        mov     clocks,#12      ; Set up to shift out opcode. 
        mov     temp,#EWEN      ; temp = erase/write-enable op code.
        call    Shout   ; Shift temp out to the EEPROM. 
        clrb    CS      ; Done. Deselect EEPROM. 
        ret

; Call to protect against accidental write/erasure. Manufacturer advises
; leaving EEPROM in write-protected state most of the time to prevent accidental
; alteration by a runaway program. 
EEdisbl setb    CS      ; Select the EEPROM. 
        mov     clocks,#12      ; Set up to shift out opcode. 
        mov     temp,#EWDS      ; temp = erase/write-disable op code.
        call    Shout   ; Shift temp out to the EEPROM. 
        clrb    CS      ; Done. Deselect EEPROM. 
        ret

; Write the byte in EEdata to EEaddr. 
EEwrite mov     temp,#WROP      ; Get the write op code. 
        mov     clocks,#4       ; Prepare to shift out 4 msbs. 
        setb    CS      ; Select the EEPROM. 
        call    Shout   ; Shift temp out to the EEPROM. 
        mov     clocks,#8       ; Now prepare for 8 addr bits. 
        mov     temp,EEaddr     ; Move address into temp. 
        call    Shout   ; Shift temp out to the EEPROM. 
        mov     clocks,#8       ; Prepare for 8 data bits. 
        mov     temp,EEdata     ; Move data into temp. 
        call    Shout   ; Shift temp out to the EEPROM. 
        clrb    CS      ; Done. Deselect EEPROM. 
        ret

; Erase the byte in EEaddr. Erasure leaves 0FFh (all 1s) in the byte.
EErase  mov     temp,#ERAS      ; Get the erase op code. 
        mov     clocks,#4       ; Prepare to shift out 4 msbs. 
        setb    CS      ; Select the EEPROM. 
        call    Shout   ; Shift temp out to the EEPROM. 
        mov     clocks,#8       ; Prepare for 8 addr bits. 
        mov     temp,EEaddr     ; Move address into temp. 
        call    Shout   ; Shift address out to the EEPROM. 
        clrb    CS      ; Done. Deselect EEPROM. 
        ret

; Erase the entire EEPROM--all 256 bytes. Call before using EEwrall below. 
EEwipe  setb    CS      ; Select the EEPROM. 
        mov     temp,#ERAL      ; Get the erase-all opcode. 
        mov     clocks,#12      ; Prepare to shift out 12 bits. 
        call    Shout   ; Send op code + don't-care bits.
        clrb    CS      ; Done. Deselect EEPROM. 
        ret

; Write the byte in EEdata to every address. Call EEwipe first.
EEwrall setb    CS      ; Select the EEPROM. 
        mov     temp,#WRAL      ; Get the write-all opcode. 
        mov     clocks,#12      ; Prepare to shift out 12 bits. 
        call    Shout   ; Send op code + don't-care bits.
        mov     clocks,#8       ; Prepare to shift out 8 data bits. 
        mov     temp,EEdata     ; Move data into temp. 
        call    Shout   ; Shift temp out to EEPROM. 
        clrb    CS      ; Done. Deselect EEPROM. 
        ret

; Check flag to determine whether the EEPROM has finished its self-timed
; erase/write. Caution: This will lock up your program until D goes high. 
Busy    mov     !ra,#1  ; Set D to input. 
        setb    CS      ; Select the EEPROM. 
:wait   jnb     D,:wait ; Wait until D goes high (end of write). 
        clrb    CS      ; Done. Deselect EEPROM. 
        mov     !ra,#0  ; Restore D to output. 
        ret

; Delay routine for demo. 
Delay   djnz    tick1,Delay     
        djnz    tick2,Delay
        ret