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:
- write "hello UART\r\n" to UART0 - this works perfectly
- raise an interrupt upon receiving a character from UART0
- 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;
}