1. 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.
    Dismiss Notice

Why does SPI work one way but not the other?

Discussion in '8051/8951' started by mik3ca, Mar 12, 2018.

  1. mik3ca

    mik3ca Member

    Joined:
    Jun 24, 2017
    Messages:
    498
    Likes:
    1
    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?

    Code (text):

    ;********************************************************
    ;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
     
     
  2. Cicero

    Cicero Active Member

    Joined:
    Nov 21, 2014
    Messages:
    429
    Likes:
    43
    Location:
    UK
    Am I understanding you correctly, you're switching from master to slave mid operation? And you're bitbanging your SPI yourself.

    I don't see it in the code, so are you sure you're changing your inputs to outputs when you switch master/slave config? As in re-configuring your MISO as a MOSI, and vice versa?

    On a side note, when you do this make do you have series resistors mid line, because there could easily be a time when you have both configured as outputs and they could be at differing levels.
     
  3. mik3ca

    mik3ca Member

    Joined:
    Jun 24, 2017
    Messages:
    498
    Likes:
    1
    im going to look into swapping the roles of slave select and spi clock line when reassigning the master and slave roles. both the 8051s have internal resistors
     
  4. dave miyares

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    2
    Likes:
    -10


     
  5. Cicero

    Cicero Active Member

    Joined:
    Nov 21, 2014
    Messages:
    429
    Likes:
    43
    Location:
    UK
    Just to make sure you fully understand me.

    Slave would have the following connections:
    • SS - input
    • SCK - input
    • MOSI - input
    • MISO - output

    Master needs the following:
    • SS - output
    • SCK - output
    • MOSI - output
    • MISO - input

    So when you switch roles, you need to switch every line.

    On the resistors part, I'm not talking about internal pullups. I mean series resistors between the connections.
    The reason why is because at some point in your code you're going to decide to switch roles, and have to change all the inputs to outputs, and outputs to inputs as above etc. Now lets say your start by switching your slave SS line to an output, and it immediately goes low before your data register is 0x00. Now, imagine your old master device's hasn't swapped just yet, and its SS is also an output and is set high. This wasn't a problem before when your slave SS was an input, but now you've got a short! (even if just for a split second) A small series resistor will protect against this situation. The other method if you're dead set against resistors is having to be really careful to change to high impedance states first, like change all your outputs to inputs first, then once you're sure everything is complete, change your inputs to outputs in a very controlled fashion.
     
  6. mik3ca

    mik3ca Member

    Joined:
    Jun 24, 2017
    Messages:
    498
    Likes:
    1
    i already assessed the series resistors situation and i find i dont need them becauae the 8051's gpio lines are always high impedance or low. never a solid vcc so short circuit is impossible in my situation
     
  7. mik3ca

    mik3ca Member

    Joined:
    Jun 24, 2017
    Messages:
    498
    Likes:
    1
    Im still have no luck. Is my timing off? or maybe theres a simpler way out?
     
  8. dave miyares

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    2
    Likes:
    -10


     
  9. Cicero

    Cicero Active Member

    Joined:
    Nov 21, 2014
    Messages:
    429
    Likes:
    43
    Location:
    UK
    I see, forgot 8051's don't have specific DDR's.

    In your code, I'm confused as to why when in slave mode you're setting and clearing the clock line? Surely that should be left to the master? You seem to be using it as a secondary handshaking routine, but it seems confusing.
     
  10. mik3ca

    mik3ca Member

    Joined:
    Jun 24, 2017
    Messages:
    498
    Likes:
    1
    ok we might as well mark this thread as closed because I decided to make the SPI routine one-direction only.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice