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.

Tiva C ek-tm4c123gxl - UART0 echo

Other Parts Discussed in Thread: EK-TM4C123GXL

Hello everybody, I'm trying to write a simple UART echo for a Tiva C ek-tm4c123gxl. I'm not using any code from the ROM memory because I want to take care of everything and learn as much as possible in the process.

I'm developing on linux, using gcc as compiler, GNU ld for linking and gdb for debugging (I can provide more details if needed). The provided uart_echo example, built with the same toolchain, works like a charm.

Reading the data sheet I've written the source code attached in this post (there's no initialization code. As far as I know, that code is fine, but I can upload it if requested). I'm expecting the microcontroller to:

  1. write "hello UART\r\n" to UART0 - this works perfectly
  2. raise an interrupt upon receiving a character from UART0
  3. execute the UART0_handler interrupt handler, read the character from the UART0 data register (no FIFO) and write it back to UART0

Regarding points 2. and 3., I can see that the UART0_handler function address is loaded at the right offset in the microcontroller flash memory (offset 0x54), but the interrupt handler is not executed when writing a character in minicom (the pc-side serial communication program that I'm using), so I guess that no interrupt is fired.

I'm sure there's something wrong with my code, but I can't really tell what's missing. Can anybody help me with this?

/*
 * Simple echo on UART0
 */
#include <stdint.h>
#include <stdbool.h>

#define SYSCTRL_GPIOHBCTL           (*((volatile uint32_t *) 0x400FE06CU))
#define SYSCTRL_RCGCGPIO            (*((volatile uint32_t *) 0x400FE608U))
#define SYSCTRL_RCGCUART            (*((volatile uint32_t *) 0x400FE618U))
#define SYSCTRL_PRGPIO              (*((volatile uint32_t *) 0x400FEA08U))

#define GPIO_PORTA_APB_GPIOAFSEL    (*((volatile uint32_t *) 0x40004420U))
#define GPIO_PORTA_APB_GPIODEN      (*((volatile uint32_t *) 0x4000451CU))
#define GPIO_PORTA_APB_GPIOPCTL     (*((volatile uint32_t *) 0x4000452CU))

#define UART_UART0_UARTDR           (*((volatile uint32_t *) 0x4000C000U))
#define UART_UART0_UARTFR           (*((volatile uint32_t *) 0x4000C018U))
#define UART_UART0_UARTIBRD         (*((volatile uint32_t *) 0x4000C024U))
#define UART_UART0_UARTFBRD         (*((volatile uint32_t *) 0x4000C028U))
#define UART_UART0_UARTLCRH         (*((volatile uint32_t *) 0x4000C02CU))
#define UART_UART0_UARTCTL          (*((volatile uint32_t *) 0x4000C030U))
#define UART_UART0_UARTIM           (*((volatile uint32_t *) 0x4000C038U))
#define UART_UART0_UARTCC           (*((volatile uint32_t *) 0x4000CFC8U))

/*
 * ignore interrupt status, since we only have 1 interrupt enabled
 *
 * Read from the rx register and write back to the tx register
 */
void
UART0_handler(void)
{
    uint32_t recv = UART_UART0_UARTDR & 0xFF;
    UART_UART0_UARTDR = recv;
}

int
main(void)
{
    SYSCTRL_RCGCUART |= 0x01U;
    SYSCTRL_RCGCGPIO |= 0x01U;

    /* wait until port clock is ready */
    while (!(SYSCTRL_PRGPIO & 0x01U))
        ;

    GPIO_PORTA_APB_GPIOAFSEL |= 0x03U;
    GPIO_PORTA_APB_GPIODEN |= 0x03U;
    GPIO_PORTA_APB_GPIOPCTL |= 0x11U;

    /*
     * 115200 baud rate, 8bit, no parity, one stop bit
     * No high speed -> ClkDiv = 16
     *
     * BRD = BRDI + BRDF = UARTSYsClk / (ClkDiv * BaudRate)
     * UARTFBRD[DIVFRAC] = floor(BRDF * 64 + 0.5)
     */
    UART_UART0_UARTIBRD = 0x08U;
    UART_UART0_UARTFBRD = 0x2CU;
    /*
     * Any change to UARTIBRD and UARTFBRD shall be followed by a write to
     * UARTLCRH for the changes to take effect
     *
     * Aside from that, we need to update it anyway at this point
     */
    UART_UART0_UARTLCRH = 0x60U;
    UART_UART0_UARTCC = 0x0;
    UART_UART0_UARTIM = 0x10;
    UART_UART0_UARTCTL = 0x0301U;

    const char *str = "hello UART!\r\n";
    for (const char *aux = str; *aux != '\0'; ++aux) {
        UART_UART0_UARTDR = *aux;
        while (UART_UART0_UARTFR & 0x08U)
            ;
    }

    while (true)
        ;

    return 0;
}

  • Gino Corazzi said:
    I'm not using any code from the ROM memory because I want to take care of everything and learn as much as possible in the process.

    May we note that while your goals are admirable - you must amend the phrase, "and take as long and add as much risk (as possible).

    For hobby use  this may be acceptable - in business - such spells, "death."    And - it may be untrue and overly simplistic to expect that your independent methods will yield, "everything" and spur (real) learning.

    You note "ROM memory" - might a better desciption be, "this vendor's rather spectacular API code base" which has long been proven to: "speed, ease & enhance" (very real) learning?    And which in no way is constrained to MCU's ROM - may (and far more likely) reside in programmable Flash memory - as well!

    To your issue at hand - should you accept the proposition advanced - load of that API UART_echo code - and then its run & debug - should quickly provide all of the detail you seek - in a far faster and less painful manner.   

    And - may we note - vendor's API has - by far - the best chance of, "taking care of everything."    Independent efforts (no offense intended) not so much...

  • This is for learning purposes. Since this is my first attempt with low level programming, yes, I firmly believe I can learn a lot from reading (and learning to read) the data sheet, while testing my knowledge writing code. So I would appreciate any highlight of what I'm (possibly) missing.

    And sure, I could inspect, in more than one way, the ROM code, also known as "this vendor's rather spectacular API code base", which in no way is constrained to MCU's ROM.

    Thanks for your time and effort, cb1_mobile.
  • My friend - mine is the perspective of small, tech biz firm owner - where (some) level of efficiency is demanded.
    We regularly hire & intern those bit new to MCUs - program development - our findings are reflected w/in my earlier writing.
    That API was a great inducement for this vendor to acquire the (past) MCU creator - it's use should not be (so heavily) discounted...
  • I've been trying to solve my own problem in the last few hours and finally realized that I didn't understand how to properly setup interrupts.

    The problem in my code was that I didn't enable the UART0 interrupt in the NVIC register. Even the less knowledgeable "Guru" could have spotted a similar mistake in no time.

  • Amit,

    Might you join in - and agree/disagree with poster's characterization of my suggestion of API's use as, "Fools negativity."

    I think both characterizations (may) prove correct - AND (far better) reflect their author...

    Hard to "miss" the fact that this poster launches "Personal Attack" - completely avoiding the tech substance - where he cannot compete...

  • Hello Gino,

    We are all prone to making errors (as shown by the missing Interrupt enable) and so am I susceptible to the same (and my past posts have shown that). Please refrain from making any personal judgmental comments.

    Regards
    Amit