Menu

Uart events corruption

Eddie_1066
2021-08-31
2021-09-01
  • Eddie_1066

    Eddie_1066 - 2021-08-31

    Hi everyone, I need some advice or help.
    I’m having an issue with a uart1 ISR and active object implementation. I have an ISR that is triggered when the uart buffer has data. On entering the ISR a new from ISR event is requested from QF, data from the uart buffer is saved into the new event object, the same data is output to the terminal using another (Uart0) with in the ISR.
    This part is working as expected the second uart0 echo’s the data received by uart1. If 1234 is sent 1234 is echoed back. After the echo process, the data is posted to the AO_uart for processing ending the ISR.

    In the AO the uart event handler just passes the data out to the terminal on uart0. With the same input of 1234 the uart from the AO prints out the last 2 values 34. Sending 1 char at time rapidly works perfectly, no data is lost. Sending 2 or 4 char at the same time, results in the first char is lost, sending 6 chars only the 2nd,4th and 6th are received by the AO.

    I’m using the DPP FreeRTOS port example version 6.4.0 as a starting point on the tm4c123, the baud rate is 9600
    it takes about 10us for the uart ISR to collect data and post an evt. Any ideas as to why I’m losing the data bytes, are the events coming too fast for the AO? Which would not make any sense as the events will still be stored in the event queue.

    case NEW_UART_DATA_SIG: {
                char temp = Q_EVT_CAST(UartEvt)->temp;
                UART0_OutChar(Q_EVT_CAST(UartEvt)->temp);
    
    
                status_ = Q_HANDLED();
                break;
            }
    
    void UART1_IRQHandler(void) {
          BaseType_t xHigherPriorityTaskWoken = pdFALSE;
          uint32_t status = UART1->RIS; /* get the raw interrupt status */
          UART1->ICR = status;          /* clear the asserted interrupts */
          UartEvt *character = Q_NEW_FROM_ISR(UartEvt, NEW_UART_DATA_SIG);
    
    
    while (((UART1->FR & UART_FR_RXFE) == 0)) { /* while RX FIFO NOT empty */
        character->temp = UART1_CHAR;
              QACTIVE_POST_FROM_ISR(AO_BLE_uart,
                                    (QEvt *)character,
                                    &xHigherPriorityTaskWoken,
                                    &UART0_IRQHandler);
    
    }
    
    }
    

    Uart ISR----------------------------------------------------------

    
    

    ~~~

     

    Last edit: Eddie_1066 2021-09-01
  • Gawie de Vos

    Gawie de Vos - 2021-09-01

    I guess that your intention was to create a new event for every character received.
    You should move Q_NEW_FROM_ISR()into your while loop to achieve that. Otherwise you are just overwriting character->temp of the same event while sitting in the loop.

     

    Last edit: Gawie de Vos 2021-09-01
  • Quantum Leaps

    Quantum Leaps - 2021-09-01

    Hi Eddie,
    Your code seems to be wrong in so many ways that I'm not sure where to begin.

    So, perhaps first let's talk about your design. Your UART apparently has a FIFO, so it can transmit or receive several characters at a time, up to the FIFO capacity. Consequently, it seems reasonable to actually use this feature. Specifically, instead of receiving one character at a time, and then posting an event with this one character as parameter, you could receive all characters from the FIFO into a single event and then post that event. Similarly, you can load the FIFO with several characters to send and then let the UART do the sending. If the FIFO has, say 16 slots, this would be 16 times more efficient than your design. That's the whole point of having a hardware FIFO.

    So, here is your custom UartEvt event that can hold :

    enum { UART_FIFO_LEN = 16 }; /* adjust to your UART */
    . . .
    typedef struct {
        QEvt super; /* inherit QEvt */
        uint8_t len; /* length of the payload */
        char chars[UART_FIFO_LEN]; /* payload */
    } UartEvt;
    

    Now, the UART receive ISR:

    void UART1_IRQHandler(void) {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        uint32_t status = UART1->RIS; /* get the raw interrupt status */
        UART1->ICR = status;          /* clear the asserted interrupts */
        UartEvt *evt = Q_NEW_FROM_ISR(UartEvt, NEW_UART_DATA_SIG);
    
        evt->len = 0;
        while ((UART1->FR & UART_FR_RXFE) == 0) && (evt->len < UART_FIFO_LEN)) {
            evt->chars[evt->len] = UART1_CHAR;
            ++evt->len;
        }
        /* Q_ASSERT(evt->len < UART_FIFO_LEN) */
    
        QACTIVE_POST_FROM_ISR(AO_BLE_uart,
                              &evt->super,
                              &xHigherPriorityTaskWoken,
                              &UART1_IRQHandler);
    
       /* let FreeRTOS determine if context switch is needed...  */
       portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
    }
    

    As you can see, you build the the event in the while() loop and fill it with all the bytes currently available in the FIFO. You also store the actual number of bytes in the evt->len parameter. Then you post the whole event just once per ISR invocation, instead of many times as before.

    Also, your ISR code did not have the FreeRTOS call to portEND_SWITCHING_ISR(). This is a bizarre aspect of the FreeRTOS design, and that's why you have the "xHigherPriorityTaskWoken" variable.

    Now, regarding the processing of the NEW_UART_DATA_SIG signal in your active object, here is some pseudocode:

    case NEW_UART_DATA_SIG: {
        UartEvt *evt = Q_EVT_CAST(UartEvt);
        uint8_t n;
        for (n = 0; (n < evt->len); ++n) {
            UART0_OutChar(evt->chars[n]);
        }
        status_ = Q_HANDLED();
        break;
    }
    

    Again, you process all the "len" received bytes in the event.

    I hope that this design makes some sense to you.

    --MMS

     
  • Eddie_1066

    Eddie_1066 - 2021-09-01

    Hi Miro
    Thanks for the very detailed explanation much appreciated, learning a lot. Your explanation (example) is in line with what I discovered after extensive debugging and datasheet reading, I had made bad assumptions. I was not of the best way to proceed, your example and explanation helped solve that issue. Thanks again.
    Eddie.

     
  • Eddie_1066

    Eddie_1066 - 2021-09-01
     

    Last edit: Eddie_1066 2021-09-01

Log in to post a comment.