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.

Compiler/TM4C129CNCPDT: UART0 RX Interrupt issue

Part Number: TM4C129CNCPDT
Other Parts Discussed in Thread: EK-TM4C129EXL

Tool/software: TI C/C++ Compiler

Hello Gurus,

I am trying to implement UART0 RX interrupt and can not implement yet. The code compiles successfully without any error. However I am facing two weird problems i.e;

  1. It doesnt capture any interrupt till I send the 8th character. As it receives the 8th character it services the interrupt handler ISR and returns back sucessfully
  2. It services the interrupt only once and never interrupts again no matter how many charter I send.

I have registered the interrupt handler in startup_css.c file already and declared as well.

//*****************************************************************************
//
// External declarations for the interrupt handlers used by the application.
//
//*****************************************************************************
extern void xPortPendSVHandler(void);
extern void vPortSVCHandler(void);
extern void xPortSysTickHandler(void);

extern void UART0ISR(void);


//*****************************************************************************

AND
  IntDefaultHandler,                      // GPIO Port B
    IntDefaultHandler,                      // GPIO Port C
    IntDefaultHandler,                      // GPIO Port D
    IntDefaultHandler,                      // GPIO Port E
    UART0ISR,                      // UART0 Rx and Tx
    IntDefaultHandler,                      // UART1 Rx and Tx
    IntDefaultHandler,                      // SSI0 Rx and Tx
    IntDefaultHandler,                      // I2C0 Master and Slave

My main.c;

#include <stdint.h>
#include <stdbool.h>
#include "main.h"
#include "drivers/pinout.h"
#include "utils/uartstdio.h"


// TivaWare includes
#include "driverlib/sysctl.h"
#include "driverlib/debug.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/gpio.h"
#include "inc/hw_memmap.h"
#include "driverlib/pin_map.h"
#include "driverlib/uart.h"
#include "inc/hw_ints.h"
#include "driverlib/interrupt.h"

// FreeRTOS includes
#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"


// Tasks declarations
void LED1Task(void *pvParameters);
void LED2Task(void *pvParameters);
void LED3Task(void *pvParameters);
void LED4Task(void *pvParameters);
void SerialTask1(void *pvParameters);
void SerialTask2(void *pvParameters);
void UART0ISR(void);

