• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Synchronous SPI code returns incorrect data


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.

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

;function shifts 48 bits right by one bit unit.
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

;slow master (mini uC=master)
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
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
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

;slow slave (big uC=slave) C=1=master not ready
jnb SSEL,nospiop ;see if master is ready
setb C ;it isn't so set carry
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
setb SPICLK ;set clock (tell master were ready)
jb SPICLK,$ ;wait till master lowers line
jnb SPICLK,$ ;wait till master raises line
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
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

Latest threads

EE World Online Articles