3.17.20 Universal Asynchronous Receiver Transmitter (UART)

The UART peripheral library (PLIB) can be configured either in blocking (interrupt disabled), non-blocking (interrupt enabled) or ring buffer mode.

Blocking mode

In blocking mode, the UART peripheral interrupts are disabled and the transfer APIs block until the requested data is transferred.

Non-blocking mode

In non-blocking mode the peripheral interrupt is enabled. The transfer API initiates the transfer and returns immediately. The transfer is then completed from the peripheral interrupt. Application can either use a callback to get notified when the transfer is complete or can use the IsBusy API to check the completion status.

Ring buffer mode

In ring buffer mode, the receiver is always enabled, and the received data is saved in the internal receive ring buffer, size of which can be configured using MCC. The application can use the API calls to read the data out from the ring buffer. APIs are provided to query the number of (unread) bytes available in the receive buffer, free space in the receive buffer and size of the receive buffer. Similarly, during transmission, the application data is deep copied into the internal transmit ring buffer, size of which can be configured using MCC. This allows the use of local buffers for data transmission. APIs are provided to query the free space in the transmit buffer, number of bytes pending transmission and the size of the transmit buffer. Additionally, application can enable notifications to get notified when n bytes are available in the receive buffer or when n bytes of free space is available in the transmit buffer. The APIs allow application to set the threshold levels for notification in both receive and transmit buffers. Further, application can also choose to enable persistent notifications, whereby the application is notified until the threshold condition is met.

In all the modes, library provides API to change the baud, parity, data width and the number of stop bits at run time.

Using The Library

Blocking Mode

#define RX_BUFFER_SIZE 10
char message[] = "UART Example in blocking mode";
char receiveBuffer[RX_BUFFER_SIZE] = {0};
UART_ERROR errorStatus;
char rxData = 0;

int main ( void )
{    
    /* Initialize all modules */
    SYS_Initialize ( NULL );

    /* Transmit buffer*/
    UART1_Write(message, sizeof(message));
	
	/* Wait for a character to be received */
	while(UART1_ReceiverIsReady() == false);
		
	if(UART1_ErrorGet() == UART_ERROR_NONE)
	{
		/* Read a byte */
		rxData = UART1_ReadByte();
	}
	
	/* Receive buffer */
    if (UART1_Read(receiveBuffer, RX_BUFFER_SIZE)) == false)
	{
		/* Read failed, get the error */
		errorStatus UART1_ErrorGet();
		
		/* Handle the error */
	}
    else
	{
		/* Transmit the received buffer*/
		UART1_Write(receiveBuffer, RX_BUFFER_SIZE);
	}

	...

    /* Execution should not come here during normal operation */

    return ( EXIT_FAILURE );
}

Non-blocking Mode

#define RX_BUFFER_SIZE 10

char message[] = "**** Non-blocking Transfer with the interrupt  ****\r\n\
**** Type 10 characters. The received characters are echoed back ****\r\n";

char messageError[] = "**** UART error occurred ****\r\n";

char receiveBuffer[RX_BUFFER_SIZE] = {0};
char echoBuffer[RX_BUFFER_SIZE+4] = {0};

bool errorStatus = false;
bool writeStatus = false;
bool readStatus = false;

void APP_WriteCallback(uintptr_t context)
{
    writeStatus = true;
}

void APP_ReadCallback(uintptr_t context)
{
    if(UART1_ErrorGet() != UART_ERROR_NONE)
    {
        /* ErrorGet clears errors, set error flag to notify console */
        errorStatus = true;
    }
    else
    {
        readStatus = true;
    }
}

int main ( void )
{
    /* Initialize all modules */
    SYS_Initialize ( NULL );

    /* Register callback functions and send start message */
    UART1_WriteCallbackRegister(APP_WriteCallback, 0);
    UART1_ReadCallbackRegister(APP_ReadCallback, 0);
    UART1_Write(&message[0], sizeof(message));

    while ( true )
    {
        if(errorStatus == true)
        {
            /* Send error message to console */
            errorStatus = false;
            UART1_Write(&messageError[0], sizeof(messageError));
        }
        else if(readStatus == true)
        {
            /* Echo back received buffer and Toggle LED */
            readStatus = false;

            echoBuffer[0] = '\n';
            echoBuffer[1] = '\r';
            memcpy(&echoBuffer[2], receiveBuffer,sizeof(receiveBuffer));
            echoBuffer[RX_BUFFER_SIZE+2] = '\n';
            echoBuffer[RX_BUFFER_SIZE+3] = '\r';

            UART1_Write(&echoBuffer[0], sizeof(echoBuffer));
        }
        else if(writeStatus == true)
        {
            /* Submit buffer to read user data */
            writeStatus = false;
            UART1_Read(&receiveBuffer[0], sizeof(receiveBuffer));
        }
        else
        {
            /* Repeat the loop */
            ;
        }
    }

    /* Execution should not come here during normal operation */

    return ( EXIT_FAILURE );
}

