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.

Uart1 when cyclically transmitting data loses RX incoming events

I will try to explain my problem.

I am using Uart1 for both transmitting and receiving data. For RX, I have set a interrupt handler to catch the incoming data from NVIC. Both TX and RX are working ok when they are independent. 

However, when there is lots of TX data under transmission, it appears that the Uart loses the RX incoming events. If I send a few events to Tiva (so RX flag would set the INT_UART1), it loses. Only when I send a burst of lots of these data, it catches some of them.

I would like to set a kind of preemption clause in order to <even if there is transmit data ongoing>, it should stop/flush the transmission (if it is necessary) and prioritize the RX handler (so I can read the data as urgent). I have already set the priority for INT_UART1 as 0x00, and the other priorities more than that, but it did not work.

Any ideas?

Thanks in advance.

  • Hello Pablo,

    The UART Has only one interrupt, so it depends on how the Interrupt Handler has been written to process the interrupt. If you can share the interrupt handler code it would be more useful to see if it can be optimized

    Also is the FIFO enabled for the RX path.

    Regards

    Amit

  • I've forgotten how this UART is implemented, but it may be possible  that you are clearing the interrupt before you read the incoming data. You should check all sources of interrupt before exiting the interrupt routine. Generally you end up with an infinite loop reading the interrupt status register until it's clear. It takes care to ensure it's correct.

    Robert

  • Hello Amit,

    I implemented the handler this way:

    void Uart1_Input_Handle(void) {
    uint8_t i;
    uint32_t status;
    status = UARTIntStatus(UART1_BASE, true); // get interrupt status
    UARTIntClear(UART1_BASE, status); // clear the asserted interrupts
    while (UARTCharsAvail(UART1_BASE)) {

    // Shift left the buffer

    for (i = 0; i < sizeof(global_Uart1Buffer64) - 1; i++)
    global_Uart1Buffer64[i] = global_Uart1Buffer64[i + 1];
     // Read the char and put it on the last position in the buffer
    global_Uart1Buffer64[sizeof(global_Uart1Buffer64) - 1] =
    UARTCharGetNonBlocking(UART1_BASE);
     // Signalize data ready to be read
    global_Uart1ReadyFlag = true;
    }
    }

    (obviously it's configured in NVIC.) And I configured Uart1 using

    void Uart1_Setup() {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    GPIOPinConfigure(GPIO_PB0_U1RX);
    GPIOPinConfigure(GPIO_PB1_U1TX);
    GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTConfigSetExpClk(UART1_BASE, SysCtlClockGet(), 19200,
    (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
    IntEnable(INT_UART1);
    UARTIntEnable(UART1_BASE, UART_INT_RX | UART_INT_RT);
    }


    Also there are other 2 interrupts working. One is from I2C0, and the other is from TIMER0. TIMER0 counter triggers a scheduler. In this scheduler, one task makes cyclic writes in Uart1, so I am periodically sending data through Uart, and sometimes I should receive data from it; but this receiving data is prioritary over that I am sending. 

    In this case, I send several 64-byte buffers using

    void Uart1_Output_Put(char *prmBuffer, int prmSize) {
    int i;
    char currentChar;
    for (i = 0; i < prmSize; i++) {
    currentChar = prmBuffer[i];
    UARTCharPut(UART1_BASE, currentChar);
    }
    }

    Do you see where am I mistaken?

    Anyway, if I relax the scheduler by sending so fewer messages, the rate of success in catching the Uart RX interrupt is much bigger, but this totally breaks my deadlines. Maybe I've forgotten some configuration.

    Also, I do not make any FIFO configuration.

    Thanks.

  • Hello Robert,

    I am handling the Uart1 interrupt this way:

    void Uart1_Input_Handle(void) {
    uint8_t i;
    uint32_t status;
    status = UARTIntStatus(UART1_BASE, true); // get interrupt status
    UARTIntClear(UART1_BASE, status); // clear the asserted interrupts
     while (UARTCharsAvail(UART1_BASE)) {
    // Shift left the buffer
    for (i = 0; i < sizeof(global_Uart1Buffer64) - 1; i++)
    global_Uart1Buffer64[i] = global_Uart1Buffer64[i + 1];
    // Read the char and put it on the last position in the buffer
    global_Uart1Buffer64[sizeof(global_Uart1Buffer64) - 1] =
    UARTCharGetNonBlocking(UART1_BASE);
    // Signalize data ready to be read
    global_Uart1ReadyFlag = true;
    }
    }

    So I am really reading the data after the interrupt is cleared. But should this be a problem?

    I am also not while(ing) at the final. But why should this be a problem? If the handler gets out, it should return to it if the interrupt continues enabled. Anyway, the problem is that the handler even is not called (so the RX INT coming events are lost).

  • That's what I was worried you were doing.

    I don't have a reflexive knowledge of the API and I'm not in a place to easily access it. However, you are ignoring the status return. That's a recipe that can easily miss interrupts. With some implementation of UARTs this could lead to missed characters (in the case that read acknowledges).

    Also, how does the reciever know what has been read.?

    Robert

  • Hello Pablo,

    Is the Transmission of the TX Buffer being scheduled in the Interrupt Handler of the Timer-0? If that is case then it could be a problem as the UART RX interrupt could be delayed and a potential Over Run could occur. Is the OE status flag being set?

    Regards,

    Amit

  • Hello Amit,

    The transmission of the TX Buffer is scheduled in the Timer-0 routine, because I have to send the data periodically. But why an Over Run could make the RX handler not to be called? I have set the OE status flag now, but seems no change.

    Regards,

    Pablo.

  • Pablo,

    I took a quick look at this UART, I think what you have will sort  of work. I think you should still have a stub for the other cases, to know if any cases occur.

    However, consider what happens when you receive more characters than the buffer size. What happens when you receive an extra character or lose one?

    Robert

  • I am clearing the interrupt status using the calls

     status = UARTIntStatus(UART1_BASE, true); // get interrupt status
    UARTIntClear(UART1_BASE, status); // clear the asserted interrupts

    The receiver does not know that the command sent has been read. At least not directly. But it should not be necessary, and would lead to undesired increase in command-response time for the mcu.

    I still don't get why this could cause the RX interrupt handler to not be called.

    Thanks,

    Pablo.

  • Hello Robert,

    I agree that if I receive more characters than my buffer size, I would lose data. However what's (I think) happening is the opposite. Be clear that if I disable the cyclic TX, the RX works pretty well, even if I sent a burst of data. 

    Anyway, [TX turned on] if I send just one 64-byte buffer (my interface has a button which sends a message using a Radio UART), it looses the data. But if I send much more data (if I keep pressing fast and repeatly the button), some time it catches the message, and the breakpoint inside the RX handler breaks.

    Thanks.

  • Pablo,

    You are using an inherently unreliable communication media. You have no way to detect the start of a packet. You do not appear to have a check on the packet validity, although you may be planning on adding it later. You have no overrun checks on either the UART or the internal buffer.

    What I've seen so far I would expect to fail on a good wired connection.

    The overflow flag Amit is suggesting will not prevent data loss, only let you know that it has occurred.

    Finally,  you should check your radio.  Many are half duplex and will not receive while sending. You will easily lose information that way.

    Robert

  • Pablo Rego said:

    The receiver does not know that the command sent has been read.

    Yes, it does. You have a flag you use for that.

     

    Pablo Rego said:

    I still don't get why this could cause the RX interrupt handler to not be called.

    It would cause you to lose data.

    Robert

  • Robert,

    I validate the data in the input and the output. It follows a communication protocol for checking the packet validity, just I don't have an ack. It is simple at this point, but checks a command message. Basically it's a 64-byte sized message begining with "/" and terminated by ";". Inside it there are several byte divisions.

    I will include the OE check latter, there are some other checks I will do besides this, but this time it seems more important to solve the lost of RX interrupt events.

    A friend made me a question I could not answer... does Tiva uses the same buffer for Rx and for Tx? And what is the size? Maybe I am sending full buffer all the time, and when I need space for Rx, there is no more space. Does it make sense?

  • Pablo Rego said:

     Basically it's a 64-byte sized message begining with "/" and terminated by ";". Inside it there are several byte divisions.

    You do not check for that when reading your packet. It is extremely easy for you to get out of sync and you cannot recover. You cannot ensure you even have sync when you start.

    Pablo Rego said:

    A friend made me a question I could not answer... does Tiva uses the same buffer for Rx and for Tx?

    I would be incredibly shocked if that was the case. UARTs are expected to send and receive at the same time on independent channels. 

    Robert

  • Check your radio. I expect it's half duplex.

    Robert

  • Robert,

    It's half duplex, your're right. 

    In this case I will have to work with limited tx rate in order to be able to receive the data.

    Thanks.

  • Pablo Rego said:

    Robert,

    It's half duplex, your're right. 

    In this case I will have to work with limited tx rate in order to be able to receive the data.

    Thanks.

    That may help Pablo, but I think it's only part of the solution.

    I think you need to add some additional checks:

      - check to see if you are receiving before attempting to transmit to further reduce collisions. You might find inspiration in rs-485 protocols

      - add a check for start of packet before writing received data into the packet buffer . I think this is essential. In fact I would rewrite the receive interrupt to move the parsing you already have in it to the processing thread and just do a conventional fifo. This will also make other integrity checks like runt packet detection easier.

     - have some method to deal with missed packets. They are going to occur. The right response might be to ignore them if the desired effect is that you get information later. OTOH, the right response may be to shut down.

     - consider what happens at the receiver when the transmitter stops.

    Robert

  • Hi,
    I read today your posts and noticed several problems with your code.
    1) First, you may note the UART has a single interrupt vector for both sending and receiving and since you enabled both, you must treat both inside the handler. See this:

    status = UARTIntStatus(UART1_BASE, true); // get interrupt status
    UARTIntClear(UART1_BASE, status); // clear the asserted interrupts

    if (status & RX_flag) { // OK, this is receive part
    // do here whatever you need
    }

    if (status & TX_flag) { // OK, this is transmit part
    // do here transmit
    }

    2) Noticed also the UARTEnble() is missing, maybe is in some other part, would be wise to be same as init, but..

    3) When sending from timer: since you try to send 64 bytes, what is the time set for the timer? is is bigger than 64xbyte time for 19200 bauds? (i.e. between two timer events, do you have enough time to send all 64 bytes?)

    4) Also sending: you set up a for loop, forcing the micro to wait(poll) that transmission. Since you use interrupt for timer, this construction is not appropriate - would be better to prepare a buffer, and send from UART interrupt. In this case maybe sending only one byte at the time would be better - this way you put the hardware to work for you, without much software complications.

    5) Same problem with receiving. Your code:
    while (UARTCharsAvail(UART1_BASE)) {
    // Shift left the buffer
    for (i = 0; i < sizeof(global_Uart1Buffer64) - 1; i++)
    global_Uart1Buffer64[i] = global_Uart1Buffer64[i + 1];
    Again, the for loop is not good to use it here - the FIFO is not 64 bytes, so you must provide means to manage the case if no chars available and to get out of interrupt. Just use indexing without for loop. (the chars available are managed by the while block, so no for loop should be here...).

    Petrei

  • If I may - we too at times employ radio - and just as Robert guides, "Radio rarely is w/out adventure!"

    Might I suggest that you FIRST "test/verify" your serial handling - via a wired connection - either to another MCU or a properly configured, PC serial port.  Only/ever/always - after your "wired" handling/protocol proves robust - would I venture into radio. 

    Further - might you be able to test for "separation" between RX & TX buffers - by limiting transmission length (on each side) so that "both" TX & RX data may "together fit" w/in a "single" buffer?  (should the read of the buffer then reveal "mixed" data {both TX & RX} that may point toward "common" buffer)