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.

CCS/EK-TM4C123GXL: Having trouble using my self-made queue with UART

Part Number: EK-TM4C123GXL

Tool/software: Code Composer Studio

Hello I'm trying to use UART with queue.

I think it doesn't have defect in logic but it works strange in the way.

For example, I added the content like "STATE 13 0 MODE 1 CALSTATE 0" and the result shows "STATEE 13 0 MODE 1 CALSTATE 0" or "STATE 33 0 MODE 1 CALSTATE 0"

I tried to debug and I can't understand the situation I encountered.

To do debugging, first I made a array variable and I stored the data MCU sent. And I confirm that queue's data is fine and the data come out from queue isn't fine.

But if I use break point every time, the data come out from queue suddenly works fine.

So, I think there's something wrong but I can't understand what's going on.

I attach the code I'm using

-----------------------------------------------------------------------------------------------------------------------------------

<<<<<<<<serialFunc.h>>>>>>>

#define BUFFERSIZE 256

class buffer
{
private:
    volatile uint8_t data[BUFFERSIZE];
    volatile uint32_t length;
    volatile uint32_t size;
    volatile uint32_t index;
    volatile uint32_t lineNum;
    volatile uint32_t readIndex;
    volatile uint32_t writeIndex;

public :
    void init();
    void addToEnd(uint8_t data);
    uint32_t byteAvailable();
    uint32_t lineAvailable();
    uint8_t getFromFront();
    uint8_t peek();
    void addArrayToEnd(const char* pui8Buffer);
    inline bool full();
    inline bool empty();

};

<<<<<<<<buffer.cpp>>>>>>>>

void buffer::init()
{
    length = 0;
    size = BUFFERSIZE;
    index = 0;
    lineNum = 0;
    readIndex = 0;
    writeIndex = 0;

    for(int i=0; i<BUFFERSIZE; i++)
        data[i] = 0;

}

void buffer::addToEnd(uint8_t cdata)
{
    IntMasterDisable();
    if(!full())

    {
     data[writeIndex] = cdata;
     writeIndex = (writeIndex+1)%size;

     if(cdata == '\n')
      lineNum++;

    }

    IntMasterEnable();

}

void buffer::addArrayToEnd(const char* pui8Buffer)
{
    IntMasterDisable();

    while(*pui8Buffer)
    {
     if(full())

      break;

     if(*pui8Buffer == '\n')
      lineNum++;

     data[writeIndex] = *pui8Buffer;
     pui8Buffer++;
     writeIndex = (writeIndex+1)%size;

    }

    IntMasterEnable();

}

uint32_t buffer::byteAvailable()
{
    return (writeIndex+size-readIndex)%size;

}

uint32_t buffer::lineAvailable()
{
    return lineNum;

}

uint8_t buffer::getFromFront()
{
    IntMasterDisable();

    static char returnValue;
    returnValue = 0;
   

    if(!empty())
    {
     returnValue = data[readIndex];
     readIndex = (readIndex+1)%size;

    }

    if(returnValue == '\n')
     lineNum--;

    IntMasterEnable();

    return returnValue;

}

uint8_t buffer::peek()
{
    IntMasterDisable();

    static uint8_t returnValue;

    if(empty())
     returnValue = 0;

    else
     returnValue = data[readIndex];

    IntMasterEnable();

    return returnValue;

}

inline bool buffer::empty()
{
 if(readIndex == writeIndex)
  return true;

 else
  return false;

}

inline bool buffer::full()
{
 if(((writeIndex+1)%size) == readIndex)
  return true;

 else
  return false;

}

<<<<<<<UART.cpp>>>>>>>>

void UARTIntHandler(void)
{
    IntMasterDisable();

    static uint32_t ui32Status;

    //
    // Get the interrupt status.
    //
    ui32Status = UARTIntStatus(UART0_BASE, true);

    //
    // Clear the asserted interrupts.
    //
    UARTIntClear(UART0_BASE, ui32Status);

    //
    // Loop while there are characters in the receive FIFO.
    //
    if(ui32Status & UART_INT_TX)
        Serial.transmit();

    if(UARTCharsAvail(UART0_BASE))
    {
        Serial.receive();

    }

    IntMasterEnable();

}

void serial::init()
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Enable pin PA0 for UART0 U0RX
    //
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0);

    //
    // Enable pin PA1 for UART0 U0TX
    //
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_1);

    UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 921600, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
   
    //
    // Enable the UART interrupt.
    //
    UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX2_8, UART_FIFO_RX4_8);
    IntEnable(INT_UART0);
    UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT | UART_INT_TX);

    IntRegister(INT_UART0, UARTIntHandler);
    //IntPrioritySet(INT_UART0, 0xE0);


    txBuffer.init();
    rxBuffer.init();

    timeout = 1000;

}

void serial::transmit()
{
    bool doTransmit = true;
    while (UARTSpaceAvail(UART0_BASE) && doTransmit)
    {
     if(!txBuffer.empty())
        {
      uint8_t cdata = txBuffer.peek();
      txBuffer.getFromFront();
         if(cdata)
          UARTCharPutNonBlocking(UART0_BASE, cdata);

        }

        else
        {
         doTransmit = false;
        }

    }

}

  • Hi,
    May have something to do with the baudrate between the transmitter and receiver. You are using a baudrate of 921600. Can you try 115200? Almost all TivaWare examples use this baudrate by default. See if it makes a difference so you can isolate the problem if baudrate dependent.
  • To Charles.

    Thanks for your advice. I followed your suggestion and it works much better. But still, I can't understand why baudrate makes the difference. Can you tell me the difference between using 921600 and 115200?

  • Hi Young,
    What is your source clock for the UART? The UART bit time is derived (or is divisible) from the UART clock. At high baudrate it will be hard to divide down and come close to the expected baudrate. Secondly, how far away are the transmitter and the receiver from each other? I think the longer the distance the more error prone it will be at extreme high baudrate.

  • first, 

    I made the main clock by using function like below. When I use SysCtlClockGet() function, it shows 80MHz

    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);   ///// 80MHz

    And I set the baudrate by using system clock for uart clock source.

    UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));

    Second, I'm using UART0 and it is transformed to USB by own launchpad itself. So, I think second one would not be a problem.

    Actually, I made the array to store the data which was delivered to UARTCharPutNonBlocking() and make breakpoint to see the data, it already crashed at that moment.

    Describing it with more detail,

    1. when breakpoint set everytime at UARTCharPut... func, data seems ok. 2. when breakpoint set randomly enabled by myself, data was crashed.

    Maybe this happens because of my mistake, but as the displayed results were same with the debugging one, I think it means something.

    But with this fact, I can't understand what's going on.. 

  • Hi Young,
    When you call UARTCharPutNonBlocking() please check the returned value to see if it returns false or true. If false, it means the write to FIFO failed perhaps the FIFO was already full in which case you will need to retry again.
  • I set fifolevel by using UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX1_8, UART_FIFO_RX4_8);
    And, in UARTIntterupt function, I put this logic

    if(ui32Status & UART_INT_TX)
    {
    bool doTransmit = true;
    while (UARTSpaceAvail(UART0_BASE) && doTransmit)
    {
    if(!txBuffer.empty())
    {
    uint8_t cdata = txBuffer.peek();

    if(cdata)
    if(UARTCharPutNonBlocking(UART0_BASE, cdata))
    txBuffer.getFromFront();

    }
    //UARTCharPutNonBlocking(UART0_BASE, txBuffer.getFromFront());

    else
    {
    doTransmit = false;
    }

    }

    }

    I think by using UARTSpaceAvail() I block the possibility of adding more data than FIFO can handle, and maybe getting the return value UARTCharPut...() function would help so I added one, but still it shows adding some one more same character or unpurposed data.

  • Take a look at getFromFront. What does it return when empty is true?

    BTW, I suspect PC-Lint would have caught this, although that static declaration might have hidden the error. That static declaration probably shouldn't be their either.

    Robert

    Oh, and why is it baud rate dependent? Two words, race condition.
  • Take a look at getFromFront. What does it return when empty is true?

    -> It returns 0, not stored one which was returned last called. I cleared it when the function start.

    BTW, I suspect PC-Lint would have caught this, although that static declaration might have hidden the error. That static declaration probably shouldn't be their either.

    -> I used static because I concerned about memory allocation problem if another intterupt occured. And plus, I did use the static variable but I also cleared the variable by put 0 in it.

    Oh, and why is it baud rate dependent? Two words, race condition.

    -> I know there would be race condition that makes problem, but I think I tried everything I could to prevent it.

    I used addBuffer function only in main loop and when I made addBuffer function, I put IntDisable function to the first and IntEnable function to the last to prevent interrupt occur while adding element.

    And when get element from buffer, here too added IntDisable and IntEnable

    If you saw something wrong I couldn't find out, please alert me the specific code part that makes problem for me.

  • Ok, I didn't see the zero init (that's one reason for asking questions rather than making assertions). That's not a useful safety construct and may actually cause more problems than it solves.

    Speaking of unsafe constructs, take a look at your use of int enable/ disable pairs. That's an inherently unsafe pattern. It fails if there is nested use. The safer version is to use a disable/ restore sequence. This is safe even when nested but does require a little more effort to setup. However, you are using the construct too often in any case. If you only allow a single producer and consumer you should only need to make the index/ pointer advancement atomic. If you allow multiple then you need to provide some sort of ownership token, perhaps by way of a mutex.

    Robert

    Oh, your code would be easier to follow if you used the paste code</> function