Synchronous SPI code returns incorrect data

Status
Not open for further replies.

mik3ca

Member
I have an at89C2051 hooked up to an at AT89S52 in which the latter drives the former clock. The speed difference is 6x apart. I thought of my whole project and decided to transfer the data synchronously such that if either microcontroller has an interrupt triggered (whether its caused by a timer or serial) then these routines will stall mid-point until the interrupt is finished.

While I am mostly on the right track, I have a problem, I am receiving incorrect data after making only changes to the routines below. Based on the data it seems the data got right-shifted 1 bit too far.

Is there any way I can optimize these routines so that all data gets sent down the line and received correctly? I don't care if I have to call each routine twice (1x to send and 1x to receive), just as long as I am able to send and receive data between the two micros regardless of how many interrupts are executing on each micro at any given time.

Code:
SPIBANK equ 18h ;Use register bank 3
SPISZ equ 30h ;Data size 30h=48 bits

;function shifts 48 bits right by one bit unit.
rrcl:
mov A,R1
rrc A
mov R1,A
mov A,R2
rrc A
mov R2,A
mov A,R3
rrc A
mov R3,A
mov A,R4
rrc A
mov R4,A
mov A,R5
rrc A
mov R5,A
mov A,R6
rrc A
mov R6,A
ret


;slow master (mini uC=master)
SPISM:
mov PSW,#SPIBANK ;Set bank
mov R7,#SPISZ ;48 bits to transfer
mov R1,A ;Make accumulator 1st byte
clr SSEL ;Tell slave we're ready
m:
jnb SPICLK,$ ;Wait till slave raises clock
mov C,DIN ;Get bit
acall rrcl ;insert into back of 48-bit train
mov DOUT,C ;Get old bit out of front of train
clr SPICLK ;lower clock
nop
setb SPICLK ;raise clock
jb SPICLK,$ ;wait till slave lowers line
djnz R7,m ;repeat for remaining 47 bits
setb SSEL ;Tell slave were done
mov A,R1 ;Get first byte as accumulator
mov PSW,#0h ;restore bank
ret


;slow slave (big uC=slave) C=1=master not ready
SPISS:
jnb SSEL,nospiop ;see if master is ready
setb C ;it isn't so set carry
ret
nospiop:
mov PSW,#SPIBANK ;Set bank
mov R7,#SPISZ ;48 bits to transfer
mov R1,A ;Make accumulator 1st byte
acall rrcl ;Shift train
mov DOUT,C ;set 1st bit
s:
setb SPICLK ;set clock (tell master were ready)
jb SPICLK,$ ;wait till master lowers line
nop
jnb SPICLK,$ ;wait till master raises line
nop
clr SPICLK ;lower line because were busy
mov C,DIN ;get bit from master
acall rrcl ;put it through our train
mov DOUT,C ;send old bit back to master
nop
djnz R7,s ;repeat for 47 bits
mov A,R1 ;make 1st byte accumulator
mov PSW,#0h ;restore bank
jnb SSEL,$ ;wait until master is done
ret
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…