This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LAUNCHXL-F28P65X: SCI Communication issues

Part Number: LAUNCHXL-F28P65X
Other Parts Discussed in Thread: C2000WARE, SYSCONFIG

Tool/software:

Hi everyone,

I'm currently working on interfacing my 65x board with a GNSS module using the Serial Communication Interface (SCI). I'm encountering several issues that I'm hoping to resolve with your help. Here's a brief overview of my setup and the challenges I'm facing:

I need to reliably receive approximately 70 bytes of GNSS data from the module. The data frequency and size can vary, so I've implemented interrupts and FIFO buffers to ensure consistent data handling. Given the time-critical nature of my application, it's essential that the data remains accurate, as it affects multiple subsystems.

To manage data flow, I've enabled FIFO interrupts for reception with a threshold set at the FIFO level full. Consequently, for 70 bytes of data, the RX FIFO generates 4 interrupts to read 64 bytes. However, this leaves 6 bytes remaining in the FIFO buffer. To retrieve the last 6 bytes, I check the RX FIFO status using the API SCI_getRxFIFOStatus(SCI0_BASE).

Here are the specific issues I'm encountering:

  1. ISR Issues with FIFO Status Check: The SCI_getRxFIFOStatus function does not seem to work within the RX FIFO ISR. I attempted to access the FIFO status directly using (HWREGH(base_addr + SCI_O_FFRX) & SCI_FFRX_RXFFST_M) >> SCI_FFRX_RXFFST_S;, but this also fails. Is there a reason why direct hardware access wouldn't work inside the ISR, or am I missing something?

  2. Inconsistent RX Data: The SCI RX data I'm receiving is inconsistent; I often only receive the last 32 bytes or so of the transmitted data. This inconsistency appears to arise when I send data continuously. However, when I transmit just once, the data is accurate. I'm puzzled as to why this behavior occurs.

  3. Interrupt Nesting: Is interrupt nesting enabled in the board or in C2000ware? Is there anything specific I need to do to enable nested interrupts?

I've attached relevant code snippets and the sysconfig for reference. Any insights or suggestions would be greatly appreciated!

Thank you for your help

#include "driverlib.h"
#include "device.h"
#include "board.h"
#include "c2000ware_libraries.h"
#include "stdio.h"
#define BUFFER_SIZE 70
#define CHUNK_SIZE 16
#define base_addr 0x00007210U
//
// Main
//

char txmsg[] = "$GNRMC,123456.00,A,3751.65,N,12225.55,W,0.00,180.00,230920,0.00,E,D";
char rxmsg[BUFFER_SIZE];
char *pos;
volatile uint32_t currentPos = 0;
int check = 0;
volatile uint16_t scitxcount = 0;
volatile uint16_t scirxcount = 0;
volatile uint16_t timerinterruptfreq = 0;
volatile uint32_t scirxlvl;
void buffercntl(char data);
void INT_SCI0_RX_ISR(void);
void INT_SCI0_TX_ISR(void);
void error(void);
void INT_myCPUTIMER0_ISR(void);

//void buffercntl(char data){
//    uint32_t nexthead = (head+16)%BUFFER_SIZE;
//    if (nexthead != tail) {
//        rxmsg[msg] = data;
//        head = nexthead;
//    }
//}


