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.

Using multiple UARTs simultaneously on EK TM4C123GXL board

Other Parts Discussed in Thread: EK-TM4C123GXL

Hello all,

I have a EK TM4C123GXL launchpad board.

I'm trying to enable several UARTs at once, preferably all f5 which I can access. I had the uart_echo program for UART0 which worked fine; then I tried modifying it for UART1 and it worked too.

But the thing is, i can't seem to configure multiple UART modules at once. If I write

IntEnable(INT_UART0);
 UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);

IntEnable(INT_UART1);
 UARTIntEnable(UART1_BASE, UART_INT_RX | UART_INT_RT);

the program gets stuck. Any one set of statements seem to work fine, i.e., if I enable interrupts for ONLY UART0 or UART1, it works fine. But both of them can't work at the same time.

Can someone please help me with what is going on and what to do , perhaps a detailed tutorial, or maybe even a multiple UART example?

Thanks a lot!!!

  • Hi Rituraj,

    Did you setup the interrupt handler for UART 1 at startup file?

    - kel
  • Hey kel,
    Yes, I did set the UART Handler for both UART0 and UART1 in the startup.ccs file. I replaced IntDefaultHandler with UARTIntHandler for both UART0 and UART1. But it gets stuck at the place where I enable both interrupts. Not if I enable either one.

    Another thing I wanted to ask: One of my friends said that I need to set the priorities for the interrupts if I need to use more than 1 UART. Is this true? Shouldn't declaring the interrupts take care of the whole situation? Thanks!

  • Hi,

    Post your startup.ccs interrupt vector table here for review. Also post your modified uart_echo code here for review.

    If you use UARTIntHandler for both UART0 and UART1, there seem to be a problem there. I have not done the same so I do not know what would be the effect of that.

    The usual practice to have a specific Interrupt Handler for that peripheral. Example UART0IntHandler for UART0 and UART1IntHandler for UART1.

    - kel
  • Hi kel,
    follwing is the code in uart_echo.c

    //*****************************************************************************
    //
    // uart_echo.c - Example for reading data from and writing data to the UART in
    // an interrupt driven fashion.
    //
    // Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
    // Software License Agreement
    //
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    //
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    //
    // This is part of revision 2.1.0.12573 of the EK-TM4C123GXL Firmware Package.
    //
    //*****************************************************************************
    #include <stdint.h>
    #include <stdbool.h>
    #include "hw_ints.h"
    #include "hw_memmap.h"
    #include "debug.h"
    #include "fpu.h"
    #include "gpio.h"
    #include "interrupt.h"
    #include "pin_map.h"
    #include "rom.h"
    #include "sysctl.h"
    #include "uart.h"
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>UART Echo (uart_echo)</h1>
    //!
    //! This example application utilizes the UART to echo text. The first UART
    //! (connected to the USB debug virtual serial port on the evaluation board)
    //! will be configured in 115,200 baud, 8-n-1 mode. All characters received on
    //! the UART are transmitted back to the UART.
    //
    //*****************************************************************************
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    //*****************************************************************************
    //
    // The UART interrupt handler.
    //
    //*****************************************************************************
    void
    UARTIntHandler(void)
    {
    uint32_t ui32Status;
    //
    // Get the interrrupt status.
    //
    ui32Status = ROM_UARTIntStatus(UART0_BASE, true);
    //
    // Clear the asserted interrupts.
    //
    ROM_UARTIntClear(UART0_BASE, ui32Status);
    //
    // Loop while there are characters in the receive FIFO.
    //
    while(ROM_UARTCharsAvail(UART0_BASE))
    {
    //
    // Read the next character from the UART and write it back to the UART.
    //
    ROM_UARTCharPutNonBlocking(UART0_BASE,
    ROM_UARTCharGetNonBlocking(UART0_BASE));
    //
    // Blink the LED to show a character transfer is occuring.
    //
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
    //
    // Delay for 1 millisecond. Each SysCtlDelay is about 3 clocks.
    //
    SysCtlDelay(SysCtlClockGet() / (1000 * 3));
    //
    // Turn off the LED
    //
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
    }
    }

    void
    UART1IntHandler(void)
    {
    uint32_t ui32Status;
    //
    // Get the interrrupt status.
    //
    ui32Status = ROM_UARTIntStatus(UART1_BASE, true);
    //
    // Clear the asserted interrupts.
    //
    ROM_UARTIntClear(UART1_BASE, ui32Status);
    //
    // Loop while there are characters in the receive FIFO.
    //
    while(ROM_UARTCharsAvail(UART1_BASE))
    {
    //
    // Read the next character from the UART and write it back to the UART.
    //
    ROM_UARTCharPutNonBlocking(UART1_BASE,
    ROM_UARTCharGetNonBlocking(UART1_BASE));
    //
    // Blink the LED to show a character transfer is occuring.
    //
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
    //
    // Delay for 1 millisecond. Each SysCtlDelay is about 3 clocks.
    //
    SysCtlDelay(SysCtlClockGet() / (1000 * 3));
    //
    // Turn off the LED
    //
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
    }
    }
    //*****************************************************************************
    //
    // Send a string to the UART.
    //
    //*****************************************************************************
    void
    UARTSend(const uint8_t *pui8Buffer, uint32_t ui32Count)
    {
    //
    // Loop while there are more characters to send.
    //
    while(ui32Count--)
    {
    //
    // Write the next character to the UART.
    //
    ROM_UARTCharPutNonBlocking(UART0_BASE, *pui8Buffer++);
    }
    }


    void
    UART1Send(const uint8_t *pui8Buffer, uint32_t ui32Count)
    {
    //
    // Loop while there are more characters to send.
    //
    while(ui32Count--)
    {
    //
    // Write the next character to the UART.
    //
    ROM_UARTCharPutNonBlocking(UART1_BASE, *pui8Buffer++);
    }
    }
    //*****************************************************************************
    //
    // This example demonstrates how to send a string of data to the UART.
    //
    //*****************************************************************************
    int
    main(void)
    {
    //
    // Enable lazy stacking for interrupt handlers. This allows floating-point
    // instructions to be used within interrupt handlers, but at the expense of
    // extra stack usage.
    //
    ROM_FPUEnable();
    ROM_FPULazyStackingEnable();
    //
    // Set the clocking to run directly from the crystal.
    //
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);
    //
    // Enable the GPIO port that is used for the on-board LED.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    //
    // Enable the GPIO pins for the LED (PF2).
    //
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
    //
    // Enable the peripherals used by this example.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    //
    // Enable processor interrupts.
    //
    ROM_IntMasterEnable();
    //
    // Set GPIO A0 and A1 as UART pins.
    //
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    GPIOPinConfigure(GPIO_PB0_U1RX);
    GPIOPinConfigure(GPIO_PB1_U1TX);
    ROM_GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    //
    // Configure the UART for 115,200, 8-N-1 operation.
    //
    ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), 115200,
    (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
    UART_CONFIG_PAR_NONE));

    ROM_UARTConfigSetExpClk(UART1_BASE, ROM_SysCtlClockGet(), 115200,
    (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
    UART_CONFIG_PAR_NONE));
    //
    // Enable the UART interrupt.
    //
    ROM_IntEnable(INT_UART0);
    ROM_UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);

    ROM_IntEnable(INT_UART1);
    ROM_UARTIntEnable(UART1_BASE, UART_INT_RX | UART_INT_RT);
    //
    // Prompt for text to be entered.
    //
    UARTSend((uint8_t *)"\033[2JEnter text: ", 16);
    UART1Send((uint8_t *)"\033[2JEnter text: ", 16);
    //
    // Loop forever echoing data through the UART.
    //
    while(1)
    {
    }
    }




    and my startup.ccs file:


    //*****************************************************************************
    // Forward declaration of the default fault handlers.
    //*****************************************************************************
    void ResetISR(void);
    static void NmiSR(void);
    static void FaultISR(void);
    static void IntDefaultHandler(void);

    //*****************************************************************************
    // External declaration for the reset handler that is to be called when the
    // processor is started
    //*****************************************************************************
    extern void _c_int00(void);

    //*****************************************************************************
    // Linker variable that marks the top of the stack.
    //*****************************************************************************
    extern unsigned long __STACK_TOP;

    //*****************************************************************************
    // External declaration for the interrupt handler used by the application.
    //*****************************************************************************
    extern void UARTIntHandler(void);
    extern void UART1IntHandler(void);

    //*****************************************************************************
    // The vector table. Note that the proper constructs must be placed on this to
    // ensure that it ends up at physical address 0x0000.0000 or at the start of
    // the program if located at a start address other than 0.
    //*****************************************************************************
    #pragma DATA_SECTION(g_pfnVectors, ".intvecs")
    void (* const g_pfnVectors[])(void) =
    {
    (void (*)(void))((unsigned long)&__STACK_TOP),
    // 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
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    IntDefaultHandler,// SVCall handler
    IntDefaultHandler,// Debug monitor handler
    0,// Reserved
    IntDefaultHandler,// The PendSV handler
    IntDefaultHandler,// The SysTick handler
    IntDefaultHandler,// GPIO Port A
    IntDefaultHandler,// GPIO Port B
    IntDefaultHandler,// GPIO Port C
    IntDefaultHandler,// GPIO Port D
    IntDefaultHandler,// GPIO Port E
    UARTIntHandler,// UART0 Rx and Tx
    UART1IntHandler,// UART1 Rx and Tx
    IntDefaultHandler,// SSI0 Rx and Tx
    IntDefaultHandler,// I2C0 Master and Slave
    IntDefaultHandler,// PWM Fault
    IntDefaultHandler,// PWM Generator 0
    IntDefaultHandler,// PWM Generator 1
    IntDefaultHandler,// PWM Generator 2
    IntDefaultHandler,// Quadrature Encoder 0
    IntDefaultHandler,// ADC Sequence 0
    IntDefaultHandler,// ADC Sequence 1
    IntDefaultHandler,// ADC Sequence 2
    IntDefaultHandler,// ADC Sequence 3
    IntDefaultHandler,// Watchdog timer
    IntDefaultHandler,// Timer 0 subtimer A
    IntDefaultHandler,// Timer 0 subtimer B
    IntDefaultHandler,// Timer 1 subtimer A
    IntDefaultHandler,// Timer 1 subtimer B
    IntDefaultHandler,// Timer 2 subtimer A
    IntDefaultHandler,// Timer 2 subtimer B
    IntDefaultHandler,// Analog Comparator 0
    IntDefaultHandler,// Analog Comparator 1
    IntDefaultHandler,// Analog Comparator 2
    IntDefaultHandler,// System Control (PLL, OSC, BO)
    IntDefaultHandler,// FLASH Control
    IntDefaultHandler,// GPIO Port F
    IntDefaultHandler,// GPIO Port G
    IntDefaultHandler,// GPIO Port H
    IntDefaultHandler,// UART2 Rx and Tx
    IntDefaultHandler,// SSI1 Rx and Tx
    IntDefaultHandler,// Timer 3 subtimer A
    IntDefaultHandler,// Timer 3 subtimer B
    IntDefaultHandler,// I2C1 Master and Slave
    IntDefaultHandler,// Quadrature Encoder 1
    IntDefaultHandler,// CAN0
    IntDefaultHandler,// CAN1
    IntDefaultHandler,// CAN2
    IntDefaultHandler,// Ethernet
    IntDefaultHandler,// Hibernate
    IntDefaultHandler,// USB0
    IntDefaultHandler,// PWM Generator 3
    IntDefaultHandler,// uDMA Software Transfer
    IntDefaultHandler,// uDMA Error
    IntDefaultHandler,// ADC1 Sequence 0
    IntDefaultHandler,// ADC1 Sequence 1
    IntDefaultHandler,// ADC1 Sequence 2
    IntDefaultHandler,// ADC1 Sequence 3
    IntDefaultHandler,// I2S0
    IntDefaultHandler,// External Bus Interface 0
    IntDefaultHandler,// GPIO Port J
    IntDefaultHandler,// GPIO Port K
    IntDefaultHandler,// GPIO Port L
    IntDefaultHandler,// SSI2 Rx and Tx
    IntDefaultHandler,// SSI3 Rx and Tx
    IntDefaultHandler,// UART3 Rx and Tx
    IntDefaultHandler,// UART4 Rx and Tx
    IntDefaultHandler,// UART5 Rx and Tx
    IntDefaultHandler,// UART6 Rx and Tx
    IntDefaultHandler,// UART7 Rx and Tx
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    IntDefaultHandler,// I2C2 Master and Slave
    IntDefaultHandler,// I2C3 Master and Slave
    IntDefaultHandler,// Timer 4 subtimer A
    IntDefaultHandler,// Timer 4 subtimer B
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    0,// Reserved
    IntDefaultHandler,// Timer 5 subtimer A
    IntDefaultHandler,// Timer 5 subtimer B
    IntDefaultHandler,// Wide Timer 0 subtimer A
    IntDefaultHandler,// Wide Timer 0 subtimer B
    IntDefaultHandler,// Wide Timer 1 subtimer A
    IntDefaultHandler,// Wide Timer 1 subtimer B
    IntDefaultHandler,// Wide Timer 2 subtimer A
    IntDefaultHandler,// Wide Timer 2 subtimer B
    IntDefaultHandler,// Wide Timer 3 subtimer A
    IntDefaultHandler,// Wide Timer 3 subtimer B
    IntDefaultHandler,// Wide Timer 4 subtimer A
    IntDefaultHandler,// Wide Timer 4 subtimer B
    IntDefaultHandler,// Wide Timer 5 subtimer A
    IntDefaultHandler,// Wide Timer 5 subtimer B
    IntDefaultHandler,// FPU
    IntDefaultHandler,// PECI 0
    IntDefaultHandler,// LPC 0
    IntDefaultHandler,// I2C4 Master and Slave
    IntDefaultHandler,// I2C5 Master and Slave
    IntDefaultHandler,// GPIO Port M
    IntDefaultHandler,// GPIO Port N
    IntDefaultHandler,// Quadrature Encoder 2
    IntDefaultHandler,// Fan 0
    0,// Reserved
    IntDefaultHandler,// GPIO Port P (Summary or P0)
    IntDefaultHandler,// GPIO Port P1
    IntDefaultHandler,// GPIO Port P2
    IntDefaultHandler,// GPIO Port P3
    IntDefaultHandler,// GPIO Port P4
    IntDefaultHandler,// GPIO Port P5
    IntDefaultHandler,// GPIO Port P6
    IntDefaultHandler,// GPIO Port P7
    IntDefaultHandler,// GPIO Port Q (Summary or Q0)
    IntDefaultHandler,// GPIO Port Q1
    IntDefaultHandler,// GPIO Port Q2
    IntDefaultHandler,// GPIO Port Q3
    IntDefaultHandler,// GPIO Port Q4
    IntDefaultHandler,// GPIO Port Q5
    IntDefaultHandler,// GPIO Port Q6
    IntDefaultHandler,// GPIO Port Q7
    IntDefaultHandler,// GPIO Port R
    IntDefaultHandler,// GPIO Port S
    IntDefaultHandler,// PWM 1 Generator 0
    IntDefaultHandler,// PWM 1 Generator 1
    IntDefaultHandler,// PWM 1 Generator 2
    IntDefaultHandler,// PWM 1 Generator 3
    IntDefaultHandler// PWM 1 Fault
    };

    //*****************************************************************************
    //
    // This is the code that gets called when the processor first starts execution
    // following a reset event. Only the absolutely necessary set is performed,
    // after which the application supplied entry() routine is called. Any fancy
    // actions (such as making decisions based on the reset cause register, and
    // resetting the bits in that register) are left solely in the hands of the
    // application.
    //
    //*****************************************************************************
    void ResetISR(void) {
    // Jump to the CCS C initialization routine. This will enable the
    // floating-point unit as well, so that does not need to be done here.
    __asm(" .global _c_int00\n"
    " b.w _c_int00");
    }

    //*****************************************************************************
    //
    // This is the code that gets called when the processor receives a NMI. This
    // simply enters an infinite loop, preserving the system state for examination
    // by a debugger.
    //
    //*****************************************************************************
    static void NmiSR(void) {
    // Enter an infinite loop.
    while (1) {
    }
    }

    //*****************************************************************************
    //
    // This is the code that gets called when the processor receives a fault
    // interrupt. This simply enters an infinite loop, preserving the system state
    // for examination by a debugger.
    //
    //*****************************************************************************
    static void FaultISR(void) {
    // Enter an infinite loop.
    while (1) {
    }
    }

    //*****************************************************************************
    //
    // This is the code that gets called when the processor receives an unexpected
    // interrupt. This simply enters an infinite loop, preserving the system state
    // for examination by a debugger.
    //
    //*****************************************************************************
    static void IntDefaultHandler(void) {
    // Go into an infinite loop.
    while (1) {
    }
    }



    In a nutshell,
    1. I Replaced IntDefaultHandler with UARTIntHandler for UART0 and UART1IntHandler for UART1, and
    2. defined the UART1IntHandler in uart_echo.c.

    3. defined UART1Send