// Main function
int main(void)
{
    // Initialize system clock to 120 MHz
    uint32_t output_clock_rate_hz;
    output_clock_rate_hz = ROM_SysCtlClockFreqSet(
                               (SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN |
                                SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480),
                               SYSTEM_CLOCK);
    ASSERT(output_clock_rate_hz == SYSTEM_CLOCK);

    // Initialize the GPIO pins for the Launchpad
    PinoutSet(false, false);

    // Set up the UART which is connected to the virtual COM port
    //UARTStdioInit(0);
    //UARTStdioConfig(0, 115200, SYSTEM_CLOCK);

    /////////////////////////////////////////////////////////////////////////////

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //UARTConfigSetExpClk(UART0_BASE, output_clock_rate_hz, 115200,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));


    UARTIntEnable(UART0_BASE, UART_INT_RX); //only enable RX interrupts
    //IntRegister(INT_UART0, UART0ISR);

    IntEnable(INT_UART0); //enable the UART interrupt
    IntMasterEnable(); //enable processor interrupts

    UARTStdioConfig(0, 115200, SYSTEM_CLOCK);
    ////////////////////////////////////////////////////////////////////////////

    // Create demo tasks
    xTaskCreate(LED1Task, (const portCHAR *)"LED1",
                configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    //xTaskCreate(demoLED2Task, (const portCHAR *)"LED2",
                //configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    xTaskCreate(LED3Task, (const portCHAR *)"LED3",
                configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    //xTaskCreate(LED4Task, (const portCHAR *)"LED4",
                //configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    xTaskCreate(SerialTask1, (const portCHAR *)"SerialTask1",
                configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    xTaskCreate(SerialTask2, (const portCHAR *)"SerialTask2",
                configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    vTaskStartScheduler();

    /// Scheduler should NEVER reach here///
    while(1)
    {
        //UARTprintf("Scheduler Error..!\n\r");
        GPIOPinWrite(CLP_D1_PORT, CLP_D1_PIN, CLP_D1_PIN);
        GPIOPinWrite(CLP_D2_PORT, CLP_D2_PIN, CLP_D2_PIN);
        GPIOPinWrite(CLP_D3_PORT, CLP_D3_PIN, CLP_D3_PIN);
        GPIOPinWrite(CLP_D4_PORT, CLP_D4_PIN, CLP_D4_PIN);
        return 0;
    }



}

and the UART0 handler defination;

void UART0ISR(void)
{
    UARTIntClear(UART0_BASE, UART_INT_RX);
    UARTprintf("UART0ISR called..!\n\r");
}

I am stuck and not able to identify the issue.

Any help/hint will be appreciable.

Thank you all.

  • Please Note the first two codes are from startup_css.c and the laste two codes are from main.c.
    I am using EK-TM4C129EXL launchpad and CCS version 7.4
  • Sahil said:
    It doesnt capture any interrupt till I send the 8th character. As it receives the 8th character it services the interrupt handler ISR and returns back sucessfully

    Inside the UARTStdioConfig() function there is the following conditionally compiled code:

    #ifdef UART_BUFFERED
        //
        // Set the UART to interrupt whenever the TX FIFO is almost empty or
        // when any character is received.
        //
        MAP_UARTFIFOLevelSet(g_ui32Base, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
    
        //
        // Flush both the buffers.
        //
        UARTFlushRx();
        UARTFlushTx(true);
    
        //
        // Remember which interrupt we are dealing with.
        //
        g_ui32PortNum = ui32PortNum;
    
        //
        // We are configured for buffered output so enable the master interrupt
        // for this UART and the receive interrupts.  We don't actually enable the
        // transmit interrupt in the UART itself until some data has been placed
        // in the transmit buffer.
        //
        MAP_UARTIntDisable(g_ui32Base, 0xFFFFFFFF);
        MAP_UARTIntEnable(g_ui32Base, UART_INT_RX | UART_INT_RT);
        MAP_IntEnable(g_ui32UARTInt[ui32PortNum]);
    #endif

    In your main function the call to UARTConfigSetExpClk() is commented out, and instead UARTStdioConfig() is being called to configure UART0. If UART_BUFFERED is defined when the Tivaware uartstudio.c utility which contains UARTConfigSetExpClk() is compiled, then UARTConfigSetExpClk() will enable the UART FIFO to only interrupt once 8 characters have been received, which could explain your first problem. Not sure if that also explains the second problem.

  • Hi
    Thank you for your reply.

    The problem is if I comment out UARTStudionConfig () and instead use UARTConfigSetExpClk(). I can no more use UARTprintf() as it hangs. So I had to use it unless you can suggest an alternative?
  • Chester Gillon said:
    In your main function the call to UARTConfigSetExpClk() is commented out, and instead UARTStdioConfig() is being called to configure UART0. If UART_BUFFERED is defined when the Tivaware uartstudio.c utility which contains UARTConfigSetExpClk() is compiled, then UARTConfigSetExpClk() will enable the UART FIFO to only interrupt once 8 characters have been received

    Oops, I didn't read the code in the UARTConfigSetExpClk() function correctly which means my previous suggestion is wrong. On further inspection:

    a) When compiled with UART_BUFFERED defined, UARTConfigSetExpClk() enables the RX/TX FIFOs (via a call to MAP_UARTEnable) and sets the UART to interrupt when any character is received (via a call to MAP_UARTFIFOLevelSet).

    b) When compiled with UART_BUFFERED NOT defined,UARTConfigSetExpClk() enables the RX/TX FIFOs (via a call to MAP_UARTEnable) but leaves the RXIFLSEL field in the UART Interrupt FIFO Level Select (UARTIFLS) register at its default value which means a receive interrupt will only be asserted when the RX FIFO is >= 1/2 full (i.e. after 8 characters have been received).

    Sahil said:
    However I am facing two weird problems i.e;
    1. It doesnt capture any interrupt till I send the 8th character. As it receives the 8th character it services the interrupt handler ISR and returns back sucessfully
    2. It services the interrupt only once and never interrupts again no matter how many charter I send.

    I think the first problem is explained by b) above. In which case try adding the following to your main function before the call to UARTConfigSetExpClk():

        //
        // Set the UART to interrupt whenever the TX FIFO is almost empty or
        // when any character is received.
        //
        MAP_UARTFIFOLevelSet(g_ui32Base, UART_FIFO_TX1_8, UART_FIFO_RX1_8);

    I think the second problem is because the UART0ISR() interrupt handler doesn't read any receive characters. The data sheet description of the UARTIFLS register contains:

    The interrupts are generated based on a transition through a level rather than being based on the level. That is, the interrupts are generated when the fill level progresses through the trigger level. For example, if the receive trigger level is set to the half-way mark, the interrupt is triggered as the module is receiving the 9th character.

    Therefore, if no receive characters are read from the receive FIFO then don't think the receive interrupt will ever be re-raised.

  • Chester Gillon said:
    The interrupts are generated based on a transition through a level rather than being based on the level. That is, the interrupts are generated when the fill level progresses through the trigger level. For example, if the receive trigger level is set to the half-way mark, the interrupt is triggered as the module is receiving the 9th character.

  • Hi,

    Just tried what you mentioned by adding the line before UARTStdioConfig() as follows;
    What happens is it calls the handler after i send two characters and never calls again any more.

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //UARTConfigSetExpClk(UART0_BASE, output_clock_rate_hz, 115200,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
    UARTEnable(UART0_BASE);

    UARTIntEnable(UART0_BASE, UART_INT_RX); //only enable RX interrupts
    //IntRegister(INT_UART0, UART0ISR);

    IntEnable(INT_UART0); //enable the UART interrupt
    IntMasterEnable(); //enable processor interrupts

    MAP_UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);

    UARTStdioConfig(0, 115200, SYSTEM_CLOCK);
  • Sahil said:
    What happens is it calls the handler after i send two characters and never calls again any more.

    As mentioned above, does the handler read any receive characters from the UART?

  • Hi,

    The handler clears the interrupt flag but doesnt read the buffer itself.

    Do you think it should read the buffer i.e. copying it to another buffer or please tell me how to accomplish that?

    Thanks

  • Here is the handler code for UART0 ISR.

    void UART0_ISR(void) { UARTprintf("UART0_ISR called..!\n\r"); //UARTCharPut(UART0_BASE, 't'); delay_clocks(20000); UARTIntClear(UART0_BASE,UART_INT_RX); }

    Please clarify what do you mean by reading the buffer as I dont undterstand how will it then clears the interrupt OR please share how to accomplish it.

    Thanks

  • Have you read the microprocessor or TIVAWare user manuals yet? I would suggest at least a quick review of the pertinent sections in both.

    You could also check the #bookshelf tag. I believe there is a reference to a book on serial communications there.

    Robert
  • Hello Robert,

    Thank you for your suggestion.

    I changed the handler such that it reads the buffer and it worked.

    Now the handler gets called each time I send a character, however the only problem is at startup, as I reset the processor, the first time i have to send two characters to get the handler called.

    void UART0ISR(void)
    {
    
        UARTCharGetNonBlocking(UART0_BASE);
        UARTIntClear(UART0_BASE, UART_INT_RX);
        UARTprintf("UART0ISR called..!\n\r");
        delay_clocks(900000);
    
        //UARTsendString("UART0ISR called..!\n\r");
    }

  • So i tried to see which character triggers the handler and it turned out that the handler is called on the previous character. 

    The code is;

    void UART0ISR(void)
    {
    
        UARTprintf("\n%c\n",UARTCharGetNonBlocking(UART0_BASE));
        UARTIntClear(UART0_BASE, UART_INT_RX);
        UARTprintf("UART0ISR called..!\n\r");
        delay_clocks(900000);
    
        //UARTsendString("UART0ISR called..!\n\r");
    }

    for example if I press "a" and then "b" and then "c" 

    On pressing "b" the handler (above) will print the previous character "a", and pressing "c", it prints the previous character "b" and so on...

     

    Please keep in mind I reading the buffer at the initialization time so to remove if there is any character etc. As shown in the following;

        UARTEnable(UART0_BASE);
    
        UARTIntEnable(UART0_BASE, UART_INT_RX); //only enable RX interrupts
        IntRegister(INT_UART0, UART0ISR);
    
        IntEnable(INT_UART0); //enable the UART interrupt
        IntMasterEnable(); //enable processor interrupts
    
        MAP_UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
    
        UARTStdioConfig(0, 115200, SYSTEM_CLOCK);
        delay_clocks(2);
        UARTCharGetNonBlocking(UART0_BASE);

    Looks like the it acknowledges buffer is flow and serves the ISR ONLY when called the next time ??

  • Sahil said:

    So i tried to see which character triggers the handler and it turned out that the handler is called on the previous character. 

    The code is;

    void UART0ISR(void)
    {
    
        UARTprintf("\n%c\n",UARTCharGetNonBlocking(UART0_BASE));
        UARTIntClear(UART0_BASE, UART_INT_RX);
        UARTprintf("UART0ISR called..!\n\r");
        delay_clocks(900000);
    
        //UARTsendString("UART0ISR called..!\n\r");
    }

    for example if I press "a" and then "b" and then "c" 

    On pressing "b" the handler (above) will print the previous character "a", and pressing "c", it prints the previous character "b" and so on...

    You are misinterpreting what you are seeing.

    The interrupt occurs when the FIFO threshold is crossed. In your case when b is pressed. At that point there are two characters in the FIFO to be read (you should read until the FIFO is empty).

    You are also probably not monitoring both the receive interrupts. There is the FIFO interrupt which you are responding to. In addition you should turn on the receive time out interrupt (RTI I think). This will provide an interrupt when a character has been received into the FIFO but the FIFO has not filled past the threshold and no further character has been received within a time period. You should treat both sources in exactly the same fashion: read the FIFO until it is empty.

    Robert

    One final note: those prints and delay in the ISR are a very bad idea.

  • Agree to your final note, the delay and prints are only at the time of code development to make it working... Later I want to use the handler only to capture the received byte and store it in my own defined string array buffer for further manipulation. However I can do so only once I make the code working.

    Isnt there a way that I get interrupt only when i receive one byte. I would rather avoid the time out idea unless that is the only way to make it work ?

    Thanks
  • Hello Robert,

    UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT); //only enable RX FIFO and RX TimeOut interrupts

    Added the above modification as you suggested. It is working fine now. You can ignore the previous silly question as well :P

    Thank you for your help.

    Thank you all for your time and assistance.

  • The previous question isn't silly, just missing a point about the FIFO. If you disable the FIFO then there is no buffering and every received character will generate an interrupt.

    The reason FIFOs are added is two fold, first to reduce the number of interrupts (and associated overhead) and second to increase the amount of CPU time you have before you have a character overrun if you don't respond to an interrupt.

    Robert
  • Yes It is very useful feature so to reduce the cpu interruption frequency this way. I may implement to make use of it later.
    Thank you, wishing you a happy year...
  • May it be noted that "Robert's post" of "2:49 today" is the one which, "Resolved your issue?"

    His writing - now quoted, "You are also probably not monitoring both the receive interrupts," clearly  led to your success!      Alas - Robert's guiding post "sits unawarded"  - while your post -  simply following Robert's direction - is the one awarded, "This post resolved."     (which it clearly - did not - it was "derivative" at best...)

    It is quite easy for you to award the (proper) "This post Resolved" to Robert's post - as identified herein.     (your "self-award" will remain - once "granted" - those "awards" cannot be negated...)