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.

TM4C123GH6PGE: UART setup for TX interrupt based comms

Part Number: TM4C123GH6PGE
Other Parts Discussed in Thread: EK-TM4C123GXL

Hey,

I am new to the TM4C123GH6PGE series. Currently I try to understand how I can do FiFo tx transfers that are controlled by interrupts.

Design:

I like to create a send function that fills the FIFO and waits till its done. Since I am using a RTOS(Zephyr) I like to do some other stuff while the FIFO transfer is going on. So the transfer should be controlled via TX/FIFO interrupt.

I like to know how I need to setup the FIFO/INTR

I attach some "pseudo code". This code is compiled from my Zephyr UART API implementation, a middle layer that handles uart async and some app functions.


The "setup" and "send" functions are the entry points.

static char * pB;
static int N;

static int uart_tiva_fifo_fill(const struct device *dev, const uint8_t *buf, int len)
{
	const struct uart_tiva_config * const cfg = DEV_CFG(dev);
	const uint32_t base = cfg->base;
	int n = 0;

	while (n < len) {
		if (false == UARTCharPutNonBlocking(base, buf[n])) {
			break;
		}
		n++;
	}

	return n;
}


static void uart_tiva_isr(const struct device *dev)
{
	const struct uart_tiva_config * const cfg = DEV_CFG(dev);
	struct uart_tiva_runtime *const dev_data = DEV_DATA(dev);
	const uint32_t base = cfg->base;

	const uint32_t UIstatus = UARTIntStatus(base, true);
	if (dev_data->cb) {
		dev_data->cb(dev, dev_data->cb_data);
	}
	UARTIntClear(base, UIstatus);
}

static void uart0_fifo_callback(const struct device *dev, void *user_data) {
	ARG_UNUSED(user_data);

	if (uart_irq_tx_ready(dev) && (N)) {
		const uint32_t am = uart_fifo_fill(dev, pB, N);
		N -= am;
		pB += am;
		if (0 == N) {
			uart_irq_tx_disable(dev);
			k_sem_give(txDone);
		}
	}

}

void send(char * txt, int len) {

	pB = txt;
	N = len;

	const int n = uart_tiva_fifo_fill(uart0, pB, N);
	N -= n;
	pB += n;

	if (am) {
		k_sem_take(txDone, K_FOREVER);
	}
}

static int uart_tiva_configure(const struct device *dev, const struct uart_config *cfg) {
	const struct uart_tiva_config * const devCfg = DEV_CFG(dev);
	const uint32_t base = devCfg->base;
	uint32_t tiCfg = 0;

	switch(cfg->parity) {
		case UART_CFG_PARITY_NONE:
			tiCfg = UART_CONFIG_PAR_NONE;
			break;
		case UART_CFG_PARITY_ODD:
			tiCfg = UART_CONFIG_PAR_ODD;
			break;
		case UART_CFG_PARITY_EVEN:
			tiCfg = UART_CONFIG_PAR_EVEN;
			break;
		case UART_CFG_PARITY_MARK:
		case UART_CFG_PARITY_SPACE:
		default:
			return -ENOTSUP;
			break;
	};

	switch(cfg->stop_bits) {
		case UART_CFG_STOP_BITS_1:
			tiCfg |= UART_CONFIG_STOP_ONE;
			break;
		case UART_CFG_STOP_BITS_2:
			tiCfg |= UART_CONFIG_STOP_TWO;
			break;
		case UART_CFG_STOP_BITS_0_5:
		case UART_CFG_STOP_BITS_1_5:
		default:
			return -ENOTSUP;
			break;
	};

	UART9BitDisable(base);
	switch(cfg->data_bits) {
		case UART_CFG_DATA_BITS_5:
			tiCfg |= UART_CONFIG_WLEN_5;
			break;
		case UART_CFG_DATA_BITS_6:
			tiCfg |= UART_CONFIG_WLEN_6;
			break;
		case UART_CFG_DATA_BITS_7:
			tiCfg |= UART_CONFIG_WLEN_7;
			break;
		case UART_CFG_DATA_BITS_8:
			tiCfg |= UART_CONFIG_WLEN_8;
			break;
		case UART_CFG_DATA_BITS_9:
			// ToDo: check how 9bit mode is right fully setup
			// tiCfg |= UART_CONFIG_WLEN_8;
			// UART9BitEnable(base);
			// break;
		default:
			return -ENOTSUP;
			break;
	};

	UARTEnable(base);
	UARTConfigSetExpClk(base, SysCtlClockGet(), cfg->baudrate, tiCfg);
	/* Clear all UART interrupts */
	UARTIntClear(base,
		UART_INT_OE | UART_INT_BE | UART_INT_PE |
		UART_INT_FE | UART_INT_RT | UART_INT_TX |
		UART_INT_RX | UART_INT_CTS);

	switch(cfg->flow_ctrl) {
		case UART_CFG_FLOW_CTRL_NONE:
			UARTFlowControlSet(base,UART_FLOWCONTROL_NONE);
			break;
		case UART_CFG_FLOW_CTRL_RTS_CTS:
			UARTFlowControlSet(base, UART_FLOWCONTROL_RX | UART_FLOWCONTROL_TX);
			break;
		case UART_CFG_FLOW_CTRL_DTR_DSR:
		default:
			return -ENOTSUP;
	};

	UARTEnable(base);

	return 0;
}

