Skip to content

Instantly share code, notes, and snippets.

@BobBurns
Created December 10, 2014 23:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BobBurns/8b4d7759d6896291761a to your computer and use it in GitHub Desktop.
Save BobBurns/8b4d7759d6896291761a to your computer and use it in GitHub Desktop.
demo assembly program using 25LC256 EEPROM with SPI
;demo program to learn how the avr can talk to another device with SPI
;in this case the 25LC256 eeprom
;
;based on the example code in c from Elliot Williams AVR Programming
;this example writes a string to the eeprom and then read it into sram to be sent over USART
;
;compile with gavrasm SPI-hello_eeprom.asm
;flash with avrdude -c avrisp -p m168 -P /dev/tty.useyourmodem -b 19200 -U flash:w:SPI-hello_eeprom.hex
;
;there are a couple extra convenience routines to use later
;-----defines ------
.device atmega168
.equ SPI_PORT = 0X05
.equ SPI_DDR = 0x04
.equ SPI_PIN = 0x03 ; I/O registers port B
.equ S_MISO = 4
.equ S_SS = 2
.equ S_MOSI = 3
.equ S_SCK = 5 ; port b pins
;
.equ UBBRvalue = 12 ;to init usart, based on cpu speed 1000000
;
.equ PAGEMAX = 0x40 ;maximum write length
.equ W_INP = 0 ;eeprom sreg flag bits ** write in progress
.equ W_ENL = 1 ; * write enable latch
.equ BP0 = 2 ; * block protect 0
.equ BP1 = 1 ; * block protect 1
;**** opcodes for eeprom ****
.equ E_READ = 0b00000011
.equ E_WRITE = 0b00000010
.equ E_WRDI = 0b00000100 ;write disable
.equ E_WREN = 0b00000110 ;write enable
.equ E_RDSR = 0b00000101 ;read status register
.equ E_WRSR = 0b00000001 ;write status register
;
;---- registers
.def temp = r16
.def count = r17
.def temp2 = r18 ;need this reg for tradeByte
.def xL = r26
.def xH = r27
.def yL = r28
.def yH = r29
.def zL = r30
.def zH = r31
;----- Main -----
.cseg
.org 0
;Initialize Stack
ldi temp,low(RAMEND)
out SPL,temp
ldi temp,high(RAMEND)
out SPH,temp
;Initialize SPI
sbi SPI_DDR,S_SS ;output on slave select
sbi SPI_PORT,S_SS ;start off not selected (high) ** always enable pullup before configuring SPI
sbi SPI_DDR,S_MOSI ;output on MOSI
sbi SPI_PORT,S_MISO ;set pullup on MISO
sbi SPI_DDR,S_SCK ;output on SCK
;
;** don't have to set phase, polarity b/c default works with 25LCxxx chips
in temp,SPCR
sbr temp,(1 << SPR0) ;divide f_cpu by 16, better for breadboards
sbr temp,(1 << MSTR) ;set AVR to SPI Master mode (use its clock)
sbr temp,(1 << SPE) ;enable SPI
out SPCR,temp
;
;initialize USART
ldi temp,high(UBBRvalue) ;baud rate param
sts UBRR0H,temp
ldi temp,low(UBBRvalue)
sts UBRR0L,temp
lds temp,UCSR0A
ori temp,(1 << U2X0) ;set use 2x because %error actual baud > .5
sts UCSR0A,temp
;--- USART register values
ldi temp,(1 << TXEN0) | (1 << RXEN0) ;enable transmit and receive
sts UCSR0B,temp
ldi temp,(1 << UCSZ01) | (1 << UCSZ00) ;8 data bits, 1 stop bit
sts UCSR0C,temp
;--- send a message
ldi zL, low(spi_str * 2)
ldi zH, high(spi_str * 2)
rcall print_s
;---- Main, really ---
;first write string into eeprom ic
;load z with pointer to string
ldi xL,0x00
ldi xH,0x00 ;load x with address to write to
rcall E_writeStr
ldi xL,0x00
ldi xH,0x00
rcall E_readStr ;reads string into dseg buffer
ldi xL,low(str_buf)
ldi xH,high(str_buf)
ld count,X+ ;get length byte first
p_lp: ld r24,X+
rcall transmit
dec count
brne p_lp
loop: nop
rjmp loop ;spin
;---- Subroutines ----
;---- function to transmit byte ----
;transmit byte from r24 over usart
transmit:
lds temp,UCSR0A
sbrs temp,UDRE0
rjmp transmit
sts UDR0,r24
ret
;print string function
;takes Z loaded with pointer to string with first byte being length
;uses r16,r17,r24
.def byte_tx = r24
print_s:
lpm count,Z+
for1: lpm byte_tx,Z+
wait: lds temp,UCSR0A
sbrs temp,UDRE0 ;wait for Tx buffer to be empty
rjmp wait ;not ready
sts UDR0,byte_tx;
dec count
brne for1
ret
;
;uses temp r16 as tx byte and returns with rx byte in SPDR
SPI_tradeByte:
out SPDR,temp
lp1: in temp2,SPSR
sbrs temp2,SPIF
rjmp lp1
ret
;---- function to send 16 bit address ---
; takes address in xH and xL registers
E_sendAddr:
mov temp,xH
rcall SPI_tradeByte
mov temp,xL
rcall SPI_tradeByte
ret
;----- function to get EEPROM sreg ----
;returns eeprom status reg in temp r16
E_readSts:
cbi SPI_PORT,S_SS ;lower SS // select slave
ldi temp,E_RDSR ;read eeprom sreg instruction
rcall SPI_tradeByte
ldi temp,0x00
rcall SPI_tradeByte ;clock out 8 bits while eeprom writes to SPDR
sbi SPI_PORT,S_SS ;de-select Slave
in temp,SPDR
ret
;---- function to set write enable ----
E_writeEnable:
cbi SPI_PORT,S_SS ;lower SS = slave select
ldi temp,E_WREN
rcall SPI_tradeByte
sbi SPI_PORT,S_SS ;deselct slave
ret
;---- function to read a byte from memory address in eeprom ic ---
;takes address in x registers
E_readByte:
cbi SPI_PORT,S_SS ;slave select
ldi temp,E_READ
rcall SPI_tradeByte
rcall E_sendAddr
ldi temp,0x00
rcall SPI_tradeByte ;clock 8 bits to get return byte
sbi SPI_PORT,S_SS ;deselect slave
in temp,SPDR
ret
;----- function to write a byte to memory in eeprom ic ---
;takes address in x registers and byte to write in temp r16
E_writeByte:
push temp ;save r16 while E_writeEnable is called
rcall E_writeEnable
cbi SPI_PORT,S_SS
ldi temp,E_WRITE
rcall SPI_tradeByte
ldi xL,0x00
ldi xH,0x00 ;send addr takes address in x reg
rcall E_sendAddr
pop temp
rcall SPI_tradeByte
sbi SPI_PORT,S_SS
lp2: rcall E_readSts
sbrc temp,W_INP ;loop while write in progress bit is set
rjmp lp2
ret
;--- function to read a string of bytes from eeprom
;--- and put them in memory
;--- takes address to read in x registers
;--- and uses y registers as pointers to write address
;--- length byte in count r17
E_readStr:
push temp ;preserve temp r16
ldi yL,low(str_buf)
ldi yH,high(str_buf) ;init address pointer
cbi SPI_PORT,S_SS ;set slave select low to send instruction
ldi temp,E_READ ;read instruction
rcall SPI_tradeByte
rcall E_sendAddr ;address to read already in xregisters
ldi temp,0x00
rcall SPI_tradeByte
in temp,SPDR
mov count,temp ;first byte is length
st Y+,temp ;store length byte too
rd_lp: ldi temp,0x00
rcall SPI_tradeByte ;address index automaticly increments
in temp,SPDR ;remember tradebyte leaves return byte in SPDR
st Y+,temp ;store read byte in str_buf and increment pointer
dec count
brne rd_lp
sbi SPI_PORT,S_SS ;** done ** de-select slave
pop temp
ret
;--- function to write a string of bytes in eeprom ic
;--- takes address to write in x registers
;--- uses y registers for pointer to read string. first byte is length
E_writeStr:
push temp
rcall E_writeEnable ;send write enable instruction
cbi SPI_PORT,S_SS ;set slave select
ldi temp,E_WRITE
rcall SPI_tradeByte
rcall E_sendAddr ;x registers should contain address to write to
ldi zH,high(hello_str * 2)
ldi zL,low(hello_str * 2)
lpm count,Z+
mov temp,count
rcall SPI_tradeByte ;send length byte
w_lp: lpm temp,Z+
rcall SPI_tradeByte
push zL
push zH
push temp
push count
ldi zL,low(write_str * 2) ;print progress
ldi zH,high(write_str * 2)
rcall print_s
pop count
pop temp
mov r24,temp
push temp
rcall transmit
ldi r24,0x0a
rcall transmit
ldi r24,0x0d
rcall transmit
pop temp
pop zH
pop zL
dec count
brne w_lp
sbi SPI_PORT,S_SS ;de-select slave
pop temp
lp3: rcall E_readSts
sbrc temp,W_INP ;loop while write in progress bit is set
rjmp lp3
ret
hello_str: .db 14,"Hello World!",0x0d,0x0a,0x00
spi_str: .db 17,"*** SPI FUN ***",0x0d,0x0a
write_str: .db 13,"writing byte:"
.dseg
str_buf: .byte 0x40 ;64 bytes of page memory
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment