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.

EK-TM4C1294XL: How to use UART5 interruptions properly?

Part Number: EK-TM4C1294XL

Hi, I'm trying to use the UART5 receive interruption with my tm4c1294xl launchpad board but I'm getting stuck because the ISR is not being called, bellow is my code

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/gpio.h"

/*variable to keep system clock*/
uint32_t g_ui32SysClock;

void init_serial(uint32_t system_clock, void (*pfnHandler) (void)){

    /*Enabling Peripherals*/
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART5);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);

    /*Setting Up pins*/
    GPIOPinConfigure(GPIO_PC6_U5RX);
    GPIOPinConfigure(GPIO_PC7_U5TX);
    GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_6 | GPIO_PIN_7);

    /*UART Configurations*/
    UARTConfigSetExpClk(UART5_BASE,system_clock,115200,
        (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));

    /*Enable uart interruptions*/
    IntEnable(INT_UART5);
    UARTIntEnable(UART5_BASE, (UART_INT_RX | UART_INT_RT));
    /*Registering UART isr*/
    IntRegister(INT_UART5, pfnHandler);

}

/*ISR for uart5 receive or receive timeout interruption */
void UARTIntHandler(void)
{
    uint32_t ui32Status;

    //
    // Get the interrrupt status.
    //
    ui32Status = UARTIntStatus(UART5_BASE, true);

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

    //
    // Loop while there are characters in the receive FIFO.
    //
    while(UARTCharsAvail(UART5_BASE))
    {
        //
        // Read the next character from the UART and write it back to the UART.
        //
        UARTCharPutNonBlocking(UART5_BASE, UARTCharGetNonBlocking(UART5_BASE));

        //
        // Blink the LED to show a character transfer is occuring.
        //
        GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, GPIO_PIN_0);

        //
        // Delay for 1 millisecond.  Each SysCtlDelay is about 3 clocks.
        //
        SysCtlDelay(g_ui32SysClock / (1000 * 3));

        //
        // Turn off the LED
        //
        GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0);
    }
}


int main(void){

    /* Set the clocking to run at 120MHz */
    g_ui32SysClock= SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                        SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                        SYSCTL_CFG_VCO_480), 120000000);
    /*Start string*/
    uint8_t *cThisChar = "Starting...";

    /*Onboard led just for verifications*/
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0);
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0x00);

    /*Enabling processor interrupts*/
    IntMasterEnable();

    /*serial configurations*/
    init_serial(g_ui32SysClock, UARTIntHandler);
    /*Sending initial string*/
    while(*cThisChar != '\0'){
        UARTCharPutNonBlocking(UART5_BASE, *cThisChar++);
    }

    while(1){
        /*Wait interruptions*/
    }
    /*no errors*/
    return 0;
}

