In this article, we will learn how to use UART on Apollo3 MCU.
Before you start developing the code, please go through the Pin mapping. You can download the Apollo3 MCU Blue Pinout details.
If you need help setting up the development environment, please read this article.

How to use UART
Sending data and receiving data over UART is the most simple serial interface. Following are the steps needed:
We need a UART handle which will be passed to HAL function for configuration.
A Macro “CHECK_ERRORS” is used to detect if any errors has occurred when a HAL function is called.
// UART handle.
void *phUART;
#define CHECK_ERRORS(x) \
if ((x) != AM_HAL_STATUS_SUCCESS) \
{ \
error_handler(x); \
}
volatile uint32_t ui32LastError;
// Catch HAL errors.
void error_handler(uint32_t ui32ErrorStatus)
{
ui32LastError = ui32ErrorStatus;
while (1); // you can replace this with your own code to handle the error condition
}
We need to create two buffers, one for TX and one for RX.
// UART buffers.
uint8_t g_pui8TxBuffer[256];
uint8_t g_pui8RxBuffer[1];
Now, define UART configuration structure variable and set the required parameters:
const am_hal_uart_config_t g_sUartConfig =
{
//
// Standard UART settings: 9600-8-N-1
//
.ui32BaudRate = 9600,
.ui32DataBits = AM_HAL_UART_DATA_BITS_8,
.ui32Parity = AM_HAL_UART_PARITY_NONE,
.ui32StopBits = AM_HAL_UART_ONE_STOP_BIT,
.ui32FlowControl = AM_HAL_UART_FLOW_CTRL_NONE,
//
// Set TX and RX FIFOs to interrupt at half-full.
//
.ui32FifoLevels = (AM_HAL_UART_TX_FIFO_1_2 |
AM_HAL_UART_RX_FIFO_1_2),
//
// Buffers
//
.pui8TxBuffer = g_pui8TxBuffer,
.ui32TxBufferSize = sizeof(g_pui8TxBuffer),
.pui8RxBuffer = g_pui8RxBuffer,
.ui32RxBufferSize = sizeof(g_pui8RxBuffer),
};
one more configuration which is required is, GPIO pin configuration. Create Macro for RX, TX numbers
#define UART0_TX_PIN 22
#define UART0_RX_PIN 23
Declare two variables one for tx and another rx gpio pin configuration. Set the alternate function for both pins.
// GPIO pin configuration for UART
am_hal_gpio_pincfg_t uart0ConfigTx;
am_hal_gpio_pincfg_t uart0ConfigRx;
uart0ConfigTx.uFuncSel = AM_HAL_PIN_22_UART0TX; // Set GPIO function, see Pinout details
uart0ConfigTx.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA;
uart0ConfigRx.uFuncSel = AM_HAL_PIN_23_UART0RX; // Set GPIO function, see Pinout details
then before super loop / while(1), we need to initialize the UART instance, UART0 in this case.
// Initialize the interface for UART output.
CHECK_ERRORS(am_hal_uart_initialize(0, &phUART));
Configure the Power State for UART, possible states are:
- AM_HAL_SYSCTRL_WAKE,
- AM_HAL_SYSCTRL_NORMALSLEEP,
- AM_HAL_SYSCTRL_DEEPSLEEP
CHECK_ERRORS(am_hal_uart_power_control(phUART, AM_HAL_SYSCTRL_WAKE, false));
Call the configuration function with configuration structure variable(defined above) as input parameter
CHECK_ERRORS(am_hal_uart_configure(phUART, &g_sUartConfig));
next you can call GPIO configuration function
am_hal_gpio_pinconfig(UART0_TX_PIN, uart0ConfigTx);
am_hal_gpio_pinconfig(UART0_RX_PIN, uart0ConfigRx);
then enable the UART interrupt
// Enable interrupts.
NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn));
This completes the configuration.
Now, we need a data transmission function.
Create a function which takes uint8_t type data array and data length as input parameters. Inside the function you need to declare and set parameters of uart transfer variable and then call am_hal_uart_transfer function as shown below:
// UART Send Data
void Uart0SendData(uint8_t *buffer, uint8_t bufferLen)
{
uint32_t ui32BytesWritten = 0;
// Write data to UART
const am_hal_uart_transfer_t sUartWrite =
{
.ui32Direction = AM_HAL_UART_WRITE,
.pui8Data = buffer,
.ui32NumBytes = bufferLen,
.ui32TimeoutMs = 10,
.pui32BytesTransferred = &ui32BytesWritten,
};
CHECK_ERRORS(am_hal_uart_transfer(phUART, &sUartWrite));
if (ui32BytesWritten != bufferLen)
{
// Couldn't send the whole data!!
while(1); // you can replace this with your own code to handle the error condition
}
}
in order to use send data function, you need to create a buffer and then pass it to the function:
uint8_t buf[10] = {0, 10, 23, 34, 45}; // array with dummy data
Uart0SendData(buf, 5); // send 5 bytes over UART0
for receiving data on interrupt, we need to create an ISR function
void am_uart_isr(void) is used for UART0 and void am_uart1_isr(void) is used for UART1.
This is defined in the startup_keil.s file, you can change the function name as per your wish.
Inside ISR function, you need to get the interrupt status which gives information about the type of interrupt, clear the interrupt and execute user code.
I hope it was easy for you to follow the article and now you will be able to uart with Apollo3 MCU.
I work as an embedded systems design consultant, helping companies build custom embedded products and develop test automation solutions for their PCBs.
If you have any feedback about the blog, you can share it in the comments below or contact me directly.