diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 6e453aa85..305336d4f 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -496,6 +496,17 @@ build_example_usb_host_usb_cdc_4g_module: variables: EXAMPLE_DIR: examples/usb/host/usb_cdc_4g_module +build_example_usb_host_usb_cdc_basic: + extends: + - .build_examples_template + - .rules:build:example_usb_host_usb_cdc_basic + parallel: + matrix: + - IMAGE: espressif/idf:release-v4.4 + - IMAGE: espressif/idf:release-v5.1 + variables: + EXAMPLE_DIR: examples/usb/host/usb_cdc_basic + build_example_utilities_xz_decompress_file: extends: - .build_examples_template diff --git a/.gitlab/ci/rules.yml b/.gitlab/ci/rules.yml index 4c8286f96..d0ebcc659 100644 --- a/.gitlab/ci/rules.yml +++ b/.gitlab/ci/rules.yml @@ -359,6 +359,9 @@ .patterns-example_usb_host_usb_cdc_4g_module: &patterns-example_usb_host_usb_cdc_4g_module - "examples/usb/host/usb_cdc_4g_module/**/*" +.patterns-example_usb_host_usb_cdc_basic: &patterns-example_usb_host_usb_cdc_basic + - "examples/usb/host/usb_cdc_basic/**/*" + .patterns-example_utilities_xz_decompress_file: &patterns-example_utilities_xz_decompress_file - "examples/utilities/xz_decompress_file/**/*" @@ -911,6 +914,20 @@ - <<: *if-dev-push changes: *patterns-example_usb_host_usb_cdc_4g_module +.rules:build:example_usb_host_usb_cdc_basic: + rules: + - <<: *if-protected + - <<: *if-label-build + - <<: *if-trigger-job + - <<: *if-dev-push + changes: *patterns-build_system + - <<: *if-dev-push + changes: *patterns-components_usb_iot_usbh + - <<: *if-dev-push + changes: *patterns-components_usb_iot_usbh_cdc + - <<: *if-dev-push + changes: *patterns-example_usb_host_usb_cdc_basic + .rules:build:example_utilities_xz_decompress_file: rules: - <<: *if-protected diff --git a/components/usb/iot_usbh_cdc/idf_component.yml b/components/usb/iot_usbh_cdc/idf_component.yml index 3a0e21e42..991688001 100644 --- a/components/usb/iot_usbh_cdc/idf_component.yml +++ b/components/usb/iot_usbh_cdc/idf_component.yml @@ -13,3 +13,5 @@ dependencies: version: "0.*" public: true override_path: "../iot_usbh" +examples: + - path: ../../../examples/usb/host/usb_cdc_basic diff --git a/examples/.build-rules.yml b/examples/.build-rules.yml index b9cb597db..f95a6b939 100644 --- a/examples/.build-rules.yml +++ b/examples/.build-rules.yml @@ -163,10 +163,10 @@ examples/usb/host/usb_audio_player: examples/usb/host/usb_cdc_4g_module: enable: - if: IDF_TARGET in ["esp32s2","esp32s3"] - disable: - - if: IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR == 0 - temporary: true - reason: IDF Bug '#36' + +examples/usb/host/usb_cdc_basic: + enable: + - if: IDF_TARGET in ["esp32s2","esp32s3"] examples/utilities/xz_decompress_file: enable: diff --git a/examples/usb/host/usb_cdc_basic/CMakeLists.txt b/examples/usb/host/usb_cdc_basic/CMakeLists.txt new file mode 100644 index 000000000..596f609b8 --- /dev/null +++ b/examples/usb/host/usb_cdc_basic/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following 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.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(usb_cdc_basic) diff --git a/examples/usb/host/usb_cdc_basic/README.md b/examples/usb/host/usb_cdc_basic/README.md new file mode 100644 index 000000000..229d7c014 --- /dev/null +++ b/examples/usb/host/usb_cdc_basic/README.md @@ -0,0 +1,85 @@ +# USB Host CDC Basic Example + +This example demonstrates how to use [iot_usbh_cdc](https://components.espressif.com/components/espressif/iot_usbh_cdc) to communicate with USB CDC device. + +## How to use the example + +### Hardware Required + +The example can be run on ESP32-S2 or ESP32-S3 based development board with USB interface. + +### Setup the Hardware + +Connect the external USB device to ESP32-S USB interface directly. + +| ESP32-Sx GPIO | USB Device | +| ------------- | ----------- | +| 20 | D+ (green) | +| 19 | D- (white) | +| GND | GND (black) | +| +5V | +5V (red) | + +### Configure the project + +1. The example enables one bulk interface by default. +2. Users can modify the `EXAMPLE_BULK_ITF_NUM` to `2` in `usb_cdc_basic_main.c` to enable two bulk interfaces. +3. Users need to modify the endpoint address `EXAMPLE_BULK_OUTx_EP_ADDR` and `EXAMPLE_BULK_INx_EP_ADDR` to the actual endpoint address of the USB device. +4. Use the command below to set build target to `esp32s2` or `esp32s3`. + +``` +idf.py set-target esp32s3 +``` + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT build flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +If your USB device (eg. 4G Module) supports AT command, When host send `AT`, the device usually returns `OK` in most cases. + +``` +I (408) USB_HCDC: Waitting Device Connection +I (438) USB_HCDC: Port=1 init succeed +W (438) USB_HCDC: Waitting USB Connection +I (688) USB_HCDC: line 261 HCD_PORT_EVENT_CONNECTION +I (688) USB_HCDC: Resetting Port +I (748) USB_HCDC: Port speed = 1 +I (748) USB_HCDC: Set Device Addr = 1 +I (748) USB_HCDC: Set Device Addr Done +I (748) USB_HCDC: Set Device Configuration = 1 +I (748) USB_HCDC: Set Device Configuration Done +I (758) USB_HCDC: Set Device Line State: dtr 1, rts 0 +I (758) USB_HCDC: Set Device Line State Done +I (768) USB_HCDC: Creating bulk in pipe +I (768) USB_HCDC: Creating bulk out pipe +I (808) USB_HCDC: usb driver install succeed + +I (6059) cdc_basic_demo: Send itf0 len=4: AT + +I (6069) cdc_basic_demo: Send itf1 len=4: AT + +I (6079) cdc_basic_demo: Itf 0, Receive len=6: +OK + +I (6079) cdc_basic_demo: Itf 1, Receive len=6: +OK + +I (7089) cdc_basic_demo: Send itf0 len=4: AT + +I (7089) cdc_basic_demo: Send itf1 len=4: AT + +I (7109) cdc_basic_demo: Itf 0, Receive len=6: +OK + +I (7109) cdc_basic_demo: Itf 1, Receive len=6: +OK +``` \ No newline at end of file diff --git a/examples/usb/host/usb_cdc_basic/main/CMakeLists.txt b/examples/usb/host/usb_cdc_basic/main/CMakeLists.txt new file mode 100644 index 000000000..ab96b2d05 --- /dev/null +++ b/examples/usb/host/usb_cdc_basic/main/CMakeLists.txt @@ -0,0 +1,3 @@ + +idf_component_register(SRCS usb_cdc_basic_main.c + INCLUDE_DIRS ".") diff --git a/examples/usb/host/usb_cdc_basic/main/idf_component.yml b/examples/usb/host/usb_cdc_basic/main/idf_component.yml new file mode 100644 index 000000000..4c38e317b --- /dev/null +++ b/examples/usb/host/usb_cdc_basic/main/idf_component.yml @@ -0,0 +1,8 @@ +targets: + - esp32s2 + - esp32s3 +dependencies: + idf: ">=4.4.1" + iot_usbh_cdc: + version: "0.2.*" + override_path: "../../../../../components/usb/iot_usbh_cdc" diff --git a/examples/usb/host/usb_cdc_basic/main/usb_cdc_basic_main.c b/examples/usb/host/usb_cdc_basic/main/usb_cdc_basic_main.c new file mode 100644 index 000000000..0e73fbda3 --- /dev/null +++ b/examples/usb/host/usb_cdc_basic/main/usb_cdc_basic_main.c @@ -0,0 +1,142 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "iot_usbh_cdc.h" + +static const char *TAG = "cdc_basic_demo"; +/* USB PIN fixed in esp32-s2/s3, can not use io matrix */ +#define BOARD_USB_DP_PIN 20 +#define BOARD_USB_DN_PIN 19 + +/* ringbuffer size */ +#define IN_RINGBUF_SIZE (1024 * 1) +#define OUT_RINGBUF_SIZE (1024 * 1) + +/* enable interface num */ +#define EXAMPLE_BULK_ITF_NUM 1 +/* bulk endpoint address */ +#define EXAMPLE_BULK_IN0_EP_ADDR 0x81 +#define EXAMPLE_BULK_OUT0_EP_ADDR 0x01 +#define EXAMPLE_BULK_IN1_EP_ADDR 0x82 +#define EXAMPLE_BULK_OUT1_EP_ADDR 0x02 +/* bulk endpoint max package size */ +#define EXAMPLE_BULK_EP_MPS 64 + +/* choose if use user endpoint descriptors */ +#define EXAMPLE_CONFIG_USER_EP_DESC + +/* +the basic demo skip the standred get descriptors process, +users need to get params from cdc device descriptors from PC side, +eg. run `lsusb -v` in linux, then hardcode the related params below +*/ +#ifdef EXAMPLE_CONFIG_USER_EP_DESC +static usb_ep_desc_t bulk_out_ep_desc = { + .bLength = sizeof(usb_ep_desc_t), + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = EXAMPLE_BULK_OUT0_EP_ADDR, + .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, + .wMaxPacketSize = EXAMPLE_BULK_EP_MPS, +}; + +static usb_ep_desc_t bulk_in_ep_desc = { + .bLength = sizeof(usb_ep_desc_t), + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = EXAMPLE_BULK_IN0_EP_ADDR, + .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, + .wMaxPacketSize = EXAMPLE_BULK_EP_MPS, +}; +#endif + +static void usb_receive_task(void *param) +{ + size_t data_len = 0; + uint8_t buf[IN_RINGBUF_SIZE]; + + while (1) { + /* Polling USB receive buffer to get data */ + for (size_t i = 0; i < EXAMPLE_BULK_ITF_NUM; i++) { + if (usbh_cdc_get_itf_state(i) == false) { + continue; + } + usbh_cdc_itf_get_buffered_data_len(i, &data_len); + if (data_len > 0) { + usbh_cdc_itf_read_bytes(i, buf, data_len, 10); + ESP_LOGI(TAG, "Itf %d, Receive len=%d: %.*s", i, data_len, data_len, buf); + } else { + vTaskDelay(1); + } + } + } +} + +static void usb_connect_callback(void *arg) +{ + ESP_LOGI(TAG, "Device Connected!"); +} + +static void usb_disconnect_callback(void *arg) +{ + ESP_LOGW(TAG, "Device Disconnected!"); +} + +void app_main(void) +{ + /* install usbh cdc driver with bulk endpoint configs + and size of internal ringbuffer*/ +#ifdef EXAMPLE_CONFIG_USER_EP_DESC + ESP_LOGI(TAG, "using user bulk endpoint descriptor"); + static usbh_cdc_config_t config = { + /* use user endpoint descriptor */ + .bulk_in_ep = &bulk_in_ep_desc, + .bulk_out_ep = &bulk_out_ep_desc, +#else + ESP_LOGI(TAG, "using default bulk endpoint descriptor"); + static usbh_cdc_config_t config = { + /* use default endpoint descriptor with user address */ + .bulk_in_ep_addr = EXAMPLE_BULK_IN0_EP_ADDR, + .bulk_out_ep_addr = EXAMPLE_BULK_OUT0_EP_ADDR, +#endif + .rx_buffer_size = IN_RINGBUF_SIZE, + .tx_buffer_size = OUT_RINGBUF_SIZE, + .conn_callback = usb_connect_callback, + .disconn_callback = usb_disconnect_callback, + }; + +#if (EXAMPLE_BULK_ITF_NUM > 1) + ESP_LOGI(TAG, "itf %d using default bulk endpoint descriptor", 1); + config.itf_num = 2; + /* test config with only ep addr */ + config.bulk_in_ep_addrs[1] = EXAMPLE_BULK_IN1_EP_ADDR; + config.bulk_out_ep_addrs[1] = EXAMPLE_BULK_OUT1_EP_ADDR; + config.rx_buffer_sizes[1] = IN_RINGBUF_SIZE; + config.tx_buffer_sizes[1] = OUT_RINGBUF_SIZE; +#endif + + /* install USB host CDC driver */ + ESP_ERROR_CHECK(usbh_cdc_driver_install(&config)); + /* Waiting for USB device connected */ + ESP_ERROR_CHECK(usbh_cdc_wait_connect(portMAX_DELAY)); + /* Create a task for USB data processing */ + xTaskCreate(usb_receive_task, "usb_rx", 4096, NULL, 2, NULL); + + /* Repeatly sent AT through USB */ + char buff[32] = "AT\r\n"; + while (1) { + int len = usbh_cdc_write_bytes((uint8_t *)buff, strlen(buff)); + ESP_LOGI(TAG, "Send itf0 len=%d: %s", len, buff); +#if (EXAMPLE_BULK_ITF_NUM > 1) + len = usbh_cdc_itf_write_bytes(1, (uint8_t *)buff, strlen(buff)); + ESP_LOGI(TAG, "Send itf1 len=%d: %s", len, buff); +#endif + vTaskDelay(pdMS_TO_TICKS(1000)); + } +}