# Faster 8051 not taking the slower 8051 pin status correctly

I'm trying to do a rather simple data transaction between two 8051 microcontrollers using a variant of the SPI protocol. The large one is a slave and the small one is a master.

The documentation for the slave (larger micro) states the clock output speed is 6x slower compared to its external crystal speed. Because of this, the master also runs 6x slower I added a bunch of nops (no-operation) commands in my code for the slave.

Hardware wise, the circuit is on a PCB and the track going to the clock is roughly 40mils wide and the other tracks are 12mils wide. Their lengths are less than one inch and the clearance for all tracks is at least 12mils.

After various tests, the SSEL (aka "slave select") line does go low when the master sets it low, but the slave does not make the SPICLK (aka "SPI clock") line high which is what it should be doing.

What am I doing wrong?

;Big micro (slave) code

SPICLK bit P3.6
DIN bit P2.5
DOUT bit P2.6
SSEL bit P2.7

org 0h
setb DIN
setb SSEL
clr SPICLK
debug:
acall SPISS ;stall until remote does valid cmd
jc debug ;carry = remote didn't set low yet
jz debug ;zero = invalid command
;process code based on accumulator value
ret

;SPI slave routine
SPISS:
setb SSEL ;Set high so master can set it low
nop     ;wait 6 cycles because master is 6x slower
nop
nop
nop
nop
nop
jnb SSEL,nospiop ;if line isn't taken low
setb C     ;then set carry
ret        ;and return. This always happens which is a problem!
nospiop:
mov R7,#8h     ;Setup 8 bits
s:
setb SPICLK    ;tell other micro we are ready
nop         ;let it catch up
nop
nop
nop
nop
nop
clr HWLED   ;turn our light on
jb SPICLK,$;wait until master lowers clock line clr SPICLK ;we keep it low to make master wait mov C,DIN ;get bit setb HWLED ;turn off light rrc A ;shift into the byte mov DOUT,C ;and take other bit as output djnz R7,s ;continue for remaining 7 bits setb SPICLK ;tell micro we are ready again nop nop nop nop nop nop clr HWLED ;turn on light jnb SSEL,$  ;wait until master turns slave select to high
clr SPICLK  ;tell micro we are always busy
setb DOUT   ;reset other values
setb DIN
setb HWLED
clr C       ;C=0 for normal completion
ret

;Little master micro code

DOUT bit P1.1
DIN bit P1.2
SSEL bit P1.3
SPICLK bit P3.2

org 0h
mov A,#COMMAND ;Some value irrelevant to the problem
acall docpucmd
sjmp $docpucmd: acall SPISM ;Send command out but we don't care what comes back clr A ;Make command as zero.. acall SPISM ;because now we want the result to the last command clr C ret ;Master SPI routine SPISM: setb SPICLK ;Make clock line so slave can pull it low setb DIN ;Make input high so slave can set it clr SSEL ;Lower slave select to start transaction mov R7,#8h ;8 bits to transfer m: nop ;wait until remote RAISES clock line to indicate ;slave is ready but slave likes to keep line low always jnb SPICLK,m mov C,DIN ;Get bit rrc A ;Shift it in and shift old bit out mov DOUT,C ;Send out old bit clr SPICLK ;lower clock line to tell slave we have data nop ;add small delay. this is executed on slow micro setb SPICLK ;raise clock line djnz R7,m ;repeat for remaining bits jnb SPICLK,$  ;wait until remote is ready
mov C,DIN     ;get official last bit
rrc A     ;and make byte correct
setb SSEL ;and reset lines
setb DOUT
setb DIN
ret


• Without looking in detail, I'd say that your clocks aren't exactly in phase and they are drifting relative to each other, as well. – jonk Mar 4 '18 at 1:30
• You need a master clock not skewed by incidental instruction times or ISR's. Nops are only good for atomic read/writes or to wait for a ADC to finish sampling. – user105652 Mar 4 '18 at 2:11
• "the slave does not make the SPICLK (aka "SPI clock") line high which is what it should be doing." - why should it be doing this? – Bruce Abbott Mar 4 '18 at 2:20
• because when the master lowers the clock then raises it to indicate data processing, then the slave can make the clock low to tell the master the slave is too busy to handle the next bit of data. – Mike -- No longer here Mar 4 '18 at 2:31
• I'm not going to check, Are you saying that the SSEL line is being driven as an output by both chips? I'm not sure looking at what little code I can see. If so, you need wire-or and an external pull-up present. Also, a LOT more code. I have an article on stuff like this, written decades ago, somewhere. I suppose I should go find it. Different clocks and sampling rates, execution variability with stuff like JNB are all problems related to timing this to work. The whole idea of "6 times slower so add some NOPs" is just crazy-making to me. It's just wrong. – jonk Mar 4 '18 at 4:16