__interrupt void INT_SCI0_RX_ISR(void){
    uint32_t rxintstat = SCI_getInterruptStatus(SCI0_BASE);
    switch(rxintstat){
    case SCI_INT_PE:
        SCI_writeCharNonBlocking(SCI1_BASE, 'P');
        error();
        break;
    case SCI_INT_OE:
        SCI_writeCharNonBlocking(SCI1_BASE, 'O');
        error();
        break;
    case SCI_INT_FE:
        SCI_writeCharNonBlocking(SCI1_BASE, 'F');
        error();
        break;
    case SCI_INT_RXERR:
        SCI_writeCharNonBlocking(SCI1_BASE, 'R');
        error();
        break;
    default:
        //error();
        break;
    }
//
// received data handling
//
//
    uint16_t bytesToRead = CHUNK_SIZE;
    if (currentPos + bytesToRead > BUFFER_SIZE) {
        bytesToRead = BUFFER_SIZE - currentPos;
    }
    SCI_readCharArray(SCI0_BASE, (uint16_t*)&rxmsg[currentPos], bytesToRead);
    currentPos += bytesToRead;

    scirxlvl = (SCI_RxFIFOLevel)(HWREGH(base_addr + SCI_O_FFRX) & SCI_FFRX_RXFFST_M) >> SCI_FFRX_RXFFST_S;
    if((BUFFER_SIZE-currentPos)< CHUNK_SIZE){
        while(scirxlvl){
                rxmsg[currentPos++] = SCI_readCharNonBlocking(SCI0_BASE);
                check++;
            }
    }
    if (currentPos >= BUFFER_SIZE) {
       // SCI_writeCharArray(SCI1_BASE, (uint16_t*)rxmsg, sizeof(rxmsg));
        currentPos = 0; // Reset position
    }

    scirxcount++;
    GPIO_togglePin(myLED1_GPIO);
    //overflow condition check?

    SCI_clearOverflowStatus(SCI0_BASE);
    SCI_clearInterruptStatus(SCI0_BASE, SCI_INT_RXFF);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

}

__interrupt void INT_SCI0_TX_ISR(void){
    GPIO_togglePin(myLED0_GPIO);
    scitxcount++;
    SCI_clearInterruptStatus(SCI0_BASE, SCI_INT_TXFF);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

}

__interrupt void INT_myCPUTIMER0_ISR(void){             //cpu timer to simulate data transmission every 1 second
    timerinterruptfreq++;
    SCI_writeCharArray(SCI1_BASE,(uint16_t*)txmsg,sizeof(txmsg));
    Interrupt_clearACKGroup(INT_myCPUTIMER0_INTERRUPT_ACK_GROUP);
}

void error(void)
{
    asm("     ESTOP0"); // Test failed
    for (;;);
}
void main(void)
{

    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Disable pin locks and enable internal pull-ups.
    //
    Device_initGPIO();

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // PinMux and Peripheral Initialization
    //
    Board_init();

    //
    // C2000Ware Library initialization
    //
    C2000Ware_libraries_init();

    //
    // Enable Global Interrupt (INTM) and real time interrupt (DBGM)
    //
    EINT;
    ERTM;
    //SCI_writeCharArray(SCI0_BASE,(uint16_t*)txmsg,sizeof(txmsg));
    while(1)
    {
        scirxlvl = SCI_getRxFIFOStatus(SCI0_BASE);

//        sprintf(pos,"%d",(int)currentPos);
//        SCI_writeCharBlockingNonFIFO(SCI1_BASE,(uint16_t)*pos);
//        sprintf(buff,"%d",)
//        SCI_writeCharNonBlocking(SCI1_BASE, scitxlvl);
//        SCI_writeCharNonBlocking(SCI1_BASE, scirxlvl);
    }
}

//
// End of File
//

How best can i implement this application so i can transmit and receive data in full duplex and still maintain reliable and consistent data.

This is still in development so any suggestions are welcome.

Thank you in advance

