Created
December 10, 2014 23:48
-
-
Save BobBurns/8b4d7759d6896291761a to your computer and use it in GitHub Desktop.
demo assembly program using 25LC256 EEPROM with SPI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;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