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.

Can only read 16 bytes from UART1 in TM4C1230D5PM

Other Parts Discussed in Thread: TM4C1230D5PM

Hi All.


I know this question has kinda been asked before, but I could not find any clear-cut answer.

Let me explain our setup.

We have a Telit-GSM module interfaced with the TM4C1230D5PM, and this includes the interfacing of RTS/CTS pins.

In code, we have done the following ::

    /*
     * Initialize the UART1.
     */
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);

    /*
     * Set up the RTS/CTS pins.
     */
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinConfigure(GPIO_PF0_U1RTS);
    GPIOPinConfigure(GPIO_PF1_U1CTS);
    ROM_GPIOPinTypeUART(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    /*
     * Set up the RX/TX pins.
     */
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    GPIOPinConfigure(GPIO_PC4_U1RX);
    GPIOPinConfigure(GPIO_PC5_U1TX);
    ROM_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    /*
     * Configure the UART for 9600, 8-N-1 operation.
     */
    ROM_UARTConfigSetExpClk(UART1_BASE, ROM_SysCtlClockGet(), 9600,
                            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                             UART_CONFIG_PAR_NONE));

    /*
     * Final UART1-initializations.
     */
    ROM_UARTFIFOEnable(UART1_BASE);
    ROM_UARTEnable(UART1_BASE);

    /*
     * Enable the interrupts (only RX).
     */
    ROM_IntEnable(INT_UART1);
    UARTIntDisable(UART1_BASE, UART_INT_TX);
    ROM_UARTIntEnable(UART1_BASE, UART_INT_RX);


Also, following is the Interrupt-Handler (UART1Handler,                      // UART1 Rx and Tx)

static void
UART1Handler(void)
{
    unsigned long interrupts;

    interrupts  = UARTIntStatus(UART1_BASE, true);
    info_log("0x%x", interrupts);
    UARTIntClear(UART1_BASE, interrupts);


    if(1)
    {
        while(ROM_UARTCharsAvail(UART1_BASE))
        {
            info_log("[%c]",  ROM_UARTCharGetNonBlocking(UART1_BASE));
            }
    }

    ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);
    info_log("exiting");
}

("info_log" is a library function of ours, which just writes to a serial UART0 to a console).

Now, when we power on the board, we send a "AT+CGSN\r\n" command to Telit-Module (via UART1), and thereafter enter into infinite-loop in the main-thread.

Thereafter, the interrupt-handler (UART1Handler) gets called JUST ONCE, and exactly 16 bytes are read every time.

Please note that if we use any other permutation (like disabling RTS/CTS, and/or disabling interrupts), the behaviour is not consistent, and sometimes 14/15/16/17 bytes are read. With RTS/CTS enabled and interrupts enabled, we are at least getting a consistent behaviour (of exactly 16 bytes being read every time).

What needs to be done, so that the complete response can be read in a deterministic, consistent manner? I guess we need to do something extra with RTS/CTS, but can't figure it out.

Will be grateful for any pointers to hit the needle in the hay.

Thanks and Regards,

