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