mirror of
https://github.com/espressif/esp-idf.git
synced 2026-06-04 20:26:38 +03:00
Merge branch 'refactor/usb_host_cdc_example' into 'master'
refactor: Merge USB Host CDC-ACM and CDC-VCP examples Closes IDF-11359 See merge request espressif/esp-idf!45589
This commit is contained in:
@@ -507,8 +507,7 @@ CDC-ACM
|
||||
"""""""
|
||||
|
||||
* A host class driver for the Communication Device Class (Abstract Control Model) is distributed as a managed component via the `ESP Component Registry <https://components.espressif.com/component/espressif/usb_host_cdc_acm>`__.
|
||||
* :example:`peripherals/usb/host/cdc/cdc_acm_host` demonstrates how to use the CDC-ACM Host Driver to enable communication between {IDF_TARGET_NAME} and a USB CDC-ACM device.
|
||||
* :example:`peripherals/usb/host/cdc/cdc_acm_vcp` demonstrates how to extend the CDC-ACM driver for Virtual Communication Port (VCP) devices like CP210x, FTDI FT23x or CH34x devices, and how to control the device and send data using the CDC-ACM API.
|
||||
* :example:`peripherals/usb/host/cdc` demonstrates how to use the CDC-ACM Host Driver to enable communication between {IDF_TARGET_NAME} and a USB CDC-ACM device, including vendor-specific devices such as CP210x, FTDI FT23x or CH34x.
|
||||
* The CDC-ACM driver is also used in `esp_modem examples <https://github.com/espressif/esp-protocols/tree/master/components/esp_modem/examples>`__, where it is used for communication with cellular modems.
|
||||
|
||||
MSC
|
||||
|
||||
@@ -425,8 +425,8 @@ USB 主机库事件
|
||||
|
||||
自动挂起定时器可以配置为以下几种模式:
|
||||
|
||||
- **单次** (:cpp:enumerator:`USB_HOST_LIB_PM_SUSPEND_ONE_SHOT`):定时器超时一次后停止。
|
||||
- **周期性** (:cpp:enumerator:`USB_HOST_LIB_PM_SUSPEND_PERIODIC`):定时器在每次超时后自动重启,无限重复。
|
||||
- **单次** (:cpp:enumerator:`USB_HOST_LIB_AUTO_SUSPEND_ONE_SHOT`):定时器超时一次后停止。
|
||||
- **周期性** (:cpp:enumerator:`USB_HOST_LIB_AUTO_SUSPEND_PERIODIC`):定时器在每次超时后自动重启,无限重复。
|
||||
|
||||
由传输提交触发自动恢复
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -469,7 +469,7 @@ USB 主机库事件
|
||||
|
||||
// 将自动挂起定时器设置为周期模式,周期为 1 秒,
|
||||
// 用于在无操作 1 秒后自动挂起设备,并在超时后自动重启
|
||||
usb_host_lib_set_auto_suspend(USB_HOST_LIB_PM_SUSPEND_PERIODIC, 1000);
|
||||
usb_host_lib_set_auto_suspend(USB_HOST_LIB_AUTO_SUSPEND_PERIODIC, 1000);
|
||||
|
||||
while (1) {
|
||||
uint32_t event_flags;
|
||||
@@ -507,8 +507,7 @@ CDC-ACM
|
||||
"""""""
|
||||
|
||||
* 通信设备 Class(抽象控制模型)的主机 Class 驱动程序通过 `乐鑫组件注册表 <https://components.espressif.com/component/espressif/usb_host_cdc_acm>`__ 作为受管理的组件分发。
|
||||
* 示例 :example:`peripherals/usb/host/cdc/cdc_acm_host` 演示了使用 CDC-ACM 主机驱动程序组件,实现 {IDF_TARGET_NAME} 与 USB CDC-ACM 设备的通信。
|
||||
* 示例 :example:`peripherals/usb/host/cdc/cdc_acm_vcp` 演示了如何扩展 CDC-ACM 的主机驱动程序,以支持 VCP 设备(即虚拟通信端口设备,如 CP210x、FTDI FT23x 或 CH34x),以及如何使用 CDC-ACM API 控制设备并发送数据。
|
||||
* 示例 :example:`peripherals/usb/host/cdc` 演示了如何使用 CDC-ACM 主机驱动程序,让 {IDF_TARGET_NAME} 与 USB CDC-ACM 设备通信,包括 CP210x、FTDI FT23x 或 CH34x 等厂商设备。
|
||||
* 示例 `esp_modem <https://github.com/espressif/esp-protocols/tree/master/components/esp_modem/examples>`__ 中也使用了 CDC-ACM 驱动程序,该程序在这些示例中与蜂窝模块通信。
|
||||
|
||||
MSC
|
||||
|
||||
@@ -7,4 +7,4 @@ cmake_minimum_required(VERSION 3.22)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(cdc_acm_vcp)
|
||||
project(cdc_host)
|
||||
@@ -1,46 +1,46 @@
|
||||
| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# USB CDC-ACM Host Driver Example
|
||||
# USB CDC Host Driver Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates how to use the [CDC-ACM Host Driver](https://components.espressif.com/components/espressif/usb_host_cdc_acm) to enable an ESP chip to communicate with a USB CDC-ACM (Communication Device Class - Abstract Control Model) device. CDC-ACM is a USB device class specification that allows USB devices to appear as serial ports, commonly used by USB-to-UART converters and virtual COM port devices.
|
||||
This example demonstrates how to use the [CDC-ACM Host Driver](https://components.espressif.com/components/espressif/usb_host_cdc_acm) together with VCP drivers to enable an ESP chip to communicate with USB CDC devices, including vendor-specific USB-to-UART converters (e.g., [CP210x](https://components.espressif.com/components/espressif/usb_host_cp210x_vcp), [FTDI FT23x](https://components.espressif.com/components/espressif/usb_host_ftdi_vcp), [CH34x](https://components.espressif.com/components/espressif/usb_host_ch34x_vcp)). CDC-ACM is a USB device class specification that allows USB devices to appear as serial ports, commonly used by USB-to-UART converters and virtual COM port devices.
|
||||
|
||||
The example performs the following operations:
|
||||
|
||||
1. Installs the USB Host Library and CDC-ACM driver
|
||||
2. Waits for a CDC-ACM device to be connected
|
||||
3. Opens the first available CDC-ACM device found
|
||||
2. Waits for CDC devices to be connected
|
||||
3. Opens the device using the appropriate driver based on VID/PID
|
||||
4. Prints the device descriptor information
|
||||
5. Sends test data to the device
|
||||
6. Receives data from the device (handled via callback)
|
||||
7. Demonstrates line coding commands (get/set baud rate, data bits, stop bits, parity)
|
||||
8. Demonstrates control line state commands (DTR/RTS)
|
||||
9. Waits for device disconnection and repeats the process
|
||||
9. Handles device disconnection and allows connecting another device
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* Development board with USB-OTG support that will act as USB host
|
||||
* USB CDC-ACM device. This can be:
|
||||
* USB CDC device. This can be:
|
||||
- A USB-to-UART converter (e.g., CP210x, FTDI FT23x, CH34x)
|
||||
- Another ESP development board configured as a USB serial device (see [tusb_serial_device example](../../../device/tusb_serial_device))
|
||||
- Another ESP development board configured as a USB serial device (see [tusb_serial_device example](../../device/tusb_serial_device))
|
||||
- Another ESP development board connected with USB-Serial-JTAG
|
||||
- Any other USB device that implements the CDC-ACM class
|
||||
|
||||
#### Pin Assignment
|
||||
|
||||
Follow instructions in [examples/usb/README.md](../../../README.md) for specific hardware setup.
|
||||
Follow instructions in [examples/usb/README.md](../../README.md) for specific hardware setup.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
1. Prepare the USB CDC device:
|
||||
- If using a USB-to-UART converter, no preparation is needed
|
||||
- If using another ESP board as a USB device, build and flash the [tusb_serial_device example](../../../device/tusb_serial_device) to that board first
|
||||
- If using another ESP board as a USB device, build and flash the [tusb_serial_device example](../../device/tusb_serial_device) to that board first
|
||||
|
||||
2. Connect the CDC device to the USB Host port
|
||||
|
||||
@@ -52,38 +52,42 @@ idf.py -p PORT flash monitor
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
(To exit the serial monitor, type ``Ctrl-]``. To stop the example, press the Boot button on the board.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
After flashing and connecting a CDC-ACM device, you should see output similar to the following in the idf monitor:
|
||||
After flashing and connecting a CDC device, you should see output similar to the following in the idf monitor:
|
||||
|
||||
```
|
||||
I (256) USB-CDC: Installing USB Host
|
||||
I (256) USB-CDC: Installing CDC-ACM driver
|
||||
I (256) USB-CDC: Opening CDC ACM device...
|
||||
I (256) usb_task: Running USB task
|
||||
I (256) usb_task: - Installing USB Host
|
||||
I (266) usb_task: - Installing CDC-ACM driver
|
||||
I (276) app_main: Waiting for CDC devices. Press Boot button to quit.
|
||||
I (584) USB-CDC: New CDC device connected VID=0x10C4 PID=0xEA60
|
||||
I (594) USB-CDC: CDC device opened (slot 0). Descriptor:
|
||||
|
||||
...
|
||||
I (1174) USB-CDC: Data received
|
||||
I (1154) USB-CDC: Testing data transmission
|
||||
I (1174) USB-CDC: - Data received (slot 0)
|
||||
I (1174) USB-CDC: 0x4ffbf640 43 44 43 20 74 65 73 74 20 73 74 72 69 6e 67 21 |CDC test string!|
|
||||
I (1274) USB-CDC: Testing control line state command
|
||||
I (1294) USB-CDC: - Control line state set to DTR=false, RTS=true
|
||||
I (1314) USB-CDC: Testing line coding commands
|
||||
I (1314) USB-CDC: - Line Coding Get: Rate: 115200, Stop bits: 0, Parity: 0, Databits: 8
|
||||
I (1314) USB-CDC: - Line Set: Rate: 115200, Stop bits: 0, Parity: 0, Databits: 8
|
||||
I (1314) USB-CDC: Example finished successfully! You can reconnect the device to run again.
|
||||
I (1314) USB-CDC: Example finished for device in slot 0. You can disconnect or connect another device.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Device Not Detected
|
||||
|
||||
If the CDC-ACM device is not detected, check:
|
||||
If the CDC device is not detected, check:
|
||||
|
||||
1. **USB connection:** Ensure the device is properly connected to the USB host port
|
||||
2. **Device compatibility:** Verify that the device implements the CDC-ACM class. Some USB-to-UART converters may use proprietary drivers
|
||||
2. **Device compatibility:** Verify that the device implements the CDC-ACM class or is a supported VCP device (CP210x/FTDI/CH34x). Some USB-to-UART converters may use proprietary drivers
|
||||
3. **Power supply:** Ensure the USB host port provides adequate power for the connected device
|
||||
4. **Cable quality:** Use a quality USB cable that supports data transfer (not charge-only cables)
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(cdc_acm_host)
|
||||
@@ -1,3 +0,0 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
usb_host_cdc_acm: "^2.1.1"
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "usb/usb_host.h"
|
||||
#include "usb/cdc_acm_host.h"
|
||||
|
||||
#define EXAMPLE_USB_HOST_PRIORITY (20)
|
||||
#define EXAMPLE_TX_STRING ("CDC test string!")
|
||||
#define EXAMPLE_TX_TIMEOUT_MS (1000)
|
||||
|
||||
static const char *TAG = "USB-CDC";
|
||||
static SemaphoreHandle_t device_disconnected_sem;
|
||||
|
||||
/**
|
||||
* @brief Data received callback
|
||||
*
|
||||
* @param[in] data Pointer to received data
|
||||
* @param[in] data_len Length of received data in bytes
|
||||
* @param[in] arg Argument we passed to the device open function
|
||||
* @return
|
||||
* true: We have processed the received data
|
||||
* false: We expect more data
|
||||
*/
|
||||
static bool handle_rx(const uint8_t *data, size_t data_len, void *arg)
|
||||
{
|
||||
ESP_LOGI(TAG, "Data received");
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, data, data_len, ESP_LOG_INFO);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Device event callback
|
||||
*
|
||||
* Apart from handling device disconnection it doesn't do anything useful
|
||||
*
|
||||
* @param[in] event Device event type and data
|
||||
* @param[in] user_ctx Argument we passed to the device open function
|
||||
*/
|
||||
static void handle_event(const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
|
||||
{
|
||||
switch (event->type) {
|
||||
case CDC_ACM_HOST_ERROR:
|
||||
ESP_LOGE(TAG, "CDC-ACM error has occurred, err_no = %i", event->data.error);
|
||||
break;
|
||||
case CDC_ACM_HOST_DEVICE_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Device suddenly disconnected");
|
||||
ESP_ERROR_CHECK(cdc_acm_host_close(event->data.cdc_hdl));
|
||||
xSemaphoreGive(device_disconnected_sem);
|
||||
break;
|
||||
case CDC_ACM_HOST_SERIAL_STATE:
|
||||
ESP_LOGI(TAG, "Serial state notif 0x%04X", event->data.serial_state.val);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unsupported CDC event: %d (possibly suspend/resume)", event->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB Host library handling task
|
||||
*
|
||||
* @param arg Unused
|
||||
*/
|
||||
static void usb_lib_task(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
// Start handling system events
|
||||
uint32_t event_flags;
|
||||
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
|
||||
ESP_ERROR_CHECK(usb_host_device_free_all());
|
||||
}
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
|
||||
ESP_LOGI(TAG, "USB: All devices freed");
|
||||
// Continue handling USB events to allow device reconnection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main application
|
||||
*
|
||||
* Here we open a USB CDC device and send some data to it
|
||||
*/
|
||||
void app_main(void)
|
||||
{
|
||||
device_disconnected_sem = xSemaphoreCreateBinary();
|
||||
assert(device_disconnected_sem);
|
||||
|
||||
// Install USB Host driver. Should only be called once in entire application
|
||||
ESP_LOGI(TAG, "Installing USB Host");
|
||||
const usb_host_config_t host_config = {
|
||||
.skip_phy_setup = false,
|
||||
.intr_flags = ESP_INTR_FLAG_LOWMED,
|
||||
};
|
||||
ESP_ERROR_CHECK(usb_host_install(&host_config));
|
||||
|
||||
// Create a task that will handle USB library events
|
||||
BaseType_t task_created = xTaskCreate(usb_lib_task, "usb_lib", 4096, NULL, EXAMPLE_USB_HOST_PRIORITY, NULL);
|
||||
assert(task_created == pdTRUE);
|
||||
|
||||
ESP_LOGI(TAG, "Installing CDC-ACM driver");
|
||||
ESP_ERROR_CHECK(cdc_acm_host_install(NULL));
|
||||
|
||||
const cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 1000,
|
||||
.out_buffer_size = 512,
|
||||
.in_buffer_size = 512,
|
||||
.user_arg = NULL,
|
||||
.event_cb = handle_event,
|
||||
.data_cb = handle_rx
|
||||
};
|
||||
|
||||
while (true) {
|
||||
cdc_acm_dev_hdl_t cdc_dev = NULL;
|
||||
|
||||
// Open any CDC-ACM device
|
||||
// This call always opens the first CDC-ACM device and first interface it finds
|
||||
ESP_LOGI(TAG, "Opening CDC ACM device...");
|
||||
esp_err_t err = cdc_acm_host_open(CDC_HOST_ANY_VID, CDC_HOST_ANY_PID, 0, &dev_config, &cdc_dev);
|
||||
if (ESP_OK != err) {
|
||||
ESP_LOGI(TAG, "Failed to open device");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000)); // To prevent infinite loop of failed attempts to open the device
|
||||
continue;
|
||||
}
|
||||
cdc_acm_host_desc_print(cdc_dev);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// Test sending and receiving: responses are handled in handle_rx callback
|
||||
ESP_ERROR_CHECK(cdc_acm_host_data_tx_blocking(cdc_dev, (const uint8_t *)EXAMPLE_TX_STRING, strlen(EXAMPLE_TX_STRING), EXAMPLE_TX_TIMEOUT_MS));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
ESP_LOGI(TAG, "Testing control line state command");
|
||||
err = cdc_acm_host_set_control_line_state(cdc_dev, false, false);
|
||||
if (ESP_ERR_NOT_SUPPORTED == err) {
|
||||
ESP_LOGW(TAG, "\t- Control line state set not supported");
|
||||
} else if (ESP_OK != err) {
|
||||
ESP_LOGE(TAG, "\t- Failed to set control line state");
|
||||
} else {
|
||||
// In case you connected ESP board with USB-Serial-JTAG, this procedure will reset the board
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
cdc_acm_host_set_control_line_state(cdc_dev, false, true);
|
||||
ESP_LOGI(TAG, "\t- Control line state set to DTR=false, RTS=true");
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
cdc_acm_host_set_control_line_state(cdc_dev, false, false);
|
||||
}
|
||||
|
||||
// Test Line Coding commands: Get current line coding and change it to 115200 8N1
|
||||
ESP_LOGI(TAG, "Testing line coding commands");
|
||||
|
||||
cdc_acm_line_coding_t line_coding;
|
||||
err = cdc_acm_host_line_coding_get(cdc_dev, &line_coding);
|
||||
if (ESP_ERR_NOT_SUPPORTED == err) {
|
||||
ESP_LOGW(TAG, "\t- Line coding get not supported");
|
||||
} else if (ESP_OK != err) {
|
||||
ESP_LOGE(TAG, "\t- Failed to get line coding");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "\t- Line Coding Get: Rate: %"PRIu32", Stop bits: %"PRIu8", Parity: %"PRIu8", Databits: %"PRIu8"",
|
||||
line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
|
||||
|
||||
// Set new line coding
|
||||
line_coding.dwDTERate = 115200;
|
||||
line_coding.bDataBits = 8;
|
||||
line_coding.bParityType = 0;
|
||||
line_coding.bCharFormat = 0;
|
||||
err = cdc_acm_host_line_coding_set(cdc_dev, &line_coding);
|
||||
if (ESP_OK != err) {
|
||||
ESP_LOGE(TAG, "\t- Failed to set line coding");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "\t- Line Set: Rate: %"PRIu32", Stop bits: %"PRIu8", Parity: %"PRIu8", Databits: %"PRIu8"",
|
||||
line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
|
||||
}
|
||||
}
|
||||
|
||||
// We are done. Wait for device disconnection and start over
|
||||
ESP_LOGI(TAG, "Example finished successfully! You can reconnect the device to run again.");
|
||||
xSemaphoreTake(device_disconnected_sem, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# USB CDC-ACM Virtual COM Port example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example shows how to extend CDC-ACM driver for Virtual Communication Port (VCP) devices, such as CP210x, FTDI FT23x or CH34x devices.
|
||||
|
||||
The drivers are fetched from [ESP Component Registry](https://components.espressif.com/) together with VCP service that automatically loads correct driver for plugged-in device.
|
||||
|
||||
## How to use example
|
||||
|
||||
1. Connect your USB<->UART converter to ESP board, the device will be automatically enumerated and correct driver will be loaded
|
||||
2. Change baudrate and other line coding parameters in [cdc_acm_vcp_example_main.cpp](main/cdc_acm_vcp_example_main.cpp) to match your needs
|
||||
3. Now you can use the usual CDC-ACM API to control the device and send data. Data are received in `handle_rx` callback
|
||||
4. Try disconnecting and then reconnecting of the USB device to experiment with USB hotplugging
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* Development board with USB-OTG support
|
||||
* A USB cable for Power supply and programming
|
||||
* Silicon Labs CP210x, FTDI FT23x or CP34x USB to UART converter
|
||||
|
||||
#### Pin Assignment
|
||||
|
||||
Follow instruction in [examples/usb/README.md](../../../README.md) for specific hardware setup.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build this project and flash it to the USB host board, then run monitor tool to view serial output:
|
||||
|
||||
```bash
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
@@ -1,4 +0,0 @@
|
||||
idf_component_register(
|
||||
SRCS "cdc_acm_vcp_example_main.cpp"
|
||||
INCLUDE_DIRS "."
|
||||
)
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "usb/cdc_acm_host.h"
|
||||
#include "usb/vcp_ch34x.hpp"
|
||||
#include "usb/vcp_cp210x.hpp"
|
||||
#include "usb/vcp_ftdi.hpp"
|
||||
#include "usb/vcp.hpp"
|
||||
#include "usb/usb_host.h"
|
||||
|
||||
using namespace esp_usb;
|
||||
|
||||
// Change these values to match your needs
|
||||
#define EXAMPLE_BAUDRATE (115200)
|
||||
#define EXAMPLE_STOP_BITS (0) // 0: 1 stopbit, 1: 1.5 stopbits, 2: 2 stopbits
|
||||
#define EXAMPLE_PARITY (0) // 0: None, 1: Odd, 2: Even, 3: Mark, 4: Space
|
||||
#define EXAMPLE_DATA_BITS (8)
|
||||
|
||||
namespace {
|
||||
static const char *TAG = "VCP example";
|
||||
static SemaphoreHandle_t device_disconnected_sem;
|
||||
|
||||
/**
|
||||
* @brief Data received callback
|
||||
*
|
||||
* Just pass received data to stdout
|
||||
*
|
||||
* @param[in] data Pointer to received data
|
||||
* @param[in] data_len Length of received data in bytes
|
||||
* @param[in] arg Argument we passed to the device open function
|
||||
* @return
|
||||
* true: We have processed the received data
|
||||
* false: We expect more data
|
||||
*/
|
||||
static bool handle_rx(const uint8_t *data, size_t data_len, void *arg)
|
||||
{
|
||||
printf("%.*s", data_len, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Device event callback
|
||||
*
|
||||
* Apart from handling device disconnection it doesn't do anything useful
|
||||
*
|
||||
* @param[in] event Device event type and data
|
||||
* @param[in] user_ctx Argument we passed to the device open function
|
||||
*/
|
||||
static void handle_event(const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
|
||||
{
|
||||
switch (event->type) {
|
||||
case CDC_ACM_HOST_ERROR:
|
||||
ESP_LOGE(TAG, "CDC-ACM error has occurred, err_no = %d", event->data.error);
|
||||
break;
|
||||
case CDC_ACM_HOST_DEVICE_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Device suddenly disconnected");
|
||||
xSemaphoreGive(device_disconnected_sem);
|
||||
break;
|
||||
case CDC_ACM_HOST_SERIAL_STATE:
|
||||
ESP_LOGI(TAG, "Serial state notif 0x%04X", event->data.serial_state.val);
|
||||
break;
|
||||
case CDC_ACM_HOST_NETWORK_CONNECTION:
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB Host library handling task
|
||||
*
|
||||
* @param arg Unused
|
||||
*/
|
||||
static void usb_lib_task(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
// Start handling system events
|
||||
uint32_t event_flags;
|
||||
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
|
||||
ESP_ERROR_CHECK(usb_host_device_free_all());
|
||||
}
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
|
||||
ESP_LOGI(TAG, "USB: All devices freed");
|
||||
// Continue handling USB events to allow device reconnection
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main application
|
||||
*
|
||||
* This function shows how you can use Virtual COM Port drivers
|
||||
*/
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
device_disconnected_sem = xSemaphoreCreateBinary();
|
||||
assert(device_disconnected_sem);
|
||||
|
||||
// Install USB Host driver. Should only be called once in entire application
|
||||
ESP_LOGI(TAG, "Installing USB Host");
|
||||
usb_host_config_t host_config = {};
|
||||
host_config.skip_phy_setup = false;
|
||||
host_config.intr_flags = ESP_INTR_FLAG_LOWMED;
|
||||
ESP_ERROR_CHECK(usb_host_install(&host_config));
|
||||
|
||||
// Create a task that will handle USB library events
|
||||
BaseType_t task_created = xTaskCreate(usb_lib_task, "usb_lib", 4096, NULL, 10, NULL);
|
||||
assert(task_created == pdTRUE);
|
||||
|
||||
ESP_LOGI(TAG, "Installing CDC-ACM driver");
|
||||
ESP_ERROR_CHECK(cdc_acm_host_install(NULL));
|
||||
|
||||
// Register VCP drivers to VCP service
|
||||
VCP::register_driver<FT23x>();
|
||||
VCP::register_driver<CP210x>();
|
||||
VCP::register_driver<CH34x>();
|
||||
|
||||
// Do everything else in a loop, so we can demonstrate USB device reconnections
|
||||
while (true) {
|
||||
const cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 5000, // 5 seconds, enough time to plug the device in or experiment with timeout
|
||||
.out_buffer_size = 512,
|
||||
.in_buffer_size = 512,
|
||||
.event_cb = handle_event,
|
||||
.data_cb = handle_rx,
|
||||
.user_arg = NULL,
|
||||
};
|
||||
|
||||
// You don't need to know the device's VID and PID. Just plug in any device and the VCP service will load correct (already registered) driver for the device
|
||||
ESP_LOGI(TAG, "Opening any VCP device...");
|
||||
auto vcp = std::unique_ptr<CdcAcmDevice>(VCP::open(&dev_config));
|
||||
|
||||
if (vcp == nullptr) {
|
||||
ESP_LOGI(TAG, "Failed to open VCP device");
|
||||
continue;
|
||||
}
|
||||
vTaskDelay(10);
|
||||
|
||||
ESP_LOGI(TAG, "Setting up line coding");
|
||||
cdc_acm_line_coding_t line_coding = {
|
||||
.dwDTERate = EXAMPLE_BAUDRATE,
|
||||
.bCharFormat = EXAMPLE_STOP_BITS,
|
||||
.bParityType = EXAMPLE_PARITY,
|
||||
.bDataBits = EXAMPLE_DATA_BITS,
|
||||
};
|
||||
ESP_ERROR_CHECK(vcp->line_coding_set(&line_coding));
|
||||
|
||||
/*
|
||||
Now the USB-to-UART converter is configured and receiving data.
|
||||
You can use standard CDC-ACM API to interact with it. E.g.
|
||||
|
||||
ESP_ERROR_CHECK(vcp->set_control_line_state(false, true));
|
||||
ESP_ERROR_CHECK(vcp->tx_blocking((uint8_t *)"Test string", 12));
|
||||
*/
|
||||
|
||||
// Send some dummy data
|
||||
ESP_LOGI(TAG, "Sending data through CdcAcmDevice");
|
||||
uint8_t data[] = "test_string";
|
||||
ESP_ERROR_CHECK(vcp->tx_blocking(data, sizeof(data)));
|
||||
ESP_ERROR_CHECK(vcp->set_control_line_state(true, true));
|
||||
|
||||
// We are done. Wait for device disconnection and start over
|
||||
ESP_LOGI(TAG, "Done. You can reconnect the VCP device to run again.");
|
||||
xSemaphoreTake(device_disconnected_sem, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
usb_host_ch34x_vcp: "^2"
|
||||
usb_host_cp210x_vcp: "^2"
|
||||
usb_host_ftdi_vcp: "^2"
|
||||
usb_host_vcp: "^1"
|
||||
idf: ">=5.1.0"
|
||||
13
examples/peripherals/usb/host/cdc/main/Kconfig.projbuild
Normal file
13
examples/peripherals/usb/host/cdc/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,13 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
|
||||
|
||||
config APP_QUIT_PIN
|
||||
int "APP Quit button GPIO pin"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
|
||||
default 35 if IDF_TARGET_ESP32P4
|
||||
default 0
|
||||
help
|
||||
GPIO pin number to be used as APP_QUIT button.
|
||||
|
||||
endmenu
|
||||
6
examples/peripherals/usb/host/cdc/main/idf_component.yml
Normal file
6
examples/peripherals/usb/host/cdc/main/idf_component.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
usb_host_cdc_acm: "^2.3"
|
||||
usb_host_ch34x_vcp: "^2.2"
|
||||
usb_host_cp210x_vcp: "^2.2"
|
||||
usb_host_ftdi_vcp: "^2.1"
|
||||
407
examples/peripherals/usb/host/cdc/main/usb_cdc_example_main.c
Normal file
407
examples/peripherals/usb/host/cdc/main/usb_cdc_example_main.c
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <assert.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "usb/cdc_host_types.h"
|
||||
#include "usb/usb_host.h"
|
||||
#include "usb/cdc_acm_host.h"
|
||||
#include "usb/vcp_ch34x.h"
|
||||
#include "usb/vcp_cp210x.h"
|
||||
#include "usb/vcp_ftdi.h"
|
||||
|
||||
#define EXAMPLE_USB_HOST_PRIORITY (20)
|
||||
#define EXAMPLE_TX_STRING ("CDC test string!")
|
||||
#define EXAMPLE_TX_TIMEOUT_MS (1000)
|
||||
#define MAX_CDC_DEVICES (5)
|
||||
#define ESPRESSIF_VID (0x303A) // 0x303A Espressif VID, used in TinyUSB devices or in USB-Serial-JTAG devices
|
||||
#define APP_QUIT_PIN CONFIG_APP_QUIT_PIN
|
||||
|
||||
static const char *TAG = "USB-CDC";
|
||||
|
||||
/** Open CDC device handles; NULL means slot is free. Needed for APP_QUIT (close all) and to clear slot on disconnect. */
|
||||
static cdc_acm_dev_hdl_t cdc_devices[MAX_CDC_DEVICES] = {0};
|
||||
|
||||
/**
|
||||
* @brief Application queue and its message IDs
|
||||
*/
|
||||
static QueueHandle_t app_queue;
|
||||
typedef struct {
|
||||
enum {
|
||||
APP_QUIT, /**< Request to exit: uninstall CDC driver and USB host lib */
|
||||
APP_DEVICE_CONNECTED, /**< New USB CDC device connected */
|
||||
APP_DEVICE_DISCONNECTED, /**< CDC device disconnected */
|
||||
} id;
|
||||
union {
|
||||
struct {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
} new_dev; /**< VID/PID for APP_DEVICE_CONNECTED */
|
||||
int device_slot; /**< Slot for APP_DEVICE_DISCONNECTED */
|
||||
} data;
|
||||
} app_message_t;
|
||||
|
||||
/**
|
||||
* @brief Find a free slot in the device table.
|
||||
*/
|
||||
static inline int find_free_slot(void)
|
||||
{
|
||||
for (int i = 0; i < MAX_CDC_DEVICES; i++) {
|
||||
if (cdc_devices[i] == NULL) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Data received callback
|
||||
*
|
||||
* @param[in] data Pointer to received data
|
||||
* @param[in] data_len Length of received data in bytes
|
||||
* @param[in] arg Argument we passed to the device open function
|
||||
* @return
|
||||
* true: We have processed the received data
|
||||
* false: We expect more data
|
||||
*/
|
||||
static bool handle_rx(const uint8_t *data, size_t data_len, void *arg)
|
||||
{
|
||||
int slot = (int)arg;
|
||||
ESP_LOGI(TAG, "\t- Data received (slot %d)", slot);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, data, data_len, ESP_LOG_INFO);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Device event callback
|
||||
*
|
||||
* Forwards disconnection to app queue
|
||||
*
|
||||
* @param[in] event Device event type and data
|
||||
* @param[in] user_ctx Argument we passed to the device open function
|
||||
*/
|
||||
static void handle_event(const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
|
||||
{
|
||||
switch (event->type) {
|
||||
case CDC_ACM_HOST_ERROR:
|
||||
ESP_LOGE(TAG, "CDC-ACM error has occurred, err_no = %i", event->data.error);
|
||||
break;
|
||||
case CDC_ACM_HOST_DEVICE_DISCONNECTED:
|
||||
if (app_queue) {
|
||||
app_message_t msg = {
|
||||
.id = APP_DEVICE_DISCONNECTED,
|
||||
.data.device_slot = (int)(intptr_t)user_ctx,
|
||||
};
|
||||
xQueueSend(app_queue, &msg, 0);
|
||||
} else {
|
||||
ESP_ERROR_CHECK(cdc_acm_host_close(event->data.cdc_hdl));
|
||||
}
|
||||
break;
|
||||
case CDC_ACM_HOST_SERIAL_STATE:
|
||||
ESP_LOGI(TAG, "Serial state notif 0x%04X", event->data.serial_state.val);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unsupported CDC event: %d (possibly suspend/resume)", event->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief New USB device callback
|
||||
*
|
||||
* Gets VID/PID and posts APP_DEVICE_CONNECTED to app queue.
|
||||
* Called from USB Host context; device is closed after this callback returns.
|
||||
*
|
||||
* @param[in] usb_dev USB device handle
|
||||
*/
|
||||
static void new_dev_cb(usb_device_handle_t usb_dev)
|
||||
{
|
||||
const usb_device_desc_t *device_desc;
|
||||
esp_err_t err = usb_host_get_device_descriptor(usb_dev, &device_desc);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "usb_host_get_device_descriptor failed: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t vid = device_desc->idVendor;
|
||||
uint16_t pid = device_desc->idProduct;
|
||||
ESP_LOGI(TAG, "New CDC device connected VID=0x%04X PID=0x%04X", vid, pid);
|
||||
|
||||
if (app_queue) {
|
||||
app_message_t msg = {
|
||||
.id = APP_DEVICE_CONNECTED,
|
||||
.data.new_dev.vid = vid,
|
||||
.data.new_dev.pid = pid,
|
||||
};
|
||||
xQueueSend(app_queue, &msg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open CDC device by VID/PID using the appropriate driver.
|
||||
*/
|
||||
static cdc_acm_dev_hdl_t example_cdc_open(uint16_t vid, uint16_t pid,
|
||||
const cdc_acm_host_device_config_t *dev_config)
|
||||
{
|
||||
cdc_acm_dev_hdl_t cdc_dev = NULL;
|
||||
esp_err_t err;
|
||||
|
||||
switch (vid) {
|
||||
case FTDI_VID:
|
||||
err = ftdi_vcp_open(pid, 0, dev_config, &cdc_dev);
|
||||
break;
|
||||
case NANJING_QINHENG_MICROE_VID:
|
||||
err = ch34x_vcp_open(pid, 0, dev_config, &cdc_dev);
|
||||
break;
|
||||
case SILICON_LABS_VID:
|
||||
err = cp210x_vcp_open(pid, 0, dev_config, &cdc_dev);
|
||||
break;
|
||||
case ESPRESSIF_VID:
|
||||
default:
|
||||
err = cdc_acm_host_open(vid, pid, 0, dev_config, &cdc_dev);
|
||||
break;
|
||||
}
|
||||
|
||||
if (err == ESP_OK) {
|
||||
return cdc_dev;
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "Failed to open device VID=0x%04X PID=0x%04X", vid, pid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void free_cdc_device(int slot)
|
||||
{
|
||||
if (slot < 0 || slot >= MAX_CDC_DEVICES || cdc_devices[slot] == NULL) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "\t- Closing CDC device in slot %d", slot);
|
||||
cdc_acm_host_close(cdc_devices[slot]);
|
||||
cdc_devices[slot] = NULL;
|
||||
}
|
||||
|
||||
static void free_all_cdc_devices(void)
|
||||
{
|
||||
for (int i = 0; i < MAX_CDC_DEVICES; i++) {
|
||||
if (cdc_devices[i] != NULL) {
|
||||
free_cdc_device(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Run CDC demo (print descriptor, tx, control line, line coding) for one device.
|
||||
*/
|
||||
static void run_cdc_demo(int slot)
|
||||
{
|
||||
cdc_acm_dev_hdl_t cdc_dev = cdc_devices[slot];
|
||||
|
||||
ESP_LOGI(TAG, "CDC device opened (slot %d). Descriptor:", slot);
|
||||
cdc_acm_host_desc_print(cdc_dev);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
ESP_LOGI(TAG, "Testing data transmission");
|
||||
ESP_ERROR_CHECK(cdc_acm_host_data_tx_blocking(cdc_dev, (const uint8_t *)EXAMPLE_TX_STRING,
|
||||
strlen(EXAMPLE_TX_STRING), EXAMPLE_TX_TIMEOUT_MS));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
ESP_LOGI(TAG, "Testing control line state command");
|
||||
esp_err_t err = cdc_acm_host_set_control_line_state(cdc_dev, false, false);
|
||||
if (err == ESP_ERR_NOT_SUPPORTED) {
|
||||
ESP_LOGW(TAG, "\t- Control line state set not supported");
|
||||
} else if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "\t- Failed to set control line state");
|
||||
} else {
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
cdc_acm_host_set_control_line_state(cdc_dev, false, true);
|
||||
ESP_LOGI(TAG, "\t- Control line state set to DTR=false, RTS=true");
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
cdc_acm_host_set_control_line_state(cdc_dev, false, false);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Testing line coding commands");
|
||||
cdc_acm_line_coding_t line_coding;
|
||||
err = cdc_acm_host_line_coding_get(cdc_dev, &line_coding);
|
||||
if (err == ESP_ERR_NOT_SUPPORTED) {
|
||||
ESP_LOGW(TAG, "\t- Line coding get not supported");
|
||||
} else if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "\t- Failed to get line coding");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "\t- Line Coding Get: Rate: %"PRIu32", Stop bits: %"PRIu8", Parity: %"PRIu8", Databits: %"PRIu8,
|
||||
line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
|
||||
line_coding.dwDTERate = 115200;
|
||||
line_coding.bDataBits = 8;
|
||||
line_coding.bParityType = 0;
|
||||
line_coding.bCharFormat = 0;
|
||||
err = cdc_acm_host_line_coding_set(cdc_dev, &line_coding);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "\t- Failed to set line coding");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "\t- Line Set: Rate: %"PRIu32", Stop bits: %"PRIu8", Parity: %"PRIu8", Databits: %"PRIu8,
|
||||
line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Example finished for device in slot %d. You can disconnect or connect another device.", slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Boot button pressed callback - send APP_QUIT to front of queue.
|
||||
*/
|
||||
static void gpio_cb(void *arg)
|
||||
{
|
||||
BaseType_t xTaskWoken = pdFALSE;
|
||||
app_message_t message = {
|
||||
.id = APP_QUIT,
|
||||
};
|
||||
|
||||
if (app_queue) {
|
||||
xQueueSendToFrontFromISR(app_queue, &message, &xTaskWoken);
|
||||
}
|
||||
|
||||
if (xTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB Host library handling task.
|
||||
*/
|
||||
static void usb_lib_task(void *arg)
|
||||
{
|
||||
ESP_LOGI("usb_task", "Running USB task");
|
||||
const usb_host_config_t host_config = {
|
||||
.skip_phy_setup = false,
|
||||
.intr_flags = ESP_INTR_FLAG_LOWMED,
|
||||
};
|
||||
ESP_LOGI("usb_task", "\t- Installing USB Host");
|
||||
ESP_ERROR_CHECK(usb_host_install(&host_config));
|
||||
|
||||
const cdc_acm_host_driver_config_t driver_config = {
|
||||
.driver_task_stack_size = 4096,
|
||||
.driver_task_priority = EXAMPLE_USB_HOST_PRIORITY + 1,
|
||||
.xCoreID = 0,
|
||||
.new_dev_cb = new_dev_cb,
|
||||
};
|
||||
ESP_LOGI("usb_task", "\t- Installing CDC-ACM driver");
|
||||
ESP_ERROR_CHECK(cdc_acm_host_install(&driver_config));
|
||||
|
||||
xTaskNotifyGive(arg); // Notify the main task that the USB host is installed
|
||||
|
||||
bool has_clients = true; // We installed CDC-ACM driver, so we have clients
|
||||
while (1) {
|
||||
uint32_t event_flags;
|
||||
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
|
||||
has_clients = false;
|
||||
if (ESP_OK == usb_host_device_free_all()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
|
||||
if (!has_clients) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
ESP_ERROR_CHECK(usb_host_uninstall());
|
||||
ESP_LOGI("usb_task", "USB Host task completed");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
app_queue = xQueueCreate(10, sizeof(app_message_t));
|
||||
assert(app_queue);
|
||||
|
||||
BaseType_t task_created = xTaskCreate(usb_lib_task, "usb_lib", 4096, xTaskGetCurrentTaskHandle(),
|
||||
EXAMPLE_USB_HOST_PRIORITY, NULL);
|
||||
assert(task_created == pdTRUE);
|
||||
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
const gpio_config_t input_pin = {
|
||||
.pin_bit_mask = BIT64(APP_QUIT_PIN),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.intr_type = GPIO_INTR_NEGEDGE,
|
||||
};
|
||||
ESP_ERROR_CHECK(gpio_config(&input_pin));
|
||||
ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LOWMED));
|
||||
ESP_ERROR_CHECK(gpio_isr_handler_add(APP_QUIT_PIN, gpio_cb, NULL));
|
||||
|
||||
cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 0,
|
||||
.out_buffer_size = 512,
|
||||
.in_buffer_size = 0,
|
||||
.user_arg = NULL,
|
||||
.event_cb = handle_event,
|
||||
.data_cb = handle_rx
|
||||
};
|
||||
|
||||
ESP_LOGI("app_main", "Waiting for CDC devices. Press Boot button to quit.");
|
||||
|
||||
bool running = true;
|
||||
while (running) {
|
||||
app_message_t msg;
|
||||
xQueueReceive(app_queue, &msg, portMAX_DELAY);
|
||||
|
||||
switch (msg.id) {
|
||||
case APP_DEVICE_CONNECTED: {
|
||||
int slot = find_free_slot();
|
||||
if (slot < 0) {
|
||||
ESP_LOGW("app_main", "No free slots for new CDC device (max %d)", MAX_CDC_DEVICES);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_config.user_arg = (void *)(intptr_t)slot;
|
||||
cdc_acm_dev_hdl_t cdc_dev = example_cdc_open(msg.data.new_dev.vid, msg.data.new_dev.pid, &dev_config);
|
||||
if (cdc_dev == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cdc_devices[slot] = cdc_dev;
|
||||
run_cdc_demo(slot);
|
||||
break;
|
||||
}
|
||||
|
||||
case APP_DEVICE_DISCONNECTED: {
|
||||
ESP_LOGI("app_main", "Device disconnected from slot %d", msg.data.device_slot);
|
||||
free_cdc_device(msg.data.device_slot);
|
||||
break;
|
||||
}
|
||||
|
||||
case APP_QUIT: {
|
||||
ESP_LOGI("app_main", "Exiting example");
|
||||
free_all_cdc_devices();
|
||||
ESP_ERROR_CHECK(cdc_acm_host_uninstall());
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGW("app_main", "Unknown message ID: %d", msg.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI("app_main", "\t- Exit completed");
|
||||
gpio_isr_handler_remove(APP_QUIT_PIN);
|
||||
gpio_uninstall_isr_service();
|
||||
vQueueDelete(app_queue);
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_USB_HOST_HUBS_SUPPORTED=y
|
||||
Reference in New Issue
Block a user