C3 SPI Drivers - part 2 ( write bits )

Now we can build up the two basic access routines: Write routine

The concept is really easy, you need just to provide a clock signal and read or write data bits. Don't forget that if you write data you need to start wit most significant bit ( MSB ), the same when reading data.

Each clock pulse is a bit to send or write.

SPI bus is a circular communication protocol, so you can read and write a bit at the same time, but with this emulator it won't happen that so I have separated them to save some more cycles.
 
Let's see how to send a clock pulse to the SPI Clock pin: 


          ' bit n
          and   outa, _SPI_SCK_MASK ' drop clock to low state by masking the clock pin 

          ... code R/W ...
          ... code R/W ...

          or    outa, _SPI_SCK      ' raise clock to high state by adding the pin bit value

          ...

_SPI_SCK          long     %00000000_00000000_00001000_00000000 ' pin 11 value
_SPI_SCK_MASK     long     %11111111_11111111_11110111_11111111 ' pin 11 masked value
 
This is the easiest way to modify the out port without disturbing other signals. All you need now is to send a certain amount of bits. Drop clock, send or receive a bit, raise clock, repeated for n bits.

A common way to send bits is to shift data to left or right according to the order of bits, in this case MSB first.

          ror   _out, _bits             ' _out is the byte, or word to transfer and bits is
                                        ' the amount of bits. Data is rotated to the right so
                                        ' it will be aligned for the transfer so de long is:
                                        ' 31 ... 7 6 5 4 3 2 1 0 and will become
                                        ' [ 7 6 5 4 3 2 1 0 ] 23 22 .... 0 

bitLoopW  and   outa, _SPI_SCK_MASK     ' drop clock 
          rol   _out,  #1            wc ' now rotate the long to the left and store the carry
                                        ' flag so the long will become
                                        ' [ 6 5 4 3 2 1 0 ] 23 22 .... 0 [ 7 ]
                                        ' and the carry result of the rotation will be 1 or 0
                                        ' according to the value of bit rotated

          muxc  outa, _SPI_MOSI         ' this operation will set those "1" bit of SPI_MOSI
                                        ' mask with value of carry flag ( 0 / 1 ),so the port a
                                        ' will take those bits values  
 

          or    outa, _SPI_SCK          ' raise clock 

          djnz  _bits, #bitLoopW        ' decrement the counter ( bits ) and loops if not
                                        ' reached 0

 
If you want, you can speed up a little more but only if you are sure about how many bit you usually need to transfer, so in my emulator I will usually use bytes, and sometimes word, so I will optimize this routine to achieve more speed with bytes only. 

So you need to check how many bits to transfer, and if 8 you can unroll the loop to save 4*7 = 28 cycles, if more or less you can use the loop instead.
This is the unrolled cycle:


          ' _BIT 7

          and   outa, _SPI_SCK_MASK     ' drop clock 
          rol   _out,  #1            wc ' now rotate the long to the left and store the carry
                                        ' flag

          muxc  outa, _SPI_MOSI         ' this operation will set those "1" bit of SPI_MOSI
                                        ' mask with value

          or    outa, _SPI_SCK          ' raise clock
 
          ' _BIT 6
          and   outa, _SPI_SCK_MASK     ' drop clock
          rol   _out,  #1            wc ' now rotate the long to the left and store the carry
                                        ' flag
          muxc  outa, _SPI_MOSI         ' this operation will set those "1" bit of SPI_MOSI
                                        ' mask with value
          or    outa, _SPI_SCK          ' raise clock 

           ...

          ' BIT 0
          and   outa, _SPI_SCK_MASK     ' drop clock
          rol   _out,  #1            wc ' now rotate the long to the left and store the carry
                                        ' flag
          muxc  outa, _SPI_MOSI         ' this operation will set those "1" bit of SPI_MOSI
                                        ' mask with value
          or    outa, _SPI_SCK          ' raise clock