diff --git a/examples/peripherals/usb/host/cdc/cdc_acm_host/README.md b/examples/peripherals/usb/host/cdc/cdc_acm_host/README.md index 1b3f8dda60..bbd5836c76 100644 --- a/examples/peripherals/usb/host/cdc/cdc_acm_host/README.md +++ b/examples/peripherals/usb/host/cdc/cdc_acm_host/README.md @@ -5,22 +5,46 @@ (See the README.md file in the upper level 'examples' directory for more information about examples.) -This example shows how to use the CDC-ACM Host Driver to allow an ESP chip to communicate with a USB CDC-ACM device. +## 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. + +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 +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 ## How to use example ### Hardware Required -Two development boards with USB-OTG support. One will act as USB host and the other as USB device. +* Development board with USB-OTG support that will act as USB host +* USB CDC-ACM 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 connected with USB-Serial-JTAG + - Any other USB device that implements the CDC-ACM class #### Pin Assignment -Follow instruction 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. Build and flash [tusb_serial_device example](../../../device/tusb_serial_device) to USB device board. -2. Build this project and flash it to the USB host board, then run monitor tool to view serial output: +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 + +2. Connect the CDC device to the USB Host port + +3. 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 @@ -34,24 +58,50 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui ## Example Output -After the flashing you should see the output at idf monitor: +After flashing and connecting a CDC-ACM device, you should see output similar to the following in the idf monitor: ``` -... -I (256) USB-CDC: USB Host installed -I (256) USB-CDC: Opening CDC ACM device 0x303A:0x4001 -... -Device descriptor is printed here -... -I (1666) USB-CDC: Data received -I (1666) USB-CDC: 0x3ffc4c20 41 54 0d |AT.| -I (2666) USB-CDC: Data received -I (2666) USB-CDC: 0x3ffc4c20 41 54 2b 47 53 4e 0d |AT+GSN.| -I (3666) USB-CDC: Setting up line coding -I (3666) USB-CDC: Line Get: Rate: 115200, Stop bits: 0, Parity: 0, Databits: 8 -I (3666) USB-CDC: Line Set: Rate: 9600, Stop bits: 1, Parity: 1, Databits: 7 -I (3666) USB-CDC: Line Get: Rate: 9600, Stop bits: 1, Parity: 1, Databits: 7 -I (3676) Example finished successfully! -... +I (256) USB-CDC: Installing USB Host +I (256) USB-CDC: Installing CDC-ACM driver +I (256) USB-CDC: Opening CDC ACM device... +... +I (1174) USB-CDC: Data received +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. ``` + +## Troubleshooting + +### Device Not Detected + +If the CDC-ACM 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 +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) + +### No Data Received + +If data is sent but not received: + +1. **Check device connection:** Ensure the device is still connected and enumerated +2. **Verify device functionality:** Test the device with another host to confirm it's working +3. **Check line coding:** Some devices may require specific line coding settings before they start transmitting data +4. **Increase log level:** Set the log level to debug via `idf.py menuconfig` to get more detailed information + +### Line Coding Commands Not Supported + +If you see warnings like: +``` +W (xxx) USB-CDC: Line coding get not supported +W (xxx) USB-CDC: Control line state set not supported +``` + +This is normal for some CDC-ACM devices that don't support these optional commands. The example will continue to work for basic data transfer operations. diff --git a/examples/peripherals/usb/host/cdc/cdc_acm_host/main/idf_component.yml b/examples/peripherals/usb/host/cdc/cdc_acm_host/main/idf_component.yml index 7865f53578..395a39e7ef 100644 --- a/examples/peripherals/usb/host/cdc/cdc_acm_host/main/idf_component.yml +++ b/examples/peripherals/usb/host/cdc/cdc_acm_host/main/idf_component.yml @@ -1,4 +1,3 @@ ## IDF Component Manager Manifest File dependencies: - usb_host_cdc_acm: "2.*" - idf: ">=4.4" + usb_host_cdc_acm: "^2.1.1" diff --git a/examples/peripherals/usb/host/cdc/cdc_acm_host/main/usb_cdc_example_main.c b/examples/peripherals/usb/host/cdc/cdc_acm_host/main/usb_cdc_example_main.c index 49fca0709f..ff91f636d3 100644 --- a/examples/peripherals/usb/host/cdc/cdc_acm_host/main/usb_cdc_example_main.c +++ b/examples/peripherals/usb/host/cdc/cdc_acm_host/main/usb_cdc_example_main.c @@ -7,7 +7,6 @@ #include #include #include -#include "esp_system.h" #include "esp_log.h" #include "esp_err.h" @@ -19,9 +18,6 @@ #include "usb/cdc_acm_host.h" #define EXAMPLE_USB_HOST_PRIORITY (20) -#define EXAMPLE_USB_DEVICE_VID (0x303A) -#define EXAMPLE_USB_DEVICE_PID (0x4001) // 0x303A:0x4001 (TinyUSB CDC device) -#define EXAMPLE_USB_DEVICE_DUAL_PID (0x4002) // 0x303A:0x4002 (TinyUSB Dual CDC device) #define EXAMPLE_TX_STRING ("CDC test string!") #define EXAMPLE_TX_TIMEOUT_MS (1000) @@ -113,7 +109,7 @@ void app_main(void) 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, xTaskGetCurrentTaskHandle(), EXAMPLE_USB_HOST_PRIORITY, NULL); + 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"); @@ -131,16 +127,14 @@ void app_main(void) while (true) { cdc_acm_dev_hdl_t cdc_dev = NULL; - // Open USB device from tusb_serial_device example example. Either single or dual port configuration. - ESP_LOGI(TAG, "Opening CDC ACM device 0x%04X:0x%04X...", EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_PID); - esp_err_t err = cdc_acm_host_open(EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_PID, 0, &dev_config, &cdc_dev); + // 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, "Opening CDC ACM device 0x%04X:0x%04X...", EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_DUAL_PID); - err = cdc_acm_host_open(EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_DUAL_PID, 0, &dev_config, &cdc_dev); - if (ESP_OK != err) { - ESP_LOGI(TAG, "Failed to open device"); - continue; - } + 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)); @@ -149,27 +143,47 @@ void app_main(void) 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)); - // Test Line Coding commands: Get current line coding, change it 9600 7N1 and read again - ESP_LOGI(TAG, "Setting up line coding"); + 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; - ESP_ERROR_CHECK(cdc_acm_host_line_coding_get(cdc_dev, &line_coding)); - ESP_LOGI(TAG, "Line Get: Rate: %"PRIu32", Stop bits: %"PRIu8", Parity: %"PRIu8", Databits: %"PRIu8"", - line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits); + 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); - line_coding.dwDTERate = 9600; - line_coding.bDataBits = 7; - line_coding.bParityType = 1; - line_coding.bCharFormat = 1; - ESP_ERROR_CHECK(cdc_acm_host_line_coding_set(cdc_dev, &line_coding)); - ESP_LOGI(TAG, "Line Set: Rate: %"PRIu32", Stop bits: %"PRIu8", Parity: %"PRIu8", Databits: %"PRIu8"", - line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits); - - ESP_ERROR_CHECK(cdc_acm_host_line_coding_get(cdc_dev, &line_coding)); - ESP_LOGI(TAG, "Line Get: Rate: %"PRIu32", Stop bits: %"PRIu8", Parity: %"PRIu8", Databits: %"PRIu8"", - line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits); - - ESP_ERROR_CHECK(cdc_acm_host_set_control_line_state(cdc_dev, true, false)); + // 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.");