Code is compling with no errors but when I send something to the board the receive interruption is not triggered.

  • I did not see a problem in the code. (But watchout using the function UARTCharPutNonBlocking() in main. If you string is longer than the FIFO is deep, 16 characters, some of your string will not be output. Calling UARTCharPut() will avoid that issue.)

    Are you getting the characters from your transmit of "Starting..."? Have you checked your hardware interface to make sure your receive characters are getting to the PC6 pin?
  • Bob Crosby said:
    If your string is longer than the FIFO is deep (16 characters) - some of your string will not be output.

    Bob - this, "Loss of Characters received" - beyond the initial 16 (FIFO size) - has been reported here multiple times.     I believe your response is the first  to, 'recognize & confirm' this behavior.   (Good that!)

    You note that 'UARTCharPut()' avoids this limitation - but its 'blocking' (all {at least most} other) program flow - may not be acceptable.      Thus - can 'anything' be done (perhaps to properly & quickly 'unload the FIFO' )- so that the 'Non-Blocking' function may be used - to receive character strings beyond those 16 characters?    (i.e. without forcing the source transmitter to confine its data packets to 16 bytes or less)    Do note that 'other' ARM MCUs have achieved this.   (>16 char capability - without blocking program flow - both during receive & transmit...)

    As always - thanks your time & attention...

  • Jamelly Ferreira said:
    /*Registering UART isr*/ IntRegister(INT_UART5, pfnHandler);

    and then follow that with:

    Jamelly Ferreira said:
    /*ISR for uart5 receive or receive timeout interruption */ void UARTIntHandler(void)

    Do note that the 2 'function names in highlight ... do NOT match!       Is that wise - and/or correct?

    Firm/I do not employ, 'Registering Interrupts' - instead we name & then place the Interrupt appropriately - w/in the project's 'Start-Up file.'       And then 'insure' - that the (exact same) interrupt name - appears w/in our code.

    I note also that there is 'no mention' of (any) physical connection - which ties UART5's TX pin to UART5's RX pin.     Minus that connection - how is UART 5's RX Interrupt (once properly named/matched) expected to note  UART5's TX transmission?      (assuming that is your expectation...)

    I would note as well - that (most) of the ARM MCU UARTs we've employed - REQUIRE that their UART RX pin be 'pulled-up' (either by a simple resistor or line-driver IC) - so that the UART's RX receiver has a, 'KNOWN/VALID LOGIC LEVEL'  - at all times - and IS NOT ALLOWED to Float!      (there is no mention of your treatment of UART5's RX pin.)

  • Hey, Bob. First of all thanks for advising about UARTCharPutNonBlocking, I fixed this by using the blocking version UARTCharPut . Yes, I'm receiving the characters in the PC6 pin, I checked that by using an oscilloscope and all seems to be correct but still no interruption is triggered.
  • cb1_mobile said:
    Jamelly Ferreira
    /*Registering UART isr*/ IntRegister(INT_UART5, pfnHandler);

    and then follow that with:

    Jamelly Ferreira
    /*ISR for uart5 receive or receive timeout interruption */ void UARTIntHandler(void)

    Do note that the 2 'function names in highlight ... do NOT match!       Is that wise - and/or correct?

    The first piece of code is part of the declaration+structure of the init_serial function, this function receives two parametters : An uint32_t and a function pointer.

    The second one is the declaration+structure of the function that I'll pass to init_serial in the main function. So, the differences in the function names are acceptable in terms of C language

    cb1_mobile said:

    I note also that there is 'no mention' of (any) physical connection - which ties UART5's TX pin to UART5's RX pin.     Minus that connection - how is UART 5's RX Interrupt (once properly named/matched) expected to note  UART5's TX transmission?      (assuming that is your expectation...)

    I would note as well - that (most) of the ARM MCU UARTs we've employed - REQUIRE that their UART RX pin be 'pulled-up' (either by a simple resistor or line-driver IC) - so that the UART's RX receiver has a, 'KNOWN/VALID LOGIC LEVEL'  - at all times - and IS NOT ALLOWED to Float!      (there is no mention of your treatment of UART5's RX pin.)

    I did not mention how I expect to get the characters in the receive FIFO(I'm really sorry for that). I'm using an usb to serial converter to send characters from my PC running a python code and also I don't intend to link the TX line of MCU of its RX line(the 'starting...' string is just to know if the MCU is sending correctly characters). About the resistor in the RX pin, is it necessary if I'm using usb to serial adapter?


    cb1_mobile said:

    Firm/I do not employ, 'Registering Interrupts' - instead we name & then place the Interrupt appropriately - w/in the project's 'Start-Up file.'       And then 'insure' - that the (exact same) interrupt name - appears w/in our code.

    I don't know how to use the project start-up file, because I always registered interrupts by code(Like in timers). Can you explain(or send some link of) how to use this file?

  • I don't know how to use the project start-up file, because I always registered interrupts by code(Like in timers). Can you explain(or send some link of) how to use this file?

    Yes & yes - but must wait till later this afternoon. Thanks for your explanation of (other) issues.

    It is 'usual' for the 'USB <-> TTL/CMOS' converter to produce that 'logic high, idle signal.' Yet surely - you can easily measure - and confirm! (such measurement - ALWAYS trumps, 'hope/prayer.')
  • Jamelly Ferreira said:
    I did not mention how I expect to get the characters in the receive FIFO(I'm really sorry for that). I'm using an usb to serial converter to send characters from my PC running a python code and also I don't intend to link the TX line of MCU of its RX line(the 'starting...' string is just to know if the MCU is sending correctly characters). About the resistor in the RX pin, is it necessary if I'm using usb to serial adapter?

    The USB to serial cables I am used to usually generate RS232 level signals. Are you sure you have 3.3V level signals at PC6? The idle or high state should be 3V and the low state, such as the start bit should be near ground.

    https://www.sparkfun.com/tutorials/215

  • To Bob & originating poster,

    There are (both) styles of  USB to UART adaptors & cables - although we find the USB <-> TTL/CMOS to be 'far more' prevalent.     (as the world has moved pretty far - away from RS232 - and towards USB.)    As always ... ALWAYS MEASURE - before connecting ANYTHING to your MCU!

    Now to our poster - here is the key portion of the Start Up file (this under IAR's IDE) yet the method is almost identical for your (single vendor version)

    First - all of the ISRs must be grouped & identified - as shown here.

    //  External declarations for the interrupt handlers used by the application.

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

    extern void IntDefaultHandler(void);

    extern void ADC0IntHandler(void);          //  Normal pgm opn.

    extern void ADC0SS0Handler(void);        //  Blinky_basicON.c tests

    extern void GPIOBIntHandler(void);       //  Hall-Sense

    extern void CANIntHandler(void);

    extern void FaultISR(void);

    extern void NmiSR(void);

    extern void PWM0IntHandler(void);        // PWM Generator

    // extern void MainWaveformTick(void);

    extern void MainMillisecondTick(void);   // multiple funct

    // extern void QEIIntHandler(void);

    extern void SysTickIntHandler(void);     // Switch, Spd Pot    

    // extern void WTimer0AIntHandler(void);    // Integ. Sat (4 Sec)

    extern void WTimer5BIntHandler(void);    // Stall Detect (2 Sec)

    extern void Timer1BIntHandler(void);     // TAK 500uS

    extern void Timer3AIntHandler(void);     // Program Time Base

    extern void WatchdogIntHandler(void);

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

    Then - below that yet still w/in the Start Up file:

    // The vector table.  Note that the proper constructs must be placed on this to

    // ensure that it ends up at physical address 0x0000.0000.

    //

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

    __root const uVectorEntry __vector_table[] @ ".intvec" =

    {

       { .ulPtr = (unsigned long)pulStack + sizeof(pulStack) },

                                               // The initial stack pointer

       ResetISR,                               // The reset handler

       NmiSR,                                  // The NMI handler

       FaultISR,                               // The hard fault handler

       IntDefaultHandler,                      // The MPU fault handler

       IntDefaultHandler,                      // The bus fault handler

       IntDefaultHandler,                      // The usage fault handler

      .

      .

    IntDefaultHandler,                      // I2C0 Master and Slave

       IntDefaultHandler,                      // PWM Fault   ***

       PWM0IntHandler,                         // PWM Generator 0        Note how this ISR's name MATCHES that used (above)

       IntDefaultHandler,                      // PWM Generator 1

       MainMillisecondTick,                    // PWM Generator 2      Again - there is a name match

       IntDefaultHandler,                      // Quadrature Encoder 0

       ADC0IntHandler,                         // ADC Sequence 0          And here is the 3rd match

       IntDefaultHandler,                      // ADC Sequence 1

       IntDefaultHandler,                      // ADC Sequence 2

       IntDefaultHandler,                      // ADC Sequence 3

       WatchdogIntHandler,                     // Watchdog timer

    ****************************

    Now those exact same ISR names are deployed w/in our code (outside of this Start Up File.)    It is vital that there exist THREE NAME MATCHES - 2 (as I've detailed here - w/in the Start Up) and the 3rd -w/in your program code.

    All clear, now?     We find this ' embedding w/in the Start Up file far more robust - and easier to test/debug - than the (far more cumbersome/error-prone 'Registering of Interrupts.'

  • Yes, I'm using 3.3V and 0V as high and low levels, respectively
  • Kudos CB1. Well done. Thank you. (#LIKE)
  • Jamelly,

    Now that CB1 has done the hard part and narrowed down the issue, if you are interested there is a description between using static or dynamic interrupt registration in section 17.1 of the Driver Library User's Guide. I , like CB1, prefer using static interrupt registration as it is slightly more efficient. I suspect that the reason why dynamic registration did not work for you was because of the linker command file. (Just a guess, we can pursue that if you are interested.) I was in the middle of trying to recreate your issue, but was using my own linker command file. I would not have been able to figure it out. CB1 has saved me a lot of effort. This forum has some of the best members for helping other members.
  • Thank you as well Bob - especially so for your 'monumental clarity' - as to the handling of 2 (or more) buffers - when the µDMA is 'unleashed' and (near) simultaneous ADC values are to be managed & processed...

    Rather than sending client users to 'Sparkfun' (which we find to be practicing 'high mark-up') we find FTDI to offer, 'Far more complete a USB - based product line - and at more competitive costs. (as FTDI - is the TRUE Source...)
  • Bob Crosby said:
    CB1 has saved me a lot of effort. This forum has some of the best members for helping other members.

    If my (bit) aged heart - will 'STILL' (at least somewhat) I'd note that, 'Check #2 is 'In the Mail.'      Not ONE - but two very kind, thoughtful 'recognitions' - land w/in the same day - w/in hours!     (the failed Encoder poster - induced yet another forum user - to write (very) kindly.)  

    Thank you, Bob - for such kind remarks - and glad that you found that quick summary of, 'Start-Up File Based - ISR Management - useful.'     (indeed - that's the ONLY format we use - some key clients (demand) that!)  

    Having to 'honor TWO checks' w/in the same day - may cost me my (planned) high-seas adventure - as we depart 'MDR' * (Marina of Kings) under sail...  (that superb - well protected harbor - courtesy of the US Army, Corps of Engineers!)

    *  MDR = Marina del Rey, Los Angeles (beautiful pleasure-boat harbor & seaside community.     Harbor protected by a multi-mile, past engineered 'Sea-Wall' - which reduces 'typhoon waves' to barely one foot...