void setup(void) {
	const struct uart_tiva_config * const cfg = DEV_CFG(dev);
	const uint32_t base = cfg->base;

	pinmux_tiva_arrayCfg(cfg->pinctrl_list, cfg->pinctrl_list_size);

	// switch uart on
	sysctl_activatePeripheral(base);

	IRQ_CONNECT(DT_INST_IRQN(n),
	DT_INST_IRQ(n, priority),
		uart_tiva_isr,
		DEVICE_DT_INST_GET(n),
		0);
	UARTIntClear(base, UART_INT_RX | UART_INT_RT);
	irq_enable(DT_INST_IRQN(n));
	
	UARTTxIntModeSet(base, UART_TXINT_MODE_EOT);

	const struct uart_config uart_cfg = {
			.baudrate = cfg->baudrate,
			.parity = UART_CFG_PARITY_NONE,
			.stop_bits = UART_CFG_STOP_BITS_1,
			.data_bits = UART_CFG_DATA_BITS_8,
			.flow_ctrl = UART_CFG_FLOW_CTRL_NONE
		};

	uart_tiva_configure(dev, &uart_cfg);

}



  • The tx intr gets enabled as well (I forgot to copy that code)

    static void uart_tiva_irq_tx_enable(const struct device *dev)
    {
    	const struct uart_tiva_config * const cfg = DEV_CFG(dev);
    	const uint32_t base = cfg->base;
    
    	UARTIntEnable(base, UART_INT_TX);
    }
    
    void send(char * txt, int len) {
    
    	pB = txt;
    	N = len;
    
    	uart_tiva_irq_tx_enable(uart0);
    	const int n = uart_tiva_fifo_fill(uart0, pB, N);
    	N -= n;
    	pB += n;
    
    	if (am) {
    		k_sem_take(txDone, K_FOREVER);
    	}
    }
    


  • Hi,

      Please refer to the uart_echo example in C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c123gxl\uart_echo. This example setup uart for RX interrupt. If you want to enable for TX FIFO interrupt then you will need to modify it such that:

      1. Enable FIFO by calling UARTFIFOEnable()

      2. Configure the FIFO level at which to generate interrupt by calling UARTFIFOLevelSet(). For example, UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8). This will configure both the TX FIFO and RX FIFO to generate interrupt when it has 4 out 8 data in the FIFO. In another word, half full. 

      3. Enable TX FIFO interrupt by calling MAP_UARTIntEnable(UART0_BASE, UART_INT_TX).

  • thx for the fast reply
    I know the uart demo from(https://github.com/yuvadm/tiva-c/tree/master/boards/ek-tm4c123gxl). The windows stuff don't work for me because I am on Linux(Ubuntu).

    Currently I am seeing some problems when filling UART TX(not FIFO mode) via "UARTCharPutNonBlocking".

    My code fills the UART till the mentioned function fails. After that I am waiting for the TX interrupt. When the intr fires, I transfer the next chunk of data. When I transmit the last byte of the data, the send function is unblocked by setting a semaphore.

    So my question, how to that without FIFO enable(that breaks my RX code)?
    I like to have the super generic case, that gives me a full duplex uart. The RX works independent(into a ringbuffer) form the TX. The TX sends a block of data. To off load the MCU I like to use the DMA or FIFO

  • Hi,

    So my question, how to that without FIFO enable(that breaks my RX code)?

    If you don't want to enable FIFO, you need to specifically disable it by calling UARTFIFODisable(). When you enable UART by calling UARTEnable(), it will also enable both the TX and RX FIFO. Actually, UARTEnable() is automatically called when you setup the UART by calling UARTConfigSetExpClk(). Therefore, if you don't want to use FIFO you must call  UARTFIFODisable() to disable it. Otherwise, the TX interrupt will only be generated after the FIFO level threshold is reached. 

    [Edit] See below example using UART interrupt mode without FIFO. 

    #include <stdint.h>
    #include <stdbool.h>
    #include <string.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/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
    
    char *string = "This example sends data to UART0 in interrupt mode without using FIFO";
    int len = 0;
    
    //*****************************************************************************
    //
    // The UART interrupt handler.
    //
    //*****************************************************************************
    void
    UARTIntHandler(void)
    {
        uint32_t ui32Status;
    
        //
        // Get the interrupt status.
        //
        ui32Status = MAP_UARTIntStatus(UART0_BASE, true);
    
        //
        // Clear the asserted interrupts.
        //
        MAP_UARTIntClear(UART0_BASE, ui32Status);
    
        if (len >= 0)
        {
            //
            // Write the next character to the UART.
            //
            MAP_UARTCharPutNonBlocking(UART0_BASE, *string++);
            len--;
        }
    }
    
    
    //*****************************************************************************
    //
    // 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.
        //
        MAP_FPUEnable();
        MAP_FPULazyStackingEnable();
    
        //
        // Set the clocking to run directly from the crystal.
        //
        MAP_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.
        //
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    
        //
        // Enable the GPIO pins for the LED (PF2).
        //
        MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
    
        //
        // Enable the peripherals used by this example.
        //
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Enable processor interrupts.
        //
        MAP_IntMasterEnable();
    
        //
        // Set GPIO A0 and A1 as UART pins.
        //
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
        MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Configure the UART for 115,200, 8-N-1 operation.
        //
        UARTConfigSetExpClk(UART0_BASE, MAP_SysCtlClockGet(), 115200,
                                (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                                 UART_CONFIG_PAR_NONE));
    
        //
        // Disable FIFO
        //
        UARTFIFODisable(UART0_BASE);
    
        //
        // Enable the UART interrupt.
        //
        MAP_IntEnable(INT_UART0);
        MAP_UARTIntEnable(UART0_BASE, UART_INT_TX);
    
        len = strlen(string);
        //
        // Prompt for text to be entered.
        //
        MAP_UARTCharPut(UART0_BASE, ' ');
    
    
        //
        // Loop forever echoing data through the UART.
        //
        while(1)
        {
        }
    }

  • disableing the FIFO solved my problem