UART async adapter

UART async adapter library works as an interface between interrupt-driven API of a UART device and software that is using the asynchronous API interface.


The current implementation is experimental.


Zephyr provides the following three different ways to access a UART peripheral:

  • Pooling API

  • Interrupt-driven API

  • Asynchronous API

While most of the UART drivers provide all three APIs, some drivers still do not provide the asynchronous UART API. An example of such a driver is USB CDC ACM. The UART async adapter library is initialized with a UART device and communicates with it using the interrupt-driven API, providing an asynchronous API for the application.

This removes the need to implement two ways of interfacing with UART devices in software. When using the UART async adapter library, the software only needs to implement interaction with a UART device using the asynchronous API and just initialize the adapter for the ones that do not support it.


To use the library, you need to enable the CONFIG_UART_ASYNC_API and CONFIG_UART_INTERRUPT_DRIVEN Kconfig options.


Use the CONFIG_UART_ASYNC_ADAPTER Kconfig option to enable the library in the build system.


See the following code snippet to learn how to use this library:

#include <uart_async_adapter.h>

/* Get the UART device we want to use */
static const struct device *uart = DEVICE_DT_GET([UART node identifier]);

/* Create UART async adapter instance */

/* UART initialization (called before any UART usage) */
static int uart_init(void)
    if (!uart_test_async_api(uart)) {
            /* Implement API adapter */
            uart_async_adapter_init(async_adapter, uart);
            uart = async_adapter;
    /* Continue initialization using asynchronous API on uart device */


When using the library in the way shown in the code snippet, it is totally transparent to the application.

If the selected UART device provides the asynchronous API, the adapter is not initialized. If the selected UART device does not provide the asynchronous API, the adapter is initialized to use such a device and a direct pointer to the device is replaced by the adapter.

Samples using the library

The following nRF Connect SDK sample use this library:


Using this library adds code and performance overhead over direct usage of UART asynchronous API provided by the driver. For UART drivers that only provide the interrupt-driven API, consider using it directly in the application. The library allows using UART devices with different APIs with only one API in the application, speeding up the development process.


This module may use Logging.

API documentation

Header file: include/uart_async_adapter.h
Source files: subsys/uart_async_adapter/
group uart_async_adapter

UART asynchronous API universal adapter.

This module acts as an adapter between UART interrupt and async interface.


The UART async API adapter implementation is experimental. It means it is not guaranteed to work in any corner situation.



The name of the data instance connected with created device instance.

  • _dev_name – The name of the created device instance


The macro that creates and instance of the UART async adapter.

  • _dev – The name of the created device instance


void uart_async_adapter_init(const struct device *dev, const struct device *target)

Initialize adapter.

Call this function before uart adapter is used. The function configures connected UART device to work with the adapter.

  • dev – The adapter interface

  • target – Target UART device with only interrupt interface


const struct uart_driver_api uart_async_adapter_driver_api

Driver API for async adapter.

The API of the UART async adapter uses standard UART API structure.

struct uart_async_adapter_data
#include <uart_async_adapter.h>

UART asynch adapter data structure.

The data used by asynch adapter.

Public Members

const struct device *target

Target device pointer

uart_callback_t user_callback

User callback function for synchronous interface

void *user_data

Pointer to the user data

struct k_spinlock lock

Lock for the data that requires it

struct uart_async_adapter_data_rx
#include <uart_async_adapter.h>

Data used for output transmission

Public Members

const uint8_t *buf

The original buffer pointer set when data transfer was requested

const uint8_t *curr_buf

Current buffer position

volatile size_t size_left

Number of data left in the current buffer

struct k_timer timeout_timer

Timer used for timeout

bool enabled

Tx state

struct uart_async_adapter_data_tx
#include <uart_async_adapter.h>

Data used for input transmission

Public Members

uint8_t *buf

Base buffer pointer used now for data reception

uint8_t *curr_buf

Current position to write data into

uint8_t *last_notify_buf

Last position of the notified buffer

size_t size_left

Number of bytes left in the current buffer

uint8_t *next_buf

Buffer prepared for the next transfer

size_t next_buf_len

The size of the buffer for the next transfer

int32_t timeout

Timeout set by the user

struct k_timer timeout_timer

Timer used for timeout

bool enabled

RX state