Ashwin Bhaskar A

  • ISR Issues with FIFO Status Check: The SCI_getRxFIFOStatus function does not seem to work within the RX FIFO ISR. I attempted to access the FIFO status directly using (HWREGH(base_addr + SCI_O_FFRX) & SCI_FFRX_RXFFST_M) >> SCI_FFRX_RXFFST_S;, but this also fails. Is there a reason why direct hardware access wouldn't work inside the ISR, or am I missing something?

    Can you explain what you mean when you say it fails? One thing to keep in mind is that CPU is running much faster than the SCI baud rate. It is possible that the FIFO is simply empty because no new RX character has been received when you read the FIFO status.

    Inconsistent RX Data: The SCI RX data I'm receiving is inconsistent; I often only receive the last 32 bytes or so of the transmitted data. This inconsistency appears to arise when I send data continuously. However, when I transmit just once, the data is accurate. I'm puzzled as to why this behavior occurs.

    This sounds like your FIFO handling scheme has some issue.

    Interrupt Nesting: Is interrupt nesting enabled in the board or in C2000ware? Is there anything specific I need to do to enable nested interrupts?

    Please review the article below.

    https://software-dl.ti.com/C2000/docs/c28x_interrupt_nesting/html/index.html

    Coming back to the original question which I believe is: What is the best way to make use of UART FIFO interrupt level to generate the fewest possible interrupts without creating the possibility of leaving data in the FIFO? 

    First, I would personally not set the RX FIFO level to max. SCI interrupts are pretty low in the priority list. Setting the RX FIFO to max trigger level leaves the possibility of an RX FIFO overrun when the CPU is not able to read data in time, e.g. when the CPU is in some higher priority ISR. Interrupt nesting sounds like a fix, but then again you may not want to interrupt some high priority ISR.

    Second, you could use an RX FIFO trigger level of 1. This would generate the most interrupts, but given that SCI interrupts have lower priority, this may be acceptable. 

    Third, is the frame length embedded in the SCI data? If so, is it possible to architect your code such that you use interrupts to to receive n x 16 characters in the frame, and then uses polling outside the ISR to read the remaining number of a characters? You could do the polling in some background task.

  • Hi Gus

    Thank you for your prompt response

    Can you explain what you mean when you say it fails? One thing to keep in mind is that CPU is running much faster than the SCI baud rate. It is possible that the FIFO is simply empty because no new RX character has been received when you read the FIFO status.

    What i meant was I'm sure that data is left in the FIFO because i checked it outside the ISR. If u check the code you can see commented code in the while(1) loop that checks the same. This shows that there is data left in the FIFO, but when i use the same API to check inside the ISR it sometimes throws junk values or 0. Even if i try to access registers directly it still throws the same issues.

    Second, you could use an RX FIFO trigger level of 1. This would generate the most interrupts, but given that SCI interrupts have lower priority, this may be acceptable. 

    My concern with such kind of approach is that it will tank my system performance because i have to generate absurd amount of interrupts . As i said i data will be dynamic in size and could come at a periodicity of 200 ms . The data size could go high as 1024 bytes . That's 1024 interrupts inside 200 ms. Will this tank my systems ability to perform other tasks. I am new to TI boards so forgive me if I'm wrong in any of this.

    Third, is the frame length embedded in the SCI data? If so, is it possible to architect your code such that you use interrupts to to receive n x 16 characters in the frame, and then uses polling outside the ISR to read the remaining number of a characters? You could do the polling in some background task.

    Do you mean that i should get 16 bytes of data at a time and then poll to get the rest of the data?. That would mean i need to generate interrupt at every 16 bytes. 

    First, I would personally not set the RX FIFO level to max. SCI interrupts are pretty low in the priority list. Setting the RX FIFO to max trigger level leaves the possibility of an RX FIFO overrun when the CPU is not able to read data in time, e.g. when the CPU is in some higher priority ISR. Interrupt nesting sounds like a fix, but then again you may not want to interrupt some high priority ISR.

    But that would contradict to what you said above. Are you saying its a tradeoff ?

    My main concern is to maintain data integrity without compromising my system performance. 

    As i said i am new to TI so please correct me if i am wrong in any of this.

    Thank you again for your inputs.

  • Hi Ashwin,

    Note: while(scirxlvl){

    Checking buffer level (main.c) high speed loop might lead to synchronization issues between CPU and SCI peripheral, besides it wastes precious CPU time. As Gus mentions set FIFO trigger level below what is expected in a single PIE interrupt for CPU to handle. TRM recommends checking for RX overflow status in the RXISR handler. We ignore overflow data, clear the overflow and exit RXISR. Serial data can cause FIFO framing errors depending on cable length and noise on RX/TX data paths. Be sure to use shielded twisted pairs to reduce errors even when testing between devices, especially testing without long distance receiver & transmit drivers.

          /* Check SCIFFRX register FIFO has overflowed */
            //if(SCI_getOverflowStatus(SCIB_BASE))
            if((HWREGH(SCIB_BASE + SCI_O_FFRX) & SCI_FFRX_RXFFOVF) == SCI_FFRX_RXFFOVF)
            {
                /* Clear Rx overflow status */
                //SCI_clearOverflowStatus(SCIB_BASE);
    
                /* clear SCIFFRX RXFFOVF SCIB */
                HWREGH(SCIB_BASE + SCI_O_FFRX) |= SCI_FFRX_RXFFOVRCLR;
    
                /* SCIA Prints event message */
                SCIprintf("\n*ClrOVF\n");
    
                /* Flush the RX buffer */
                for(i=0; i == 31; i++)
                {
                    CcRxBuff[i] = 0;
                }
    
                #if DEBUG
                    SCIprintf("\n>> RxBuffFlushed \n");
    
                #endif
    
                goto Exit;
    
            }
    

  • Ashwin,

    I don't know the specifics of your GNSS module and how it generates UART frames so it's difficult to provide a suggestion. My proposal was that *if* the UART data from the GNSS module includes the number of bytes in the frame, then you could architect your code around that. For example, if the GNSS module minimum frame length is say 8 characters, and if one of those characters is the frame length, then you could write your code as:

    - RX interrupt level = 8

    - In RX ISR, always read 8 characters from RX FIFO. If first 8 characters, determine the frame length there, set some global variable to track the # characters received vs. total frame length

    - In main.c background task, wait for # characters received = total frame length. If total frame length is not a multiple of 8 (UART RX INT trigger level), and the last N characters remain, poll UART RX FIFO level until last remaining characters have been received. Here N = frame length % 8. 

  • Hi Gus,

    Thank you for your suggestions,

    I think i understand what you are recommending. But ideally it would've been better for me to deal with the N characters inside the RX ISR. I had a logic that required me to check the RXFIL level and use that to get the data within the FIFO. But for some reason i was not able to get the register value even though i am using HWREGH . That was one of my primary questions. 

    As Genatco mentioned polling for buffer level or polling the remaining characters might waste system resources, which was my main motive in going for FIFO interrupts in the RX side. 

    I will try implementing your suggestions and evaluate my system to see what works. 

    Thank you again for your suggestions Gus and Genatco. 

    Warm Regards

    Ashwin Bhaskar A

  • The x49c SCI RX FIFO 16 levels deep (10bit register) first word buffered, (same x65 SCI)??  We managed to input 32 characters in single ISR loop. Checking the RX FIFO trigger set 6 words RXISR input loop function calls another FIFO drain function (below) prior to clear ACK SCI group. Seemingly has something to do with pushing RXISR return address on the stack and calling RX input function handler to drain the FIFO.

      CPU pops the call stack sometime after call far process 32x 8-bit buffered data. The SCI peripheral is bus clocked and RXFIFO will keep processing serial data, additional triggered level interrupts will be ignored until SCI group clear ACK. You can input as many characters as character buffer is set to hold, ePIE flag state signal the CPU to keep processing the interrupt data.

    #define ARGU_NRX_BUF_SIZE           32
    
    /* Command input buffer */
    char CcRxBuff[ARGU_NRX_BUF_SIZE];
    
    /* Load RX data elements */
    for(i = 0; i <= 31; i++)
    {
        CcRxBuff[i] = (HWREG(SCIB_BASE + SCI_O_RXBUF) & SCI_RXBUF_SAR_M);
    }