Handling 64-bit data through spi communication for 8-bit PIC

NorthGuy

Joined Jun 28, 2014
611
You can mark the transmission with CS. CS goes low, you exchange the whole 8 bytes (or whatever), then CS goes high. You program the slave to reset its state as soon as it sees CS going high. You verify the transmission with checksum or CRC if needed. If you've got errors, you wait enough time for the slave to reset the state, then you repeat the attempt. This way you don't need any byte counting.
 

Thread Starter

sarvanan

Joined Aug 8, 2016
45
Hi Papabravo and other members,

I took some time to understand how spi works and how can pic transfer data to another controller. I looked at MPLABX Code Configuator spi code also. Now I have some fair idea and also understand need of synchronization I just need some help to complete this task. Its PIC16lf1939. Its 8-bit. I shared datasheet earlier. Request to check my initial requirement. Its send(16-bit fixedVal1, 16-bit FixedVal2, val1, val2). Same way receive(16-bit same_fixedVal1, 16-bit same_FixedVal2, calculated_val1, calculated_val2).
Requirement:
1. Select controller chip, Check the Interrupt line of other controller, if high, send 16 bit-data. Check the Interrupt line of other controller again , if high send 16-bit data again otherwise wait. Keep doing this until 64-bit data is transferred.

Here is the MCC code:
Code:
uint8_t SPI_Exchange8bit(uint8_t data)
{
    // Clear the Write Collision flag, to allow writing
    SSPCON1bits.WCOL = 0;
    SSPBUF = data;
    while(SSPSTATbits.BF == SPI_RX_IN_PROGRESS)
    {
    }
    return (SSPBUF);
}

uint8_t SPI_Exchange8bitBuffer(uint8_t *dataIn, uint8_t bufLen, uint8_t *dataOut)
{
    uint8_t bytesWritten = 0;
    if(bufLen != 0)
    {
        if(dataIn != NULL)
        {
            while(bytesWritten < bufLen)
            {
                if(dataOut == NULL)
                {
                    SPI_Exchange8bit(dataIn[bytesWritten]);
                }
                else
                {
                    dataOut[bytesWritten] = SPI_Exchange8bit(dataIn[bytesWritten]);
                }
                bytesWritten++;
            }
        }
        else
        {
            if(dataOut != NULL)
            {
                while(bytesWritten < bufLen )
                {
                    dataOut[bytesWritten] = SPI_Exchange8bit(DUMMY_DATA);
                    bytesWritten++;
                }
            }
        }
    }
    return bytesWritten;
}
I just want to know how to use SDO, SDI lines in the MCC code as I don't see it in this code. Also how to handle the Chip select and interrupt checking at every 16-bit data transfer in the above code?
As I understand this code does sending and receiving both. How to extract all 4 separate 16-bit data coming from other controller to PIC?
Simplified code will be appreciated.

Please help.

Thanks & regards,
Sarvanan.

Moderator Edit: added code tags
 

NorthGuy

Joined Jun 28, 2014
611
The formatting is lost, so it's hard to judge, but at a first glance it looks more or less Ok. You don't usually check the code visually, you compile and test.

You handle CS manually. Set TRIS to 1. Set LAT to 1 to drive high, set LAT to 0 to drive low.
 

Thread Starter

sarvanan

Joined Aug 8, 2016
45
Hi North Guy,

Thanks for the help.
Could you please let me know about SDO, SDI lines as in MCC code i didn't find these or Am i missing something?
Also could you help as I understand this code does sending and receiving both. How to enable interrupt to other controller when 16-bit is transferred in the above code? How to extract all 4 separate 16-bit data coming from other controller to PIC?

Thanks & regards,
Sarvanan.
 

NorthGuy

Joined Jun 28, 2014
611
SDO and SCK lines are controlled by MSSP module. The module also provide means for sending/retrieving data. Read the MSSP chapter in the datasheet.

Are both of your controllers PICs?
 

Thread Starter

sarvanan

