UART: Programming

As with Timer32, we will be using various DriverLib functions and features in order to utilize the UART on the Launchpad. The UART DriverLib functions are underpinned by a struct that defines all of the useful parameters needed to operate the UART.

typedef struct _eUSCI_eUSCI_UART_Config

{

    uint_fast8_t selectClockSource;

    uint_fast16_t clockPrescalar;

    uint_fast8_t firstModReg;

    uint_fast8_t secondModReg;

    uint_fast8_t parity;

    uint_fast16_t msborLsbFirst;

    uint_fast16_t numberofStopBits;

    uint_fast16_t uartMode;

    uint_fast8_t overSampling;

} eUSCI_UART_Config;

As the name implies, the selectClockSource parameter chooses which of two clock sources to choose from: EUSCI_A_UART_CLOCKSOURCE_SMCLK or EUSCI_A_UART_CLOCKSOURCE_ACLK. Generally, you will want to use the first clock source, as the other is optimized for low-power mode (which you will not have to use in this course). Note that the frequency of the clock source can be found in the system_msp432p401r.c file, defined by the __SYSTEM_CLOCK macro. The clockPrescalar parameter is, of course, the prescalar applied to the source clock. Unlike with Timer32, this parameter is a simple unsigned integer. You may also see this parameter referred to as UCBR. The firstModReg parameter corresponds to the integer portion of the division factor, modulus 16. You may also see this parameter referred to as UCBRF. Similarly, the secondModReg parameter corresponds to the fractional portion division factor when matched with Table 24.4, typically left as a hex value. This parameter may also be called UCBRS. The parity parameter determines the parity of the UART: EUSCI_A_UART_NO_PARITY, EUSCI_A_UART_ODD_PARITY, or EUSCI_A_UART_EVEN_PARITY. The msborLsbFirst parameter determines whether the data frame is EUSCI_A_UART_MSB_FIRST or EUSCI_A_UART_LSB_FIRST. The numberofStopBits parameter selects between EUSCI_A_UART_ONE_STOP_BIT or EUSCI_A_UART_TWO_STOP_BITS. The uartMode parameter configures what mode the UART will operate in, but generally, you will want to use the default mode: EUSCI_A_UART_MODE. Finally, the overSampling parameter sets the baudrate generation mode, where EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION will usually be desirable.


Taking the previous example, we know the integer portion of the division factor is 1041. Dividing that by 16 gives us the UCBR value of 65.0625‬, which will simply be treated as 65. firstModReg will be the integer portion of the division factor (1041) modulus 16, which is 1. secondModReg, as we already looked up, will be 0xD6. From there, all we have to do is fill in the other parameters from the problem. The struct for this specific UART would be:

eUSCI_UART_Config uartConfig = {

         EUSCI_A_UART_CLOCKSOURCE_SMCLK,               // SMCLK Clock Source = 10MHz

         65,                                           // UCBR = 65

         1,                                            // UCBRF = 1

         0xD6,                                         // UCBRS = 0xD6

         EUSCI_A_UART_EVEN_PARITY,                       // Even Parity

         EUSCI_A_UART_LSB_FIRST,                       // LSB First

         EUSCI_A_UART_ONE_STOP_BIT,                    // One stop bit

         EUSCI_A_UART_MODE,                            // UART mode

         EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION // Oversampling

    };

Although we have a struct to hold all of this information, we haven’t configured the UART module yet. In order to initialize the UART, we can use the following function:

extern bool UART_initModule(uint32_t moduleInstance,

        const eUSCI_UART_Config *config);

The moduleInstance parameter selects which communication module to initialize out of four possible options: EUSCI_A0_BASE, EUSCI_A1_BASE, EUSCI_A2_BASE, or EUSCI_A3_BASE. In other words, just like Timer32 and GPIO ports, there are more than one of these modules on the chip. It is unlikely that you will be using multiple UART modules simultaneously in this course, so be sure to be consistent with whichever module you choose, as you will need to call on that module in many other UART DriverLib functions. The *config parameter is a pointer to an eUSCI_UART_Config struct, which contains all the data needed to initialize the UART module.

Initializing the module is not enough, however. In order to use the UART, it must be enabled with the following function:

extern void UART_enableModule(uint32_t moduleInstance);

This function uses only a moduleInstance parameter, which is the same used for the initialization function. Keep in mind that if you want to change the UART’s configuration, modifying the struct alone is not enough. You will have to re-initialize and re-enable the UART module with the updated struct in order for the modifications to be reflected.

Now that our UART module is up and ready, how will we know if it has received any data? The following function can tell us if the UART has received or transmitted data:

extern uint_fast8_t UART_getInterruptStatus(uint32_t moduleInstance,

        uint8_t mask);

As with the previous functions, moduleInstance specifies the UART module we want to check. The mask parameter essentially selects which flag you want to inspect. The choices for mask are EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG, EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG, EUSCI_A_UART_STARTBIT_INTERRUPT_FLAG, or EUSCI_A_UART_TRANSMIT_COMPLETE_INTERRUPT_FLAG. The return values of this function are either 0 when the flag is not active and the mask itself when the flag is active. A useful application of this function is to check when the UART has received data.

if (UART_getInterruptStatus (EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG)

                == EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG)

This if statement will only execute if the UART has received data. Another application is to check that the UART is ready to transmit data.

if (UART_getInterruptStatus (EUSCI_A0_BASE, EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG)

                    == EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG)

Knowing when the UART has data is nice, but how do we extract the received data? Yet another function comes to our aid.

extern uint8_t UART_receiveData(uint32_t moduleInstance);

Once again, moduleInstance is the UART module from which we want to get data from. The returned value is a byte, which can be stored nicely into a char data type.

What about transmitting data from the UART? There’s a function for that, too!

extern void UART_transmitData(uint32_t moduleInstance,

        uint_fast8_t transmitData);

As usual, moduleInstance is the UART module from which you want to transmit data from. The transmitData parameter is, as implied, the byte you want to transmit.