| ??? 09/04/08 16:25 Read: times |
#157957 - Need help with SPI implementation code in AT89S52 |
Hi,
I am trying to interface a serial EEPROM (Microchip 25AA256) with a plain AT89S52 which does not have HW SPI. I have pored over the data sheet and finally came up with some code. But as it usually happens with all my projects initially, it is not working. Here, I am posting the code and maybe someone here can provide some clues or pointers if I am really doing anything wrong here. Oh yes, the EEPROM is in fine condition because recently I interfaced it with my 'Arduino' board and it was able to read and write from it without any difficulty. I have written the code so that it writes 'X' or 0x58 onto location 0000h into the EEPROM and then reads the same hex byte back. Then it echoes it back via the serial port. I have a small C program written over my PC which reads from the serial port and echoes the read character, formatted with %d. The problem is, I am getting 255 when I read back the first location in the EEPROM. Either READ is not working, or WRITE is not working, or worst case neither are working. Here goes the code. Any help would be greatly appreciated!
; EEPROM connecting lines
_cs equ p2.0
so equ p2.1
_wp equ p2.2
_hold equ p2.3
sck equ p2.4
si equ p2.5
; EEPROM Intructions
READ equ 00000011b
WRITE equ 00000010b
WRDI equ 00000100b
WREN equ 00000110b
RDSR equ 00000101b
WRSR equ 00000001b
org 0000h
ljmp main ; bypassing the interrupt vectors
org 0030h
main:
lcall init_ser_port
lcall init_eeprom
mov a,#WRSR
lcall shift_out
mov a,#0h ;0h for no protection
lcall shift_out
lcall delay_5ms
lcall init_eeprom_write
mov a,#'X'
lcall eeprom_write_byte
nop
nop ;some delay
lcall eeprom_read_byte
sjmp $
; Establish default values for EEPROM bus lines
init_eeprom:
setb _cs ;_cs default as HIGH : to NOT select chip when not needed
setb _wp ;_wp default as HIGH : to allow writes
clr _hold ;_hold default as LOW : to select device always , unless overridden
setb sck ;sck default as HIGH : as idle condition
setb so ;so default as HIGH : as idle condition
setb si ;si default as HIGH : as idle condition
ret
; WRITE Specific init routine
init_eeprom_write:
clr _cs ;setting _cs to low first
mov a,#WREN
lcall shift_out
setb _cs ;bringing up _cs to HIGH again to set write latch
ret
eeprom_write_byte:
clr _cs ;selecting chip before writing
push acc ;saving byte to write to stack for the moment
mov a,#WRITE
lcall shift_out
;sending address to write as 0000h for writing
mov a,#0h
lcall shift_out
lcall shift_out
pop acc ;recovering byte to write from stack
lcall shift_out
setb _cs ;de-asserting _cs after writing is over
ret
eeprom_read_byte:
clr _cs ;asserting _cs just before reading
mov a,#READ
lcall shift_out
;Sending address to read from first, 0000h
mov a,#0h
lcall shift_out
lcall shift_out
;read the data byte now
lcall shift_in
setb _cs ;de-asserting _cs after reading is over
ret
shift_out:
;data to shift out is in A, and we have to shift it out, MSB first via si
mov r0,#8
clr C
_back:
rlc A
mov si,C
clr sck ;lowering clock from idle level(HIGH)
nop ;some delay
setb sck ;raising clock to latch bit
nop ;again some delay to allow EEPROM to digest what we just sent
djnz r0,_back ;repeat for all bits in A
ret
shift_in:
;data would be shifted in via so line
mov r0,#8
clr C
mov a,#00h
setb so
_back1:
clr sck
nop
setb sck ;this will cause EEPROM to vomit out the bit onto so
nop
nop
mov C,so
rlc A ;this rotation would pack the bits starting with MSB and then proceed to LSB
nop ;some delay
djnz r0,_back1
lcall send_one_char
ret
init_ser_port:
;Initializing the serial baud rate generator
mov ie,#10010100b ;enabling the serial port interrupt and int1
setb it1 ;to set interrupt 1 as edge triggered
mov tmod, #20h ;timer 1, mode 2(auto reload mode)
mov th1,#-3 ;9600 baud rate
mov scon,#50h ;8-bit, 1 stop bit, ren enabled
setb tr1 ;start timer 1
ret
send_one_char:
mov sbuf,a
jnb ti,$
clr ti
ret
recv_one_char:
jnb ri,$
mov a,sbuf
clr ri
ret
delay_5ms:
mov r1, #250 ; write cycle time
dly5ms1:
lcall dly20us ; ~250 * 20us = 5msec
djnz r1, dly5ms1
ret
dly20us:
mov r2, #38 ; 0.5 usec
dly20:
djnz r2, dly20 ; 0.5 usec * 38 = 19 usecs
ret ; 0.5 usec
end
|
| Topic | Author | Date |
| Need help with SPI implementation code in AT89S52 | 01/01/70 00:00 | |
| one thing after other | 01/01/70 00:00 | |
Got the issue! | 01/01/70 00:00 |