Ring buffer Mode

uint8_t txBuffer[50];
uint8_t rxBuffer[10];
volatile uint32_t nBytesRead = 0;
volatile bool txThresholdEventReceived = false;
volatile bool rxThresholdEventReceived = false;

void UARTReadEventHandler(UART_EVENT event, uintptr_t context )
{
    uint32_t nBytesAvailable = 0;
    
    if (event == UART_EVENT_READ_THRESHOLD_REACHED)
    {
        /* Receiver should atleast have the thershold number of bytes in the ring buffer */
        nBytesAvailable = UART1_ReadCountGet();
        
        nBytesRead += UART1_Read((uint8_t*)&rxBuffer[nBytesRead], nBytesAvailable);                          
    }
}

void UARTWriteEventHandler(UART_EVENT event, uintptr_t context )
{
    txThresholdEventReceived = true;
}

int main ( void )
{
    uint32_t nBytes = 0;        
    
    /* Initialize all modules */
    SYS_Initialize ( NULL );          
    
    /* Register a callback for write events */
    UART1_WriteCallbackRegister(UARTWriteEventHandler, (uintptr_t) NULL);
    
    /* Register a callback for read events */
    UART1_ReadCallbackRegister(UARTReadEventHandler, (uintptr_t) NULL);              
    
    /* Print the size of the read buffer on the terminal */
    nBytes = sprintf((char*)txBuffer, "RX Buffer Size = %d\r\n", (int)UART1_ReadBufferSizeGet());
    
    UART1_Write((uint8_t*)txBuffer, nBytes);  
    
    /* Print the size of the write buffer on the terminal */
    nBytes = sprintf((char*)txBuffer, "TX Buffer Size = %d\r\n", (int)UART1_WriteBufferSizeGet());
    
    UART1_Write((uint8_t*)txBuffer, nBytes);    
    
    UART1_Write((uint8_t*)"Adding 10 characters to the TX buffer - ", sizeof("Adding 10 characters to the TX buffer - "));    
    
    /* Wait for all bytes to be transmitted out */
    while (UART1_WriteCountGet() != 0);    
    
    UART1_Write((uint8_t*)"0123456789", 10);           
        
    /* Print the amount of free space available in the TX buffer. This should be 10 bytes less than the configured write buffer size. */
    nBytes = sprintf((char*)txBuffer, "\r\nFree Space in Transmit Buffer = %d\r\n", (int)UART1_WriteFreeBufferCountGet());

    UART1_Write((uint8_t*)txBuffer, nBytes);    
    
    /* Let's enable notifications to get notified when the TX buffer is empty */
    UART1_WriteThresholdSet(UART1_WriteBufferSizeGet());   
    
    /* Enable notifications */
    UART1_WriteNotificationEnable(true, false);
   
    /* Wait for the TX buffer to become empty. Flag "txThresholdEventReceived" is set in the callback. */
    while (txThresholdEventReceived == false);
    
    txThresholdEventReceived = false;    
    
    /* Disable TX notifications */
    UART1_WriteNotificationEnable(false, false);
    
    UART1_Write((uint8_t*)"Enter 10 characters. The received characters are echoed back. \r\n>", sizeof("Enter 10 characters. The received characters are echoed back. \r\n>"));               
            
    /* Wait till 10 (or more) characters are received */
    while (UART1_ReadCountGet() < 10);
    
    /* At-least 10 characters are available in the RX buffer. Read out into the application buffer */
    UART1_Read((uint8_t*)rxBuffer, 10);  
    
    /* Echo the received data */
    UART1_Write((uint8_t*)rxBuffer, 10);    
    
    /* Now demonstrating receiver notifications */
    UART1_Write((uint8_t*)"\r\n Now turning on RX notifications \r\n>", sizeof("\r\n Now turning on RX notifications \r\n>"));
    
    /* For demonstration purpose, set a threshold value to receive a callback after every 5 characters are received */
    UART1_ReadThresholdSet(5);
    
    /* Enable RX event notifications */
    UART1_ReadNotificationEnable(true, false);
                   
    while(1)
    {
        /* Wait until at-least 10 characters are entered by the user */
        while (nBytesRead < 10);    
    
        /* Echo the received data */
        UART1_Write((uint8_t*)rxBuffer, nBytesRead);
        
        UART1_Write((uint8_t*)"\r\n>", 3);

        nBytesRead = 0;
    }

    /* Execution should not come here during normal operation */

    return ( EXIT_FAILURE );
}

