I'm trying to make a two way master and slave system for my microcontrollers.
The small microcontroller runs at about 3.6Mhz is the master and the big slave microcontroller runs at 22.1184Mhz which is a 6x speed difference.
The small micro (at89c2051) has its clock driven from the ALE of the at89S52. The ALE is configured to always run and neither microcontroller performs any external memory operations.
On initialization the small micro is the master and the large one is slave. The small master calls its docpucmd function to send test data to the slave and the slave correctly responds by constantly calling SPISS function until it finds valid data which it then processes. Then later the master calls do1cpucmd with a command for the micros to switch roles.
Now the faster microcontroller is the master and the small one is slave. So far everything goes well except for the fact that the "slow" small slave isn't recognizing the data the master sends to it yet I made very small modifications to the code.
The big micro calls its own docpucmd (shown halfway down in code). and the slow small slave constantly calls SPIGS for valid data but I learn that I always get zeros coming from SPIGS.
Is my timing that terrible or am I doing something else wrong?
The small microcontroller runs at about 3.6Mhz is the master and the big slave microcontroller runs at 22.1184Mhz which is a 6x speed difference.
The small micro (at89c2051) has its clock driven from the ALE of the at89S52. The ALE is configured to always run and neither microcontroller performs any external memory operations.
On initialization the small micro is the master and the large one is slave. The small master calls its docpucmd function to send test data to the slave and the slave correctly responds by constantly calling SPISS function until it finds valid data which it then processes. Then later the master calls do1cpucmd with a command for the micros to switch roles.
Now the faster microcontroller is the master and the small one is slave. So far everything goes well except for the fact that the "slow" small slave isn't recognizing the data the master sends to it yet I made very small modifications to the code.
The big micro calls its own docpucmd (shown halfway down in code). and the slow small slave constantly calls SPIGS for valid data but I learn that I always get zeros coming from SPIGS.
Is my timing that terrible or am I doing something else wrong?
Code:
;********************************************************
;code for mini micro that runs at 3.686400Mhz (6x slower)
;********************************************************
;This function runs when master and slave switch roles
do1cpucmd:
acall SPISM
ret
;This function runs when master wants to send a 1-byte
;command from accumulator and wants a 1-byte response right away
docpucmd:
acall SPISM
clr A
acall SPISM
ret
;slow master (mini uC=master) A=new input > A=old output
SPISM:
clr SSEL ;lower slave-select pin
mov R7,#8h ;8 bits to transfer
setb SPICLK ;raise clock
setb DOUT ;Make output high for now
setb DIN ;Make input high so micro accepts input
nop ;Stall a bit
nop
nop
m:
jnb SPICLK,$ ;Stall until remote micro raises clock line
mov C,DIN ;Read one bit of input
rrc A ;shove it into accumulator
mov DOUT,C ;send oldest bit back out to slave
clr SPICLK ;lower clock line
nop ;wait
setb SPICLK ;raise clock line
nop ;wait
djnz R7,m ;repeat for remaining 7 bits
jnb SPICLK,$ ;wait until remote micro raises clock line
setb DOUT ;set lines high
setb DIN
nop
setb SSEL ;including slave select
ret
;slow micro as slave
SPIGS:
setb SSEL ;make slave select ready
jnb SSEL,nospiop ;if slave isnt selected by master
setb DIN
setb DOUT
clr A
setb C ;reset lines and exit
ret
nospiop:
mov R7,#8h ;setup 8 bits
mov A,B ;load data in
rrc A
mov DOUT,C
s: ;process bits. Eliminated nops because slave is slow
setb SPICLK
jnb SPICLK,$
jb SPICLK,$
clr SPICLK
mov C,DIN
rrc A
mov DOUT,C
djnz R7,s
setb SPICLK
jnb SSEL,$
clr SPICLK
setb DIN
setb DOUT
clr C
ret
;********************************************************
;code for large micro that runs at 22.1184Mhz (faster)
;********************************************************
;This is executed on big micro when big micro is slave and has nothing to do.
SPISS:
setb SSEL ;tell master (mini micro) we are ready
jnb SSEL,nospiop ;see if they lowered slave select
setb DIN ;they didnt
setb DOUT ;so make lines high for sanity
nop ;and...
clr A ;return nothing for accumulator
ret
nospiop:
mov R7,#8h ;setup 8 bit transfer
mov A,B ;load last command result into accumulator
rrc A ;get bit
mov DOUT,C ;and send it out
s:
setb SPICLK ;tell master we are ready
jnb SPICLK,$ ;wait until master makes line high
jb SPICLK,$ ;wait until master makes line low
clr SPICLK ;we make line low to indicate busy
mov C,DIN ;get bit and...
rrc A ;move it into accumulator and old bit...
mov DOUT,C ;back to the master.
djnz R7,s ;repeat for 7 more bits
setb SPICLK ;tell master we are ready again
jnb SSEL,$ ;wait until master raises slave select
clr SPICLK ;tell master we are busy
setb DIN ;reset other lines
setb DOUT
acall SPIdelay ;add delay to let master keep up
ret
;execute small CPU command from big CPU.
;C=1=small CPU too busy
; *** FUNCTION CURRENTLY NOT WORKING CORRECTLY ***
docpucmd:
setb C
jb SPIPROC,nolcpuproc
mov A,R5 ;import parameter
acall SPIGM ;send it out to little cpu slave
mov A,R6 ;import next parameter
acall SPIGM ;send it out to little cpu slave
clr A ;Send nothing. we only want response
acall SPIGM ;get 1st parameter response
mov R5,A
clr A
acall SPIGM ;get 2nd parameter response
mov R6,A
clr C
nolcpuproc:
ret
;Big micro as master
SPIGM:
clr SSEL ;tell slave were ready
mov R7,#8h ;8 bits
setb SPICLK ;setup everything
setb DOUT
setb DIN
acall SPIdelay ;delay so slave (small micro) can catch up
m:
jnb SPICLK,$ ;wait until slave raises clock
acall SPIdelay ;delay so small micro can process stuff
mov C,DIN ;get bit
rrc A ;put in accumulator
mov DOUT,C ;send old bit out
clr SPICLK ;lower clock
acall SPIdelay ;and stall so slave can keep up
setb SPICLK ;raise clock
acall SPIdelay ;stall again so slave can keep up
djnz R7,m ;repeat for 7 more bits
jnb SPICLK,$ ;wait for slave to be ready
setb DOUT
setb DIN
setb SSEL ;reset slave select
acall SPIdelay ;and stall more
ret
;This function applies to both micros. It creates about a 27 clock cycle delay
SPIdelay:
push B
mov B,#10h
djnz B,$
pop B
ret