Estoy tratando de hacer una transacción de datos bastante simple entre dos microcontroladores 8051 usando una variante del protocolo SPI. El grande es un esclavo y el pequeño es un maestro.
La documentación del esclavo (micro más grande) indica que la velocidad de salida del reloj es 6 veces más lenta en comparación con la velocidad del cristal externo. Debido a esto, el maestro también se ejecuta 6 veces más lento. Agregué un montón de comandos nops (sin operación) en mi código para el esclavo.
En cuanto al hardware, el circuito está en una PCB y la pista que va hacia el reloj tiene aproximadamente 40 millas de ancho y las otras pistas tienen 12 millas de ancho. Sus longitudes son de menos de una pulgada y el espacio libre para todas las pistas es de al menos 12 millas.
Después de varias pruebas, la línea SSEL (también conocida como "selección de esclavos") baja cuando el maestro la establece baja, pero el esclavo no hace que la línea SPICLK (también conocida como "reloj SPI") sea alta. haciendo.
¿Qué estoy haciendo mal?
;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