Hot!Combining USART and SPI togetther on PIC18LF45K22 micrcontroller

Page: 123 > Showing page 1 of 3
Author
VikramTrivedi
New Member
  • Total Posts : 15
  • Reward points : 0
  • Joined: 2017/11/30 09:20:39
  • Location: 0
  • Status: offline
2017/12/01 08:02:36 (permalink)
0

Combining USART and SPI togetther on PIC18LF45K22 micrcontroller

Hi all,
This is my first time using the Microchip forum. So please forgive if it is not the correct way of posting on the forum.
I am into the middle of the project where I have to get the data on the SPI slave and transmit that data out from the USART onto the PC.
The controller I am using is PIC18LF45K22.
When I run the codes individually where two PIC18 boards act as SPI Master and Slave the communication is perfect.
Similarly, when I configure one of the PIC as USART Tx & Rx I see the data getting displayed on the PC terminal whatever I send out and also I receive what I send to PC.
 
But the issue arises when I combine both the peripheral together.
I have one Master SPI device that is not PIC18LF45K22 but it is a MSP432 controller and one PIC18LF45K22 device as SPI Slave.
Whenever the SPI slave receives something sent by MSP432, it immediately needs to send that to the PC terminal.
After first SPI buffer receive, PIC18 does not send anything to the PC and never does it again receive anything from Master SPI.
 
The logic seems to be correct as the same logic was applied earlier when I was using CC1310 radio boards as Slave SPI.
Not sure what I might be doing wrong.
I am using the interrupt concept in this case.
 
I am attaching the files in the code if someone can look and see what am I doing incorrect and guide me for the right approach would be grateful.
Not sure how to attach the entire code.
 
Thank you
Vikram
#1