Library Interface

UART peripheral library provides the following interfaces:

Functions

NameDescriptionBlocking modeNon-blocking modeRing buffer mode
UARTx_InitializeInitializes given instance of the UART peripheralYesYesYes
UARTx_SerialSetupSets up serial configurations for UART peripheralYesYesYes
UARTx_WriteWrites data to the given UART peripheral instanceYesYesYes
UARTx_ReadReads data from the given UART peripheral instanceYesYesYes
UARTx_WriteIsBusyReturns the write request status associated with the given UART peripheral instanceNoYesNo
UARTx_ReadIsBusyReturns the read request status associated with the given UART peripheral instanceNoYesNo
UARTx_WriteCountGetGets the byte count of processed bytes for a given UART read operation in non-blocking mode. Returns the number of bytes pending to be transmitted out in the transmit buffer in ring buffer mode.NoYesYes
UARTx_ReadCountGetGets the byte count of processed bytes for a given UART read operation in non-blocking mode. Returns the number of bytes available in the internal receive buffer of the PLIB in ring buffer mode.NoYesYes
UARTx_TransmitterIsReadyReturns the hardware status of the UART TransmitterYesNoNo
UARTx_ReceiverIsReadyReturns the hardware status of the UART ReceiverYesNoNo
UARTx_ErrorGetGets the error of the given UART peripheral instanceYesYesYes
UARTx_WriteCallbackRegisterSets the pointer to the function (and it's context) to be called when the given UART's write events occurNoYesYes
UARTx_ReadCallbackRegisterSets the pointer to the function (and it's context) to be called when the given UART's read events occurNoYesYes
UARTx_ReadByteSubmits request to read a byte of data to the given UART peripheralYesNoNo
UARTx_WriteByteSubmits a byte of data to the given UART peripheral to transferYesNoNo
UARTx_ReadAbortAborts the ongoing read requestNoYesNo
UARTx_WriteFreeBufferCountGetReturns the number of bytes of free space available in the internal transmit bufferNoNoYes
UARTx_WriteBufferSizeGetReturns the size of the internal transmit ring bufferNoNoYes
UARTx_WriteNotificationEnableThis API lets the application turn the transmit notifications on/offNoNoYes
UARTx_WriteThresholdSetThis API allows the application to set a threshold level on the number of free space available in the transmit bufferNoNoYes
UARTx_ReadFreeBufferCountGetReturns the number of bytes of free space available in the internal receive bufferNoNoYes
UARTx_ReadBufferSizeGetReturns the size of the receive ring bufferNoNoYes
UARTx_ReadNotificationEnableThis API lets the application turn the receive notifications on/offNoNoYes
UARTx_ReadThresholdSetThis API allows the application to set a threshold level on the number of bytes of data available in the receive bufferNoNoYes
UARTx_AutoBaudQueryReturns the status of auto-baud operationYesYesYes
UARTx_AutoBaudSetEnables the auto-baud detectionYesYesYes

Data types and constants

NameTypeDescriptionBlocking modeNon-blocking modeRing buffer mode
UART_ERRORMacros and TypedefDefines the macros and typedefs associated with the UART peripheral errorsYesYesYes
UART_DATAEnumDefines the data width types for the UART peripheralYesYesYes
UART_PARITYEnumDefines the parity types for the UART peripheralYesYesYes
UART_STOPEnumDefines the data type for the UART peripheral stop bitsYesYesYes
UART_SERIAL_SETUPStructDefines the data structure which is used to configure UART serial parameters at run timeYesYesYes
UART_CALLBACKTypedefDefines the data type and function signature of the UART peripheral library callback functionYesYesNo
UART_EVENTEnumDefines the enums associated with the UART events in the ring buffer modeYesYesYes
UART_RING_BUFFER_CALLBACKTypedefDefines the data type and function signature for the UART peripheral callback function in the ring buffer modeNoNoYes