Joined Aug 8, 2016
45
Hi NorthGuy,

Thanks. I will check.
Other controller is not PIC but 32-bit microcontroller.
Could you please tell How to enable interrupt to other controller when 16-bit is transferred in the above code? How to extract all 4 separate 16-bit data coming from other controller to PIC?

Thanks & regards,
Sarvanan.
 

NorthGuy

Joined Jun 28, 2014
611
Could you please tell How to enable interrupt to other controller when 16-bit is transferred in the above code?
You cannot force an interrupt in other controller. The other controller will participate in transmission, watch CS etc. This will give it enough information to produce an interrupt. You should look at the docs for this other controller.

How to extract all 4 separate 16-bit data coming from other controller to PIC?
This is explained in details in the chapter of the datasheet I referred to. If you use "SPI_Exchange8bitBuffer()", then this data will be stored at "dataOut".
 

Thread Starter

sarvanan

Joined Aug 8, 2016
45
Hi NorthGuy,

You are correct. Interrupt will be generated by other controller. PIC only needs to watch it and transmit the data when interrupt is set.

Thanks & regards,
Sarvanan.
 

Thread Starter

sarvanan

Joined Aug 8, 2016
45
Hi Members,

Please help. I still could not crack SPI communication.
I have simplified PIC16lf1939 spi code for more understanding and used MPLABX Code Configurator.
Code:
#define  CS0              TRISAbits.TRISA0 // /Chip Select
#define  INT_LINE       PORTBbits.RB0 // Interrupt line
#define  SCK              TRISCbits.TRISC3 // sck line
#define  SDO              TRISCbits.TRISC5 // sdo line MOSI
#define  SDI                PORTCbits.RC4 // sdi line MISO

void main(void)
{
           SSPSTAT = 0x00;
           SSPCON1 = 0x20;
           SSPADD = 0x00;

           TRISAbits.TRISA0 = 0; // for Chip select
            LATAbits.LATA0 = 0;

            TRISBbits.TRISB0 = 1; // for INT_LINE
            LATBbits.LATB0 = 1;

            spi_exchange8bit(0x05);
}

uint8_t spi_exchange8bit(uint8_t data)
{
          CS0 = 0;
          SSPCON1bits.WCOL = 0;
          SSPBUF = data; //sending ??
          if(INT_LINE == 0) // need to check if other controller is ready to accept data
          {
                 while(SSPSTATbits.BF == SPI_RX_IN_PROGRESS)
                 {
                 }
                 return (SSPBUF); //is this received data from slave???
          }
}
Is this code complete to send 8-bits data and receive 8-bit data? Does SSPBUF will contain the data coming from slave? What registers needs to be checked for sending and receiving data?

Am i correct that SDI, SDO lines are not needed as SSPSTAT, SSPCON1, SSPADD initialization will take
case of it?
Still there is some issue and not getting proper value from the slave controller. Could anybody please figure out the issue?

Thanks & Regards,
Sarvanan.

Moderator edit: added code tags
 

Thread Starter

sarvanan

Joined Aug 8, 2016
45
Hi NorthGuy,

Sorry for my many questions and requests. I am new to the microcontroller. I have gone through the spi part of datasheet and understand it partially. That is why tried to write code and understand it further. Sorry again.
Could you please correct the problem in the above code showing sending and receiving data from this pic16lf1939 to other controller so that i can understand what am I missing?
I will be thankful to you.

Thanks & regards,
Sarvanan.
 

jpanhalt

Joined Jan 18, 2008
11,087
Based on comments, not posted code, it appears you want to do burst reads and writes. I cannot do C, but I don't believe the MCU datasheet discusses burst reading and writing specifically. They may bemore dependent on the slave/target. I happen to be using a chip in a current project that supports such read/writes. It automatically increments the read address with each read. This is from that chip's datasheet for burst reads:
upload_2016-11-18_9-49-38.png
Some features to note:
1) CS is cleared during the entire duration of the read.
2) Clearing the register initiates another byte of data from the slave.
3) The very first byte received from the slave in response to setting the address is ignored. Subsequent data bytes are saved in sequential registers using indirect addressing.
4) After all bytes are received, CS is set to stop the dialog. I just use a counter, which happens to be set for 8 bytes.