41 Replies Related Threads

    Aussie Susan
    Super Member
    • Total Posts : 3115
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/03 18:47:33 (permalink)
    5 (2)
    I must admit that I really do not like MCC generated code - there is a tone of code in there that is not used and simply delays sorting out problems for simple applications such as this; not to mention the code that is used is horribly convoluted (in my opinion!).
    I must admit I can't see how you get the first character passed on as you describe. In the SPI ISR the received character is put into a buffer until DATA_SPI characters are received (DATA_SPI is set to 240) and only then is the 'callback' function called (which is set to 'spiCallback' in the main file) which sends the characters to the EUART.
    If all you need to do is to copy each character read on the SPI slave to the EUSART, then there really is no need for interrupts, 5 (and probably more) code files etc. Ignoring the initialisation of the SPI and EUSART (and oscillator etc.) the pseudo code for the main loop is:

    while(1)
    {
        wait for the SPI exchange to complete (i.e the BF bit to be set)
        read the SPIBUF value
        wait for the EUSART tx buffer to be free
        write the value to the EUSART buffer
        (perhaps set a new value in the SPIBUF for the next exchange - optional)
    }

    (OK - you may want to handle errors etc. but that is not hard to add in.)
    Susan
    #2
    qɥb
    Monolothic Member
    • Total Posts : 2060
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: online
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/03 18:58:47 (permalink)
    5 (1)
    Pretty much agree with Susan (about the over complexity of MCC),
    but the suggested alternative will only work if the Master is sending SPI data at a slower rate than the USART can resend it.
    Otherwise you need a FIFO buffer between the two, and a pair of state machines to handle "SPI receive" and "USART send", or some way of holding the Master off until the previous character has been sent.
     

    PicForum "it just works"
    #3
    VikramTrivedi
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2017/11/30 09:20:39
    • Location: 0
    • Status: offline
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/04 07:42:57 (permalink)
    0
    Thank you for the suggestions and information.
    I agree that there is no need for interrupt to the part of the code that you saw Susan.
    However, there few other things that also will be added in this code later on.
    One is that I have to also received the information that is sent from the PC and based on that information I have to execute other tasks. One of them will be whatever command I receive from PC I have to send that from Slave SPI to Master SPI.
    And also the Master SPI is sending the data at 1MHz clock and the USART has a baud rate of 9600 so won't that be a challenge?
     
    Vikram
    #4
    VikramTrivedi
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2017/11/30 09:20:39
    • Location: 0
    • Status: offline
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/04 11:46:06 (permalink)
    0
    Also one more reason why I cannot keep the while loop constantly waiting for the BF flag checking is that it will consume the CPU power and especially my application is on running on battery I will not be able to do this in while loop.
    Since this PIC is selected for its radio feature, the other task that will be always running is the radio Tx Rx concept that will be watching if another radio has sent any command or not?
    So I cannot use the while loop and have to use the interrupt concept.
    #5
    Aussie Susan
    Super Member
    • Total Posts : 3115
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/04 18:27:26 (permalink)
    0
    I quite understand about why you want to use interrupts and (presumably) sleep mode for the power savings.
    However I would suggest that you get the basic functionality working first and then add in the other layers.
    For example, step 1 is to make sure that you can reliably pass a character at a time from the SPI to the UART. Step 2 is to add in a buffer (if that is required - I don't know your full requirements). Step 3 might be to add in the processing for the return data and step 4 would be to add in the remaining functionality. Step 5 would be to make it all work while utilising sleep (or idle) mode as this may well alter the timing of various parts - but at leat you knwo they are basically working as intended.
    For step 1 I'd start with not using interrupts and then add them in later when you know that the external interactions are working correctly.
    Based on what you have said, if you are expecting to pass on commands from the PC to the SPI Master via this device, *and* you are expecting to use the low power (idle or sleep) modes, I assume that the SPI master is initiating exchanges sufficiently fast for it to receive the commands in a timely manner for your application. Don't forget that SPI is an exchange process and the master is in charge of when the exchanges take place. This can interfere with your requirement for low power while sleeping/idle mode if you are not careful.
    Susan
    #6
    VikramTrivedi
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2017/11/30 09:20:39
    • Location: 0
    • Status: offline
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/05 09:42:57 (permalink)
    0
    Thank you Susan for the suggestion on step by step approach.
    I did execute the firmware without interrupt for one byte of data transmission.
    That works fine.
    However, the SPI communication for more than one byte of data is getting distorted meaning I am getting all random data in the SPI buffer.
    The challenge is as below:
    The Master SPI is MSP432 and the driver library function for SPI transmission in MSP432 prepares a structure for SPI transfer. In that strucure is the SPI Tx buffer which is filled up with data before transmission begins. The SPI has seperate TX and RX buffer unlike PIC18 which has a single register for SPI TX and RX.
    So now when SPi transfer begins MSP432 SPI master is already having all the data to be sent but at the receiving end on PIC that has single register SSP1BUF for TX and RX it is becoming hard to store all consecutive characters coming into SPI slave.
    Not sure how to resolve this issue.
     
    Vikram
    #7
    qɥb
    Monolothic Member
    • Total Posts : 2060
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: online
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/05 12:10:41 (permalink)
    0
    VikramTrivedi
    ...
    So now when SPi transfer begins MSP432 SPI master is already having all the data to be sent but at the receiving end on PIC that has single register SSP1BUF for TX and RX it is becoming hard to store all consecutive characters coming into SPI slave.
    Not sure how to resolve this issue.

    I already told you back in post#3.
    The data is arriving faster than you can send it, so you MUST implement a FIFO buffer in the PIC.

    PicForum "it just works"
    #8
    VikramTrivedi
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2017/11/30 09:20:39
    • Location: 0
    • Status: offline
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/05 14:09:31 (permalink)
    0
    Hi Susan,
    So do you mean to use the DMA?
    Since I am using PIC18LF45K22, it does not have the DMA concept and I have verified going through the datasheet of the same.
    I have modified the code as below so that I can pass more data to Tx buffer on slave side so as to get more data in Rx.
    #include <xc.h>
    #include <string.h>
    #include "mcc_generated_files/mcc.h"
    #define MY_BUFFER_SIZE 2
    uint8_t data;
    uint8_t spi[2];
    volatile unsigned char r; // immediate received byte from ISR
    void USART_putc(unsigned char c); // byte by byte USART write function
    void USART_puts(unsigned char *s); // string of bytes USART write function
    uint8_t myTransmitBuffer[2] = {0xAA,0XBB};
    void USART_putc(unsigned char c)
    {
    while(!TXSTA2bits.TRMT2); // wait until transmit shift register is empty
    TXREG2 = c; // write character to TXREG and start transmission
    }
    void USART_puts(unsigned char *s)
    {
    while (*s)
    {
    USART_putc(*s); // send character pointed to by s
    s++; // increase pointer location to the next character
    }
    }
    void main(void)
    {
    uint8_t spicounter = 0;
    // Initialize the device
    SYSTEM_Initialize();
    USART_puts("Hi This is Test Program\r\n");
    Board_TXRX_DONE_SetLow();

    while(1)
    {
    while(spicounter < MY_BUFFER_SIZE)
    {
    spi[spicounter] = SPI_Write(myTransmitBuffer[spicounter]);
    spicounter++;
    _delay(50000);
    GREEN_LED_Toggle();
    }
    spicounter = 0;
    for(data = 0;data<MY_BUFFER_SIZE;data++)
    {
    USART_putc(spi[data]);
    LED_RED_Toggle();
    _delay(50000);
    }
    SSP1BUF = 0xBB;
    Board_TXRX_DONE_SetLow();
    }

    }
    unsigned char SPI_Write(unsigned char data)
    {
    SSP1CON1bits.WCOL = 0;
    SSP1BUF = data;
    SPI_Read();
    }
    unsigned char SPI_Read(void)
    {
    // Wait for Data Transmit/Receipt complete
    while(!SSP1STATbits.BF);
    Board_TXRX_DONE_SetHigh();
    return(SSP1BUF);
    }
    unsigned spiDataReady() //Check whether the data is ready to read
    {
    if(SSP1STATbits.BF)
    return 1;
    else
    return 0;
    }
     
    the Board_TXRX_Done_SetLow() and Set High() are providding a delay mechanism for the master to send next data byte.
     
    Not sure what is wrong in this.
    Please suggest.
     
    #9
    qɥb
    Monolothic Member
    • Total Posts : 2060
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: online
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/05 14:18:43 (permalink)
    0
    Ok, I'm done here. You plainly don't want to learn how to do it.
     

    PicForum "it just works"
    #10
    VikramTrivedi
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2017/11/30 09:20:39
    • Location: 0
    • Status: offline
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/05 14:26:46 (permalink)
    0
    If I don't want to learn why would I be asking this many questions.
    The point what is confusing is about making FIFO buffer.
    Since when I read the datasheet of other PIC's they have separate Tx and Rx buffers for example one is PIC24 which is not the same in PIC18 MCU that I am using.
    And now I can't change the PIC since the hardware is already finalized for production.
    And when you mentioned that data is arriving faster than I can send, I am not worried about the data that is sent back to Master for the time being since that can be ignored but the data that is received from master is more important.
    And i order to slow that down I have used the GPIO line which is pulled high and low in between SPI transfers.
     
    If I understood correctly making FIFO is same as creating a buffer with dummy bytes that are to be kept ready before calling the SPI_Read at the Slave end so that when Masters pulls the clock line to send data, Slave Tx has already data lined up in response to the data sent from Master SPI.
     
    #11
    qɥb
    Monolothic Member
    • Total Posts : 2060
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: online
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/05 14:41:35 (permalink)
    0
    A "FIFO" buffer" is a software concept, it does not require any hardware.
    It simply means you store received bytes in RAM as they are received, and read them out in the same order they were stored. That is what "First In, First Out" = "FIFO"  means.
    This is usually implemented with a "circular buffer" of a fixed size, with a read pointer and a write pointer that wrap back to the start when they reach the end.
     
    It's quite easy to be reading and writing at the same time. You just run a loop which continually does this:
    [1] Receive a byte from SPI to the FIFO if available
    [2] Send a byte from the FIFO to the USART, if the FIFO is not empty and the USART is ready
    [3] Go back to step #1
     
     
     

    PicForum "it just works"
    #12
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2262
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: online
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/05 16:27:18 (permalink)
    0
    It is impossible to manually wait on one module without stalling other parts.
    Adjusting your speeds will eventually overlap again.  It will never be reliable.
     
    i/o needs buffering because data comes in/out at different rates and is unpredictable.
    You have to make predictable.
    It is fundermental stuff you should have known when you learned how to code.
     

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #13
    Aussie Susan
    Super Member
    • Total Posts : 3115
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/05 18:54:31 (permalink)
    0
    VikramTrivedi
    However, the SPI communication for more than one byte of data is getting distorted meaning I am getting all random data in the SPI buffer.

    As others have said that could be that you are not handling the characters fast enough or that you are not using the '\SS\' signal and there is noise on the SCK line that is causing the slave to respond incorrectly.
    Also I was not suggesting that you only test this for 1 character. Have the slave reliably exchange a whole lot of characters first and then move on from there.
    VikramTrivedi
    The SPI has seperate TX and RX buffer unlike PIC18 which has a single register for SPI TX and RX.
     

    For the PIC this is not the case. Look at Figure 15-1 you will thee that there are separate read and write paths to the buffer. In the data sheet for this device (at least on my quick read) it does not really make it clear that this means there are (effectively) 2 registers with the same name. When you write to the buffer to do not overwrite the last received value, and also you will not automatically send the last received value on the next exchange.
    You can treat them as separate read and write buffers as long as you perform the accesses at the appropriate times (see the warning at the  bottom of section 15.2.1 abut the buffer not begin double buffered when you write to it).
    Susan
    #14
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2262
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: online
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/05 19:11:40 (permalink)
    0
    Also you can run this fast or slow.
    Have the slave send a busy state, read until ready.
     
    What is missing is that you don't have any protocol, send commands to the slave.
    i.e.
    spi_write(SPIDEV_BUSY);
    while(spi_read());
    spi_write(SPIDEV_GETBUFFER);
    spi_write(4); //bytes
     
    for(int f=0;f<4;f++)
        *ptr++=spi_read();

    post edited by Gort2015 - 2017/12/05 19:21:06

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #15
    VikramTrivedi
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2017/11/30 09:20:39
    • Location: 0
    • Status: offline
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/06 13:47:24 (permalink)
    0
    Thank you all for your suggestions.
    I tried to implement the FIFO concept in the code but it does not work still.
    I still get garbage value in the buffer that I am storing into even though the data on the MOSI line in the logic analyzer shows correct value.
    But the value on the MISO line is different in the sense it does not shows what I am sending but instead is shows what I have received on the MOSI line and that too every alternate character.
    For example from Master SPI I am sending ascii characters 0-9 followed by A-Z and then a-z I see this correctly on the MOSI line but on MISO line every alternate character is replaced by some fixed value sometimes 0x8A sometimes 0xE6 and others.
    For example I get on MISO line : '138','s','138','u','138,'w','138,'y','138'.....
    So if you see the characters in between the sequence are replaced by some constant character.
    I am also providing ample delay on the Master SPI before pulling the CS line high so that slave does not miss any character.
    Additionally I also tried providing a GPIO line between master and slave that is output on slave side and input on master side. So once the character is received I pull the line high so as to inform master not to send the next data buffer and only once the data is transfered to USART I pull the line low again. 
    This even did not work.
    Below is what I tried to implement the FIFO concept:
    if(inptr == outptr)
    {
    USART_puts("Buffer is empty\r\n");
    }
    spi[inptr++] = SPI_Read();
    if((inptr+1) == outptr)
    {
    USART_puts("Buffer is full\r\n");
    Board_TXRX_DONE_SetHigh();
    }
    _delay(50000);
    LED_RED_Toggle();
    SSP1BUF = 0x55;
    if(inptr == MY_BUFFER_SIZE)
    {
    inptr = 0;
    }
    if((inptr+1) == MY_BUFFER_SIZE)
    {
    inptr = 0;
    }
    USART_putc(spi[outptr++]);
    Board_TXRX_DONE_SetLow();
    _delay(50000);
    GREEN_LED_Toggle();
    if(outptr == MY_BUFFER_SIZE)
    {
    outptr = 0;
    }
     
    Even tried the concept that "Gort2015" suggested but even that did not work out.
    Gort2015
    Also you can run this fast or slow.
    Have the slave send a busy state, read until ready.
     
    What is missing is that you don't have any protocol, send commands to the slave.
    i.e.
    spi_write(SPIDEV_BUSY);
     
    while(spi_read());
     
    spi_write(SPIDEV_GETBUFFER);
     
    spi_write(4); //bytes
     
     
     
    for(int f=0;f<4;f++)
     
        *ptr++=spi_read();





    What I don't get in this is when you say to send 4 bytes over from spi_slave before reading the 4 bytes.
    When receiving the SPI data we can run the loop for SPI_read 4 times as it is going to get always new value uploaded in SSP1BUF .
    But when we are writting 4 bytes to SSP1BUF in one go, the SSP1BUF is just going to get overwritten since slave cannot initiate the transmission and when master initiates the transmission it gets the byte and loads some value on the same SSP1BUF which we have to read to get it empty.
    How would it work?
     
    Lastly, the FIFO concept is only useful if I have to get a byte and forward the byte immediately to the USART to display.
    But the application that I am trying to work is such that master SPI is going to send 240 bytes of data in one go which is supposed to be read by slave spi and send this over the USART to radio. In total there will 130 chunks of 240 bytes that SPI master is going to send and at the same time each chunk has to be sent to USART before another chunk is received by SPI slave.
    Not sure how FIFO concept will solve this issue.
     
    Thank you
    Vikram
    #16
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2262
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: online
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/06 16:09:56 (permalink)
    0
    Every time M does a write, set S reply as busy or not busy.
    When S reads data from M, S loads spi with busy, if M attempts a WR, S reloads SPI with busy.  That gives you all the time in the World for S to use the UART.
     
    They exchange meaning data from S is always one com. out of date.
     
    Have you tried a loopback on your master?
    Test the slave as well.
     
    A command structure is only the way to handle S spi coms.  Buffer is then optional.
    Try it again.
     
    You can get S to do a lot more than UART, that chip could be controlling an lcd, keyboard, midi and even do your coding for you like a dual core mpu.  You can also make use of the S ram.
     
    I also have the uart on another chip but not on the same board.  I use M spi to send command via 2.4GHz radio.  The S does what it has to but it lets M know that it is busy through the exchange.
     
    M always checks the return result when issuing a command to make sure S is ready.
    Doesn't matter if it takes 1 MicroSecond or 1 Hour.
     
    The S chip uses the uart, does other stuff and it is 2 Meters away.  I've had that going through two walls.  Never misses and you'll get the same if you do what I suggested.
     

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #17
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2262
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: online
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/06 16:17:46 (permalink)
    0
    That is a typical command to an spi device.
    -> command:read
    -> address
    -> send count
     
    The next 4 bytes read, any more reading returns status_ok.
     
    Set it up in 16bit mode for accessing S memory.
     
     

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #18
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2262
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: online
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/06 16:20:33 (permalink)
    0
    Even though I said read (post #18), the exchange still happens.
    Both sides must check their returns for a busy/message.
     
    If S is busy (data->uart) then M has to wait it's turn.  An error could have happened like uart down, check return values.
     
    post edited by Gort2015 - 2017/12/06 16:36:56

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #19
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2262
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: online
    Re: Combining USART and SPI togetther on PIC18LF45K22 micrcontroller 2017/12/06 16:30:14 (permalink)
    0
    On a break from programming and that fact that a hard disk crashed.
    (@#$%! Damn you Seagate)
     
    Too much time coding is bad for ya, you start dreaming of why bit of code is not working.
     

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #20
    Page: 123 > Showing page 1 of 3
    Jump to:
    © 2018 APG vNext Commercial Version 4.5