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.

Simple UART Configuration Function

I've created a function to quickly set up basic UART ports. I thought I would post it here in case anyone else might find it useful or if anyone had thoughts on how it could be improved. I think when it comes to production it may be better in terms of memory management to manually configure the UARTs and avoid this but it seems useful for development. As a test in the hello example project, modify hello.c, include uartconf.h and comment out the ConfigureUART function.


#uartconf.h
#ifndef UARTCONFIG_H_
#define UARTCONFIG_H_

#include <stdint.h>
#include <stdbool.h>
#include "driverlib/gpio.h"
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/debug.h"
#include "utils/uartstdio.h"
#include "driverlib/rom.h"

// Friendly print message macros for debug.
#define NL UARTprintf("\r\n") // print a newline
#define TAB UARTprintf("\t") // print a tab
#define PRINT(s) UARTprintf("%s", s) // print a string
#define PRINT_C(c) UARTprintf("%s: %c", #c, c) // print a char variable
#define PRINT_D(d) UARTprintf("%s: %d", #d, d) // print a decimal variable
#define PRINT_I(i) PRINT_D(i) // print an integer variable
#define PRINT_S(s) UARTprintf("%s: %s", #s, s) // print a string variable
#define PRINT_U(u) UARTprintf("%s: %u", #u, u) // print an unsigned variable
#define PRINT_X(x) UARTprintf("%s: %x", #x, x) // print a hexadecimal variable
#define PRINT_LINE UARTprintf("Line[%d]", __LINE__); // print the line number where this is called

/* ConfigureUART
 * This can replace the standard ConfigureUART function found in many
 * of the TivaWare example projects.
 * 
 * This version of the function allows for variadic input and automatically
 * configures the parameters based on which UART you want to use. When
 * you call ConfigureUART the parameter list will be parsed/generated
 * and sent to ConfigureUART_base
 * 
 * \param ui32PortNum - UART Port number to configure (default=0)
 * \param ui32Baud - Baud rate to be used on that UART (default=115200)
 * \param ui32SrcClock - Source clock frequency (default=16000000)
 * 
 * Example Usage:
 * - ConfigureUART();
 *   - All defaults:
 *     Enable UART0, Rx on PA0, Tx on PA1
 *     Set baud rate to 115200
 *     Source clock frequence to 16000000
 * - ConfigureUART(2);
 *   - Port number only:
 *     Enable UART2, Rx on PD6, Tx on PD7
 *     Default baud and clock
 * - ConfigureUART(.ui32Baud=9600);
 * 	 - Baud rate only:
 *     Set baud rate to 9600
 *     Default UART0 and clock
 * - ConfigureUART(.ui32PortNum=0,.ui32Baud=115200,.ui32SrcClock=16000000);
 *   - All explicitly defined
 * - ConfigureUART(0,115200,16000000);
 *   - All defined
 */
void ConfigureUART_base(uint32_t ui32PortNum, uint32_t ui32Baud, uint32_t ui32SrcClock);

typedef struct {
	// Arguments required ConfigureUART function
	uint32_t ui32PortNum; // The UART Port number (0-7)
	uint32_t ui32Baud; // Baud rate used to communicate
	uint32_t ui32SrcClock; // Source clock frequency
} ConfigureUART_args;

void var_ConfigureUART(ConfigureUART_args in);

#define ConfigureUART(...) var_ConfigureUART((ConfigureUART_args){__VA_ARGS__});
/*\ConfigureUART */

/* TIVA UART Configuration Table 
 * This table defines the port and pins used for each UART
 */
typedef struct {
	uint32_t sysctlPeriphGPIO;
	uint32_t sysctlPeriphUART;
	uint32_t gpioPinURx;
	uint32_t gpioPinUTx;
	uint32_t gpioPortBase;
	uint32_t gpioPinRx;
	uint32_t gpioPinTx;
	uint32_t uartBase;
} uart_port;

extern const uart_port uart_ports[8];
/*\TIVA UART Configuration Table */

#endif

#uartconf.c
#include "uartconfig.h"

const uart_port uart_ports[8] = {
	//UART Port Mappings for TM4C123G LaunchPad
	{SYSCTL_PERIPH_GPIOA,
		SYSCTL_PERIPH_UART0,
		GPIO_PA0_U0RX,
		GPIO_PA1_U0TX,
		GPIO_PORTA_BASE,
		GPIO_PIN_0,
		GPIO_PIN_1,
		UART0_BASE}, //UART0
	{SYSCTL_PERIPH_GPIOB,
		SYSCTL_PERIPH_UART1,
		GPIO_PB0_U1RX,
		GPIO_PB1_U1TX,
		GPIO_PORTB_BASE,
		GPIO_PIN_0,
		GPIO_PIN_1,
		UART1_BASE}, //UART1
	{SYSCTL_PERIPH_GPIOD,
		SYSCTL_PERIPH_UART2,
		GPIO_PD6_U2RX,
		GPIO_PD7_U2TX,
		GPIO_PORTD_BASE,
		GPIO_PIN_6,
		GPIO_PIN_7,
		UART2_BASE}, //UART2
	{SYSCTL_PERIPH_GPIOC,
		SYSCTL_PERIPH_UART3,
		GPIO_PC6_U3RX,
		GPIO_PC7_U3TX,
		GPIO_PORTC_BASE,
		GPIO_PIN_6,
		GPIO_PIN_7,
		UART3_BASE}, //UART3
	{SYSCTL_PERIPH_GPIOC,
		SYSCTL_PERIPH_UART4,
		GPIO_PC4_U4RX,
		GPIO_PC5_U4TX,
		GPIO_PORTC_BASE,
		GPIO_PIN_4,
		GPIO_PIN_5,
		UART4_BASE}, //UART4
	{SYSCTL_PERIPH_GPIOE,
		SYSCTL_PERIPH_UART5,
		GPIO_PE4_U5RX,
		GPIO_PE5_U5TX,
		GPIO_PORTE_BASE,
		GPIO_PIN_4,
		GPIO_PIN_5,
		UART5_BASE}, //UART5
	{SYSCTL_PERIPH_GPIOD,
		SYSCTL_PERIPH_UART6,
		GPIO_PD4_U6RX,
		GPIO_PD5_U6TX,
		GPIO_PORTD_BASE,
		GPIO_PIN_4,
		GPIO_PIN_5,
		UART6_BASE}, //UART6
	{SYSCTL_PERIPH_GPIOE,
		SYSCTL_PERIPH_UART7,
		GPIO_PE0_U7RX,
		GPIO_PE1_U7TX,
		GPIO_PORTE_BASE,
		GPIO_PIN_0,
		GPIO_PIN_1,
		UART7_BASE} //UART7
};

void ConfigureUART_base(uint32_t ui32PortNum, uint32_t ui32Baud, uint32_t ui32SrcClock) {

	// Check the arguments.
	ASSERT((ui32PortNum == 0) || (ui32PortNum == 1) || (ui32PortNum == 2)); // UARTStdioConfig seems to only allow 0,1,2 (not sure what happened to 3-7)
	ASSERT((ui32Baud == 9600) || (ui32Baud == 115200)); // TODO: there are more valid baud rates than this
	// TODO: what source clock frequencies are valid?

	// Set port/pin values based on UART channel
	uart_port uport = uart_ports[ui32PortNum];

    // Enable the GPIO Peripheral used by the UART.
    ROM_SysCtlPeripheralEnable(uport.sysctlPeriphGPIO);

    // Enable UART
    ROM_SysCtlPeripheralEnable(uport.sysctlPeriphUART);

    // Configure GPIO Pins for UART mode.
    ROM_GPIOPinConfigure(uport.gpioPinURx);
    ROM_GPIOPinConfigure(uport.gpioPinUTx);
    ROM_GPIOPinTypeUART(uport.gpioPortBase, uport.gpioPinRx | uport.gpioPinTx);

    // Use the internal 16MHz oscillator as the UART clock source.
    UARTClockSourceSet(uport.uartBase, UART_CLOCK_PIOSC);

    // Initialize the UART for console I/O.
    UARTStdioConfig(ui32PortNum, ui32Baud, ui32SrcClock);
}

void var_ConfigureUART (ConfigureUART_args in) {
	// Sets the default values for undefined parameters when calling
	// ConfigureUART
	uint32_t ui32PortNum_out = in.ui32PortNum ? in.ui32PortNum : 0; // Default to 0, Port A
	uint32_t ui32Baud_out = in.ui32Baud ? in.ui32Baud : 115200; // Default to 115200, max baud
	uint32_t ui32SrcClock_out = in.ui32SrcClock ? in.ui32SrcClock : 16000000; // Default to 16Mhz
	return ConfigureUART_base(ui32PortNum_out, ui32Baud_out, ui32SrcClock_out);
}

  • Hello Jamie,

    Thanks for contributing to the forum knowledge base. The function var_ConfigureUART can be recursively be called for setting up all the UARTs?

    Regards

    Amit

  • Unfortunately the code hasn't received a whole lot of testing. I had a breadboard project set up using multiple UART's but it was disassembled before I had a chance to test this. It definitely works on UART0. I'll try to update this thread after I've used it on a few more complex projects.

    I wrote it with the intent that it could be called recursively.

    *Note: You should call the ConfigureUART macro instead of calling var_ConfigureUART directly.

  • Hello Jamie,

    I agree. A well tested code would always be more useful. But still it is a good input to the forum

    Thanks for the pointer on ConfigureUART API.

    Regards

    Amit