Ajay

  • If the Interrupt-handler section is changed to 

        if(1)
        {
            while(1)
            {
                info_log("[%c]",  ROM_UARTCharGet(UART1_BASE));
            }
        }
    

    5 extra bytes are read (thereby total of 21 bytes), but still not complete, and no "\r\n".

    Really desperate to know the "that's it" way.

  • Hello Ajay

    Did you check the UART's status register to see if the FIFO has data or not (the flag is RNE).

    Regards
    Amit
  • ("info_log" is a library function of ours, which just writes to a serial UART0 to a console).

    That is a problem. Potentially a big one and fairly fundamental. Calling a serial output routine within a serial input interrupt is really risking overrun, especially if the rates are similar. And that's before you added the formatting step.

    You need to move your processing outside the interrupt, including the logging.

    Robert

    Your symptoms are absolutely consistent with overrun. I think this UART has an overrun flag you can check
  • Hi Amit, Robert.


    Thanks for the replies.

    I have a basic query at this point ::

    Is the chance of overrun due to (excessive) processing within the interrupt-handler? Or is it that no other function can be called from within the interrupt-handler (which might cause something like stack-overflow)?

    If it indeed is the (excessive) processing, is there a deterministic solution to the issue? I would believe that using hardware-control (using RTS/CTS) would take care of that, irrespective of how fast/slow the interrupt-processing is?


    As it is, a consistent deterministic behaviour is highly desired, speed is not at all mandatory.

    Looking forward to some light on this conceptual query.

    Thanks and Regards,

    Ajay

  • Ajay Garg said:
    Hi Amit, Robert.

    Thanks for the replies.

    I have a basic query at this point ::

    Is the chance of overrun due to (excessive) processing within the interrupt-handler?

    yes
    Ajay Garg said:
    Or is it that no other function can be called from within the interrupt-handler (which might cause something like stack-overflow)?
    yes
    Ajay Garg said:

    If it indeed is the (excessive) processing, is there a deterministic solution to the issue?

    yes
    Ajay Garg said:
    I would believe that using hardware-control (using RTS/CTS) would take care of that, irrespective of how fast/slow the interrupt-processing is?
    no
    Ajay Garg said:

    As it is, a consistent deterministic behaviour is highly desired, speed is not at all mandatory.

    Looking forward to some light on this conceptual query.

    Thanks and Regards,

    Ajay

  • Sorry for the double post to reply but the editor is broken to near non functionality on a tablet.

    The last answer should be amplified. There is no standard for the behaviour of CTS/RTS. Neither de facto or de jure. To use it you need to ask

    Does the module you are connecting to support I? If so, how?
    Is your implementation working? Is it compatible?

    Several common implementations

    Stop transmitting after the current character
    Stop transmitting when the transmit buffer is empty
    Stop transmitting after the current transaction

    Note that transmit FIFOs on many UARTs by necessity make the second option fairly common.

    A perfectly general implementation must be able to accept an arbitrary number of characters after telling the transmitter to stop.

    Xon/Xoff has the same issues along with a few more.

    Robert
  • Thanks Robert for the heads-up.

    Firstly, we are not facing any issue while transmitting (at least in the initial tests, we are sending simple short AT-commands).
    It is the response from the Telit-module that is inconsistent (especially the output to AT+CGSN command, which should return a "long" 15-digit IMEI, but does not).

    Also, we intend to do everything in a Send->Receive->Send->Receive cycle (in a pseudo single-thread), so no multi-threading issues as such.

    Anyhow, thanks for the direction, let me see if I can find information about whether RTS/CTS is supported in the Telit-module.

    Thanks and Regards,
    Ajay

  • One more thing.

    IIRC, this micro, oddly, separates the receive timeout interrupt from the receive interrupt. If you don't respond to both in the same fashion you would also get your symptoms.

    Robert

    I say oddly since I have not been able to think of a practical case where they would be dealt with differently. That leaves the only effect of separating them as breaking interrupt serial code if you miss that unique implementation.
  • transmit would not show any RTS/CTS issues.

    Robert
  • Hi Robert.

    Great that Transmission is not likely to cause any issues (even if long strings are sent).

    So, Receive is the only pain remaining to be killed.

  • Maybe. Transmit could have other issues. Length of transmission is, at least, easy to verify.

    Robert
  • Hello Ajay,

    Did you try sending a deterministic set of bytes (16 and more) from the TX to the RX and evaluate the application performance. Then did you check the UART Status Register via the debugger to see if there are bytes in the FIFO. Nowhere I have seen a debug of the application or the underlying controller.

    Regards
    Amit
  • While 9600 baud is not "speed demon" - and "deterministic compliance" has received (some) mention - might a dialing down (perhaps to 1200 baud) serve to further highlight processing or system weakness? Debug will add insight - the two, together should yield increased understanding...
  • Hello cb1,

    My point here is that the Status Register should indicate if there is any data pending in the FIFO or not which has not crossed the threshold value.

    Regards
    Amit
  • Hi Amit,

    While that's true - to me - it avoids poster's "deterministic objective" - which better reveals via a slowed data transfer.

    Together - insights expand so that poster may better realize a solution...
  • I don't know if you have this option in the Telit-GSM, but we just solved a similar issue by always transmitting 16 extra null bytes of data at the end of a packet. That way we ensured that the packet always clears the FIFO regardless of how may bytes are in the packet. That way only the nulls get stuck in the FIFO, and they get stripped off the beginning of the next packet.

    If 16 bytes of data is too much overhead then you probably want to poll the UART instead of trying to use the FIFO interrupt. Use a timer 'interrupt' to run your polling routine at a rate of about 1.5x your character rate.
  • Hello John,

    Or enable the RTIM (Receive Time Out Interrupt) for the clear the RXFIFO of any unread byte.

    Regards
    Amit
  • Excellent! Thanks, Amit.
  • Amit, why on earth would you ever not enable the timeout interrupt? And for that matter why would you treat it differently from the receive interrupt?

    Robert
  • l don't think it avoids determinism cb1. It might change the pattern slightly but the processing time is still well known and bounded.

    Robert
  • Hello Robert,

    In the case for FIFO being enabled: The receive interrupt is based on RXFIFO threshold while timeout interrupt is based on the RXFIFO used being less than the threshold.
    In the case for FIFO not being enabled: The receive interrupt is based on the single byte hold buffer having data while timeout still is for the data not being read.

    The enabling of specific interrupt bits like Timeout (Parity, Overrun), etc is to be done by the application developer and it's handling enabled accordingly.

    Regards
    Amit
  • John, that would require that the telit echo the nulls and otherwise not react to them and also assumes they are not meaningful as a reply from the telit. In addition it assumes lossless transmission of nulls in both directions.

    Better just to get the receive written correctly. There is no reason the receive interrupt should miss characters except at high baud rates or if the processor disables interrupts for a significant period.

    Robert
  • Amit, I don't see that providing distinct functionality from the receive interrupt. Other UART families, I believe more than one family, combine them. As near as I can tell it's because there's no reason to separate them. It provides no extra functionality but it does make it much easier to fail.

    I was rather shocked to find the receive timeout was a distinct interrupt.

    Robert
  • Hello Robert

    Let me clarify: It is not a distinct interrupt vector, but one of the mapped interrupt bits that generated the UART interrupt. Handling of the UART TimeOut (TO) interrupt, requires that the user read the data considering the status flag and not just a for loop reading out a fixed number of bytes.

    Regards
    Amit
  • The caveat - if the transmitter may start sending the next packet before the receiver can check and clear the buffer (RTIM) then you can't clear the buffer and have so sort through it for valid data.
  • Hello John,

    Do you meant to say that if the RX is receiving a byte and the buffer is read by the CPU w/o having a valid data then the RT interrupt will not be asserted?

    Regards
    Amit
  • No. My caveat was to your Sep 4, 2015 5:10 PM post; kind of what Robert referred to at 5:33 PM. Sorry for the confusion.
  • Hi All.

    Here are the steps that solved the issue.
    If any of the following is not adhered to, bytes-reading behaves inconsistently.

    a)
    Set the baud rates for UartX (serial-logging), and UartY(reading from any external-module, like GSM-module) to be exactly same.

    b)
    In the interrupt-handler (which is async by definition), first read all bytes available in the current-cycle of "while(ROM_UARTCharsAvail(UARTY_BASE))", and only then proceed to logging it serially (via UartX) (if at all logging is necessary).

    c)
    Even for synchronous-reading for UART, do not log-to-serial-console every character read.


    Hope anyone else does not get stuck, in trying to figure out the correct, consistent way !!