-
Notifications
You must be signed in to change notification settings - Fork 8k
doc: connectivity: usb: add initial CDC ACM documentation #96716
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
Open
jfischer-no
wants to merge
1
commit into
zephyrproject-rtos:main
Choose a base branch
from
jfischer-no:pr-device_next-doc
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+168
−66
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
.. _usbd_cdc_acm: | ||
|
||
USB device CDC ACM | ||
################## | ||
|
||
The CDC ACM function provided by the USB device stack only implements Abstract | ||
Control Model Serial Emulation. Its sole purpose is to emulate serial lines, as | ||
its name suggests. Most modern operating systems should provide support | ||
for it out of the box. | ||
|
||
The CDC ACM function is represented as a serial interface on both the host and | ||
device sides, while the user or application interface is the :ref:`uart_api` | ||
driver API. This allows applications that already use the UART API to use the | ||
serial interface provided by the CDC ACM function without changing the code | ||
responsible for data communication. Only additional configuration and USB | ||
device stack initialization are required. | ||
|
||
CDC ACM UART configuration | ||
========================== | ||
|
||
Like the real UART controller, the virtual CDC ACM UART is described in the | ||
device tree. The devicetree compatible property for CDC ACM UART is | ||
:dtcompatible:`zephyr,cdc-acm-uart`. | ||
|
||
CDC ACM support is automatically selected when USB device support is enabled | ||
and a compatible node in the devicetree sources is present. If necessary, CDC ACM | ||
support can be explicitly disabled by :kconfig:option:`CONFIG_USBD_CDC_ACM_CLASS`. | ||
The number of possible CDC ACM instances depends on the number of supported | ||
endpoints on the USB device controller. | ||
The CDC ACM node can use the label property to distinguish different interfaces | ||
on the host side. Below is an example of the devicetree overlay file. | ||
|
||
.. code-block:: devicetree | ||
|
||
&zephyr_udc0 { | ||
cdc_acm_uart0: cdc_acm_uart0 { | ||
compatible = "zephyr,cdc-acm-uart"; | ||
label = "CDC_ACM_0"; | ||
}; | ||
}; | ||
|
||
Before the application uses CDC ACM UART, it may want to wait for the DTR | ||
signal. Please refer to :zephyr:code-sample:`usb-cdc-acm` on how to implement | ||
this functionality. | ||
|
||
.. note:: | ||
To communicate with the host, beside the UART configuration, the application | ||
requires to enable USB device stack, for that please refer to | ||
:ref:`usb_device_next_howto_configure` and read carefully the next chapter. For | ||
users and applications migrating from the legacy stack, this is the only part | ||
they need to adapt. | ||
|
||
.. _cdc_acm_uart_as_serial_backend: | ||
|
||
CDC ACM UART as serial backend | ||
============================== | ||
|
||
With the example from above and ``zephyr,console`` property of the chosen node, | ||
we can describe that CDC ACM UART is to be used with the console. | ||
|
||
.. code-block:: devicetree | ||
|
||
/ { | ||
chosen { | ||
zephyr,console = &cdc_acm_uart0; | ||
}; | ||
}; | ||
|
||
&zephyr_udc0 { | ||
cdc_acm_uart0: cdc_acm_uart0 { | ||
compatible = "zephyr,cdc-acm-uart"; | ||
label = "CDC_ACM_0"; | ||
}; | ||
}; | ||
|
||
In the same way that the console in the above example is configured to use the | ||
CDC ACM UART, the chosen property, ``zephyr,shell-uart``, can be used to | ||
configure the shell to use the CDC ACM UART as the serial backend. See | ||
sample :zephyr:code-sample:`shell-module` and :ref:`chosen nodes documentation | ||
<devicetree-chosen-nodes>`. | ||
|
||
Since the use case as a serial backend is very common and no configuration is | ||
necessary at runtime for the CDC ACM UART, the stack offers a helper that | ||
performs the steps described in :ref:`usb_device_next_howto_configure`. The | ||
helper is enabled by the :kconfig:option:`CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT` | ||
and initializes the USB device stack with a single CDC ACM instance. Sample | ||
:zephyr:code-sample:`usb-cdc-acm-console` demonstrates how to use it. | ||
|
||
:kconfig:option:`CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT` should also be used | ||
by the boards like :zephyr:board:`nrf52840dongle`, which do not have a debug | ||
adapter but a USB device controller, and wants to use CDC ACM UART as default | ||
serial backend for logging and shell. | ||
As the configuration would be identical for any board, there are common | ||
:zephyr_file:`devicetree file <boards/common/usb/cdc_acm_serial.dtsi>` and | ||
:zephyr_file:`Kconfig file <boards/common/usb/Kconfig.cdc_acm_serial.defconfig>` | ||
that must be included in the board's devicetree and Kconfig.defconfig files. | ||
Comment on lines
+82
to
+96
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about #94748? |
||
|
||
Using CDC ACM UART in the application | ||
===================================== | ||
|
||
CDC ACM implements a virtual UART controller and provides Interrupt-driven UART | ||
API and Polling UART API. The ASYNC API is not supported yet. If the | ||
application wants to communicate over CDC ACM UART, the preferable way is to | ||
use Interrupt-driven UART API. It is essential to understand API documentation, | ||
nevertheless, some notes below. | ||
|
||
Interrupt-driven UART API | ||
------------------------- | ||
|
||
Internally the CDC ACM UART 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, application 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add something like: