Setup for UART Receive

The following procedure is used to receive a byte of data:

  1. Configure the clock input and baud rate as detailed in Clocking and Baud Rate Configuration.
  2. Configure the data width and parity by writing a selection to the MODE[3:0] bits.
  3. Configure the polarity, Stop bit duration and flow control.
  4. Configure the RX interrupt watermark using the RXWM[2:0] bits (UxSTAT[26:24]).
  5. Configure the address detect if needed as detailed in Address Detect.
  6. Set the ON bit (UxCON[15]).
  7. Set the RXEN bit (UxCON[4]).

An RX interrupt will be generated when a byte is received, according to the UART Receive Interrupt Select bits setting, RXWM[2:0] (UxSTAT[26:24]). The RXWMx bits can be configured to generate an RX interrupt when the RX buffer contains one to eight bytes.

Software can then read the data from the UxRXB register. The time, relative to the Stop bit when the RX interrupt is generated, is configurable using the STPMD bit (UxSTAT[22]). By default, an RX interrupt is generated in the middle of the Stop bit. Writing a ‘1’ will move the RX interrupt to the end of the Stop bit.

The RXBF status bit (UxSTAT[16]) can be read by software to determine if the receive buffer is full, and a read operation of UxRXB is required to allow reception of additional bytes. Similarly, the RXBE status bit (UxSTAT[17]) can be read with software to determine if the receive buffer is empty.

UART1 Reception with Interrupts

#include <xc.h>

//Clocking based on CPU @8MHz, UART1 running on 1/2 speed peripheral bus @4MHz
#define FP 4000000
#define BAUDRATE 9600
//Baud rate calculation for fractional baud rate mode
#define BRGVAL (FP/BAUDRATE)

#define RECEIVED_CHAR_SIZE 16
uint8_t receivedChar[RECEIVED_CHAR_SIZE];
uint8_t receivedCount = 0;

int main(void) {
    
        //Configure I/O
    _U1RXR = 50; //Assign RP50 (RD1) to UART1 RX input function
    _TRISD1 = 1; //Set RC6 as input

    U1CONbits.MODE = 0;                    // Asynchronous 8-bit UART
    U1CONbits.CLKSEL = 0;                  // 1/2 speed peripheral clock as Baud Clock source
    U1CONbits.STP = 0;                     // 1 stop bit

    //Use fractional baud rate divider
    U1CONbits.CLKMOD = 1;   
    U1BRG = BRGVAL;                        // Baud Rate setting for 9600

    U1STATbits.RXWM = 0;                   // Interrupt when there is one word or more in the buffer
    IEC3bits.U1RXIE = 1;                   // Enable Receive interrupt

    U1CONbits.ON = 1;                      // Enable UART
    U1CONbits.RXEN = 1;                    // Enable UART RX.

    while(1) {}

    return 0;
}

void __attribute__((interrupt)) _U1RXInterrupt(void)
{ 
    IFS3bits.U1RXIF = 0;                    // Clear RX interrupt flag
    while(U1STATbits.RXBE == 0)             // Check if RX buffer has data to read 
    { 
        receivedChar[receivedCount++] = U1RXB; // Read a character from RX buffer
        
        //Avoid buffer overrun
        if (receivedCount >= RECEIVED_CHAR_SIZE) {
            receivedCount = 0;
        }
    }
}