Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

usb: device_next: align CDC ACM UART with Interrupt-driven UART API #75439

Merged
116 changes: 91 additions & 25 deletions doc/connectivity/usb/device_next/usb_device.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,6 @@ classes and provides an API to implement custom USB functions.
The new USB device support is considered experimental and will replace
:ref:`usb_device_stack`.

Built-in functions
==================

The USB device stack has built-in USB functions. Some can be used directly in
the user application through a special API, such as HID or Audio class devices,
while others use a general Zephyr RTOS driver API, such as MSC and CDC class
implementations. The *Identification string* identifies a class or function
instance (``n``) and is used as an argument to the :c:func:`usbd_register_class`.

+-----------------------------------+-------------------------+-------------------------+
| Class or function | User API (if any) | Identification string |
+===================================+=========================+=========================+
| USB Audio 2 class | :ref:`uac2_device` | :samp:`uac2_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| USB CDC ACM class | :ref:`uart_api` | :samp:`cdc_acm_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| USB CDC ECM class | Ethernet device | :samp:`cdc_ecm_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| USB Mass Storage Class (MSC) | :ref:`usbd_msc_device` | :samp:`msc_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| USB Human Interface Devices (HID) | :ref:`usbd_hid_device` | :samp:`hid_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| Bluetooth HCI USB transport layer | :ref:`bt_hci_raw` | :samp:`bt_hci_{n}` |
+-----------------------------------+-------------------------+-------------------------+

Samples
=======

Expand Down Expand Up @@ -223,3 +198,94 @@ for this capability.
:dedent:
:start-after: doc device msg-cb start
:end-before: doc device msg-cb end

Built-in functions
******************

The USB device stack has built-in USB functions. Some can be used directly in
the user application through a special API, such as HID or Audio class devices,
while others use a general Zephyr RTOS driver API, such as MSC and CDC class
implementations. The *Identification string* identifies a class or function
instance (``n``) and is used as an argument to the :c:func:`usbd_register_class`.

+-----------------------------------+-------------------------+-------------------------+
| Class or function | User API (if any) | Identification string |
+===================================+=========================+=========================+
| USB Audio 2 class | :ref:`uac2_device` | :samp:`uac2_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| USB CDC ACM class | :ref:`uart_api` | :samp:`cdc_acm_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| USB CDC ECM class | Ethernet device | :samp:`cdc_ecm_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| USB Mass Storage Class (MSC) | :ref:`usbd_msc_device` | :samp:`msc_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| USB Human Interface Devices (HID) | :ref:`usbd_hid_device` | :samp:`hid_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| Bluetooth HCI USB transport layer | :ref:`bt_hci_raw` | :samp:`bt_hci_{n}` |
+-----------------------------------+-------------------------+-------------------------+

CDC ACM UART
============

CDC ACM implements a virtual UART controller and provides Interrupt-driven UART
API and Polling UART API.

Interrupt-driven UART API
-------------------------

Internally the implementation uses two ringbuffers, these take over the
function of the TX/RX FIFOs (TX/RX buffers) from the :ref:`uart_interrupt_api`.

As described in the :ref:`uart_interrupt_api`, the functions
:c:func:`uart_irq_update()`, :c:func:`uart_irq_is_pending`,
:c:func:`uart_irq_rx_ready()`, :c:func:`uart_irq_tx_ready()`
:c:func:`uart_fifo_read()`, and :c:func:`uart_fifo_fill()`
should be called from the interrupt handler, see
:c:func:`uart_irq_callback_user_data_set()`. To prevent undefined behaviour,
the implementation of these functions checks in what context they are called
and fails if it is not an interrupt handler.

Also, as described in the UART API, :c:func:`uart_irq_is_pending`
:c:func:`uart_irq_rx_ready()`, and :c:func:`uart_irq_tx_ready()`
can only be called after :c:func:`uart_irq_update()`.

Simplified, the interrupt handler should look something like:

.. code-block:: c

static void interrupt_handler(const struct device *dev, void *user_data)
{
while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
if (uart_irq_rx_ready(dev)) {
int len;
int n;

/* ... */
n = uart_fifo_read(dev, buffer, len);
/* ... */
}

if (uart_irq_tx_ready(dev)) {
int len;
int n;

/* ... */
n = uart_fifo_fill(dev, buffer, len);
/* ... */
}
}

All these functions are not directly dependent on the status of the USB device.
Filling the TX FIFO does not mean that data is being sent to the host. And
successfully reading the RX FIFO does not mean that the device is still
connected to the host. If there is space in the TX FIFO, and the TX interrupt
is enabled, :c:func:`uart_irq_tx_ready()` will succeed. If there is data in the
RX FIFO, and the RX interrupt is enabled, :c:func:`uart_irq_rx_ready()` will
succeed. Function :c:func:`uart_irq_tx_complete()` is not implemented yet.

Polling UART API
----------------

The CDC ACM poll out implementation follows :ref:`uart_polling_api` and
blocks when the TX FIFO is full only if the hw-flow-control property is enabled
and called from a non-ISR context.
Loading
Loading