Here is my code for doing that, which unfortunately is pretty crude and in Assembly. I get stuff to work and include unnecessary comments to myself. Then I clean it up.

Code:
GetData                       ;called subroutine
     movlw     8
     movwf     count
     movlw     DX_L           ;starting register for saving read data (0x77)
     movwf     FSR0L
     movlw     0x42           ;starting register for read
     bsf       WREG,7         ;set read bit
     movlb     2              ;CSn LATx
     bcf       CSn
     movlb     4              ;SPI bank
     btfsc     SSPSTAT,BF     ;be sure SPI is ready, necessary?
     bra       $-1        
     movwf     SSPBUF         ;send address
     btfss     SSPSTAT,BF
     bra       $-1
_Burst
     clrf      SSPBUF         ;discard first read & initiate subsequent reads
     btfss     SSPSTAT,BF     
     bra       $-1
     movf      SSPBUF,w       ;first real data from indexed register
     movwi     FSR0++         ;move read data to sequential registers
     decf      count,f
     btfsc     STATUS,2       ;check if done
     bra       ExitData       ;done
     bra       _Burst
                        
ExitData                      ;exit read, reset CSn and switch to Bank0
     movlb     2
     bsf       CSn            ;end read session
     movlb     0
     return
John
 

Papabravo

Joined Feb 24, 2006
22,084
It is a fact of life in the SPI world that a master is compelled to do what the slave device requires, and not the other way around. There is nothing stopping a master from inserting gaps between the byts of a burst operation so long as CS* remains active. As long as there are no clocks the slave devices will be just as happy as clams.
 

Thread Starter

sarvanan

Joined Aug 8, 2016
45
Hi Papabravo,

Thanks for the reply.
In my requirement PIC16lf1939 is master and other controller is slave. PIC sends or receives data when slave is ready to accept(INT_LINE low).
Please check my code and help me in solving this. As per your suggestions 3 days back, I wrote sample code which i shared to get more understanding but still some issue is there.
Could you please modify the code or provide me sample xc8 spi code for pic16lf1939? Please help. Copying the code below again.

  1. #define CS0 TRISAbits.TRISA0 // /Chip Select
  2. #define INT_LINE PORTBbits.RB0 // Interrupt line
  3. #define SCK TRISCbits.TRISC3 // sck line
  4. #define SDO TRISCbits.TRISC5 // sdo line MOSI
  5. #define SDI PORTCbits.RC4 // sdi line MISO

  6. void main(void)
  7. {
  8. SSPSTAT = 0x00;
  9. SSPCON1 = 0x20;
  10. SSPADD = 0x00;

  11. TRISAbits.TRISA0 = 0; // for Chip select
  12. LATAbits.LATA0 = 0;

  13. TRISBbits.TRISB0 = 1; // for INT_LINE
  14. PORTBbits.RB0 = 1;

  15. spi_exchange8bit(0x05);
  16. }

  17. uint8_t spi_exchange8bit(uint8_t data)
  18. {
  19. CS0 = 0;
  20. SSPCON1bits.WCOL = 0;
  21. SSPBUF = data; //sending ??
  22. if(INT_LINE == 0) // need to check if other controller is ready to accept data
  23. {
  24. while(SSPSTATbits.BF == SPI_RX_IN_PROGRESS)
  25. {
  26. }
  27. return (SSPBUF); //is this received data from slave???
  28. }
  29. }
Thanks & regards,
Sarvanan.
 

NorthGuy

Joined Jun 28, 2014
611
I have gone through the spi part of datasheet and understand it partially. That is why tried to write code and understand it further.
Very well then. Don't try to do anything complex before you can do simple things. It's important to understand the basics first. Get two PICs and try to send a single byte from the master to the slave and don't worry about the response just yet - that's the easiest thing you can do. Once you do it and see it working, it'll be much easier to move forward.

Do you have a scope or logic analyzer?
 

Thread Starter

sarvanan

Joined Aug 8, 2016
45
Hi NorthGuy,

Thanks for guidance. I am using PICKit3 for debugging.
If you can provide the sample spi code for send and receive for PIC16lf1939, it wold be great.
I can analyse what i am missing in my implementation.
Thanks for your patience and guidance again.

Thanks & regards,
Sarvanan.
 

Thread Starter

sarvanan

Joined Aug 8, 2016
45
Based on comments, not posted code, it appears you want to do burst reads and writes. I cannot do C, but I don't believe the MCU datasheet discusses burst reading and writing specifically. They may bemore dependent on the slave/target. I happen to be using a chip in a current project that supports such read/writes. It automatically increments the read address with each read. This is from that chip's datasheet for burst reads:
View attachment 115505
Some features to note:
1) CS is cleared during the entire duration of the read.
2) Clearing the register initiates another byte of data from the slave.
3) The very first byte received from the slave in response to setting the address is ignored. Subsequent data bytes are saved in sequential registers using indirect addressing.
4) After all bytes are received, CS is set to stop the dialog. I just use a counter, which happens to be set for 8 bytes.

Here is my code for doing that, which unfortunately is pretty crude and in Assembly. I get stuff to work and include unnecessary comments to myself. Then I clean it up.

Code:
GetData                       ;called subroutine
     movlw     8
     movwf     count
     movlw     DX_L           ;starting register for saving read data (0x77)
     movwf     FSR0L
     movlw     0x42           ;starting register for read
     bsf       WREG,7         ;set read bit
     movlb     2              ;CSn LATx
     bcf       CSn
     movlb     4              ;SPI bank
     btfsc     SSPSTAT,BF     ;be sure SPI is ready, necessary?
     bra       $-1       
     movwf     SSPBUF         ;send address
     btfss     SSPSTAT,BF
     bra       $-1
_Burst
     clrf      SSPBUF         ;discard first read & initiate subsequent reads
     btfss     SSPSTAT,BF    
     bra       $-1
     movf      SSPBUF,w       ;first real data from indexed register
     movwi     FSR0++         ;move read data to sequential registers
     decf      count,f
     btfsc     STATUS,2       ;check if done
     bra       ExitData       ;done
     bra       _Burst
                       
ExitData                      ;exit read, reset CSn and switch to Bank0
     movlb     2
     bsf       CSn            ;end read session
     movlb     0
     return
John
Thanks jpanhalt. So nice of you. Definitely it provided me points to ponder though i needed C code.
 

NorthGuy

Joined Jun 28, 2014
611
If you can provide the sample spi code for send and receive for PIC16lf1939, it wold be great. I can analyse what i am missing in my implementation. Thanks for your patience and guidance again.
Your code is Ok. You can easily expand it to send more bytes, organize packets etc., but then you write your perfect code, connect everything, and it doesn't work. Then what?

Instead of thinking about the code, try to figure out how to create the very simplest test which actually does something - like transmitting a single byte. Once the simplest test is working, you can slowly expand it to make more complex things. Without anything working, it is like shooting in the dark, and all the code discussions are purely academic.

Have you tried running your code? What happens when you try to transmit a byte?
 

Thread Starter

sarvanan

Joined Aug 8, 2016
45
Hi NorthGuy,

Thanks for the mail. I am going on the same line as suggested by you. I am running code on device using pickit3.
Now, I sent a byte and am able to receive data. I need to verify the data. When I transferred 2-bytes 0x8001, I received 0x08, and 0x01. Is it correct? But I feel received data depends on what is available in slave buffer not what transmitted. It depends on the S/W.
Let me know if my opinion is wrong.

Thanks & regards,
Sarvanan.
 
Top