diff --git a/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml b/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml index 9e8b64bfd7..4f69c071a5 100644 --- a/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml +++ b/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml @@ -4,7 +4,7 @@ components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag: disable: - if: SOC_USB_SERIAL_JTAG_SUPPORTED != 1 disable_test: - - if: IDF_TARGET in ["esp32p4", "esp32c5", "esp32h4"] + - if: IDF_TARGET in ["esp32p4", "esp32c5", "esp32h4", "esp32h21"] temporary: true reason: No runners. depends_components: @@ -16,7 +16,7 @@ components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs: disable: - if: SOC_USB_SERIAL_JTAG_SUPPORTED != 1 disable_test: - - if: IDF_TARGET in ["esp32p4", "esp32c5", "esp32h4"] + - if: IDF_TARGET in ["esp32p4", "esp32c5", "esp32h4", "esp32h21"] temporary: true reason: No runners. depends_components: diff --git a/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md b/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md index 51341d5b2e..1fd60c328e 100644 --- a/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md +++ b/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | diff --git a/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs/README.md b/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs/README.md index 51341d5b2e..1fd60c328e 100644 --- a/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs/README.md +++ b/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | diff --git a/components/esp_rom/esp32h21/Kconfig.soc_caps.in b/components/esp_rom/esp32h21/Kconfig.soc_caps.in index e455d4e363..9ec3ed9069 100644 --- a/components/esp_rom/esp32h21/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32h21/Kconfig.soc_caps.in @@ -98,3 +98,7 @@ config ESP_ROM_HAS_OUTPUT_PUTC_FUNC config ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY bool default y + +config ESP_ROM_NO_USB_SERIAL_OUTPUT_API + bool + default y diff --git a/components/esp_rom/esp32h21/esp_rom_caps.h b/components/esp_rom/esp32h21/esp_rom_caps.h index 6dc77b3576..0e6b2dd688 100644 --- a/components/esp_rom/esp32h21/esp_rom_caps.h +++ b/components/esp_rom/esp32h21/esp_rom_caps.h @@ -31,3 +31,4 @@ // #define ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB (1) // ROM supports the HP core to jump to the RTC memory to execute stub code after waking up from deepsleep. //TODO: [ESP32H21] IDF-11515 #define ESP_ROM_HAS_OUTPUT_PUTC_FUNC (1) // ROM has esp_rom_output_putc (or ets_write_char_uart) #define ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY (1) // ROM mem/str functions are not optimized well for misaligned memory access. +#define ESP_ROM_NO_USB_SERIAL_OUTPUT_API (1) // ROM does not export the usb-serial-jtag write char function diff --git a/components/esp_rom/esp32h21/include/esp32h21/rom/efuse.h b/components/esp_rom/esp32h21/include/esp32h21/rom/efuse.h index b33df42b71..a4429c4403 100644 --- a/components/esp_rom/esp32h21/include/esp32h21/rom/efuse.h +++ b/components/esp_rom/esp32h21/include/esp32h21/rom/efuse.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -274,6 +274,16 @@ int ets_jtag_enable_temporarily(const uint8_t *jtag_hmac_key, ets_efuse_block_t */ unsigned char esp_crc8(unsigned char const *p, unsigned int len); +/** + * @brief Read if usb print in ROM disabled by efuse + * + * + * @return + * - 0 for enable. + * - 1 for disable. + */ +uint32_t ets_efuse_usb_print_is_disabled(void); + /** * @} */ diff --git a/components/hal/esp32h21/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32h21/include/hal/usb_serial_jtag_ll.h new file mode 100644 index 0000000000..3c47d10dab --- /dev/null +++ b/components/hal/esp32h21/include/hal/usb_serial_jtag_ll.h @@ -0,0 +1,335 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +* +* SPDX-License-Identifier: Apache-2.0 +*/ + +#pragma once + +#include +#include "esp_attr.h" +#include "soc/pcr_struct.h" +#include "soc/usb_serial_jtag_reg.h" +#include "soc/usb_serial_jtag_struct.h" +#include "hal/usb_serial_jtag_types.h" +#include "hal/misc.h" + +/* ----------------------------- Macros & Types ----------------------------- */ + +#define USB_SERIAL_JTAG_LL_INTR_MASK (0x7ffff) // All interrupts mask +#define USB_SERIAL_JTAG_LL_PHY_DEPENDS_ON_BBPLL (1) + +// Define USB_SERIAL_JTAG interrupts +// Note the hardware has more interrupts, but they're only useful for debugging +// the hardware. +typedef enum { + USB_SERIAL_JTAG_INTR_SOF = (1 << 1), + USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT = (1 << 2), + USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY = (1 << 3), + USB_SERIAL_JTAG_INTR_TOKEN_REC_IN_EP1 = (1 << 8), + USB_SERIAL_JTAG_INTR_BUS_RESET = (1 << 9), + USB_SERIAL_JTAG_INTR_EP1_ZERO_PAYLOAD = (1 << 10), +} usb_serial_jtag_ll_intr_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------- USJ Peripheral ----------------------------- */ + +/** +* @brief Enable the USB_SERIAL_JTAG interrupt based on the given mask. +* +* @param mask The bitmap of the interrupts need to be enabled. +* +* @return None +*/ +static inline void usb_serial_jtag_ll_ena_intr_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.serial_jtag_int_ena.val |= mask; +} + +/** +* @brief Disable the USB_SERIAL_JTAG interrupt based on the given mask. +* +* @param mask The bitmap of the interrupts need to be disabled. +* +* @return None +*/ +static inline void usb_serial_jtag_ll_disable_intr_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.serial_jtag_int_ena.val &= (~mask); +} + +/** +* @brief Get the USB_SERIAL_JTAG interrupt status. +* +* @return The USB_SERIAL_JTAG interrupt status. +*/ +static inline uint32_t usb_serial_jtag_ll_get_intsts_mask(void) +{ + return USB_SERIAL_JTAG.serial_jtag_int_st.val; +} + +/** +* @brief Get the USB_SERIAL_JTAG raw interrupt status. +* +* @return The USB_SERIAL_JTAG raw interrupt status. +*/ +static inline __attribute__((always_inline)) uint32_t usb_serial_jtag_ll_get_intraw_mask(void) +{ + return USB_SERIAL_JTAG.serial_jtag_int_raw.val; +} + +/** +* @brief Clear the USB_SERIAL_JTAG interrupt status based on the given mask. +* +* @param mask The bitmap of the interrupts need to be cleared. +* +* @return None +*/ +static inline __attribute__((always_inline)) void usb_serial_jtag_ll_clr_intsts_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.serial_jtag_int_clr.val = mask; +} + +/** +* @brief Get status of enabled interrupt. +* +* @return interrupt enable value +*/ +static inline uint32_t usb_serial_jtag_ll_get_intr_ena_status(void) +{ + return USB_SERIAL_JTAG.serial_jtag_int_ena.val; +} + +/** +* @brief Read the bytes from the USB_SERIAL_JTAG rxfifo. +* +* @param buf The data buffer. +* @param rd_len The data length needs to be read. +* +* @return amount of bytes read +*/ +static inline int usb_serial_jtag_ll_read_rxfifo(uint8_t *buf, uint32_t rd_len) +{ + int i; + for (i = 0; i < (int)rd_len; i++) { + if (!USB_SERIAL_JTAG.serial_jtag_ep1_conf.serial_jtag_serial_out_ep_data_avail) break; + buf[i] = USB_SERIAL_JTAG.serial_jtag_ep1.val; + } + return i; +} + +/** +* @brief Write byte to the USB_SERIAL_JTAG txfifo. Only writes bytes as long / if there +* is room in the buffer. +* +* @param buf The data buffer. +* @param wr_len The data length needs to be written. +* +* @return Amount of bytes actually written. May be less than wr_len. +*/ +static inline int usb_serial_jtag_ll_write_txfifo(const uint8_t *buf, uint32_t wr_len) +{ + int i; + for (i = 0; i < (int)wr_len; i++) { + if (!USB_SERIAL_JTAG.serial_jtag_ep1_conf.serial_jtag_serial_in_ep_data_free) break; + USB_SERIAL_JTAG.serial_jtag_ep1.val = buf[i]; + } + return i; +} + +/** +* @brief Returns 1 if the USB_SERIAL_JTAG rxfifo has data available. +* +* @return 0 if no data available, 1 if data available +*/ +static inline int usb_serial_jtag_ll_rxfifo_data_available(void) +{ + return USB_SERIAL_JTAG.serial_jtag_ep1_conf.serial_jtag_serial_out_ep_data_avail; +} + +/** +* @brief Returns 1 if the USB_SERIAL_JTAG txfifo has room. +* +* @return 0 if no data available, 1 if data available +*/ +static inline int usb_serial_jtag_ll_txfifo_writable(void) +{ + return USB_SERIAL_JTAG.serial_jtag_ep1_conf.serial_jtag_serial_in_ep_data_free; +} + +/** +* @brief Flushes the TX buffer, that is, make it available for the +* host to pick up. +* +* @note When fifo is full (with 64 byte), HW will flush the buffer automatically, +* if this function is called directly after, this effectively turns into a +* no-op. Because a 64-byte packet will be interpreted as a not-complete USB +* transaction, you need to transfer either more data or a zero-length packet +* for the data to actually end up at the program listening to the CDC-ACM +* serial port. To send a zero-length packet, call +* usb_serial_jtag_ll_txfifo_flush() again when +* usb_serial_jtag_ll_txfifo_writable() returns true. +* +* @return na +*/ +static inline void usb_serial_jtag_ll_txfifo_flush(void) +{ + USB_SERIAL_JTAG.serial_jtag_ep1_conf.serial_jtag_wr_done=1; +} + +/** +* @brief Enable USJ JTAG bridge +* +* If enabled, USJ is disconnected from internal JTAG interface. JTAG interface +* is routed through GPIO matrix instead. +* +* @param enable Enable USJ JTAG bridge +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_jtag_bridge(bool enable) +{ + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_usb_jtag_bridge_en = enable; +} + +/* ---------------------------- USB PHY Control ---------------------------- */ + +/** +* @brief Sets PHY defaults +* +* Some PHY register fields/features of the USJ are redundant on the ESP32-H4. +* This function those fields are set to the appropriate default values. +* +* @param hw Start address of the USB Wrap registers +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_defaults(void) +{ + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_usb_pad_enable = 1; +} + +/** +* @brief Enables/disables exchanging of the D+/D- pins USB PHY +* +* @param enable Enables pin exchange, disabled otherwise +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_pin_exchg(bool enable) +{ + if (enable) { + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_exchg_pins = 1; + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_exchg_pins_override = 1; + } else { + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_exchg_pins_override = 0; + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_exchg_pins = 0; + } +} + +/** +* @brief Enables and sets voltage threshold overrides for USB FSLS PHY single-ended inputs +* +* @param vrefh_step High voltage threshold. 0 to 3 indicating 80mV steps from 1.76V to 2V. +* @param vrefl_step Low voltage threshold. 0 to 3 indicating 80mV steps from 0.8V to 1.04V. +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_vref_override(unsigned int vrefh_step, unsigned int vrefl_step) +{ + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_vrefh = vrefh_step; + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_vrefl = vrefl_step; + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_vref_override = 1; +} + +/** +* @brief Disables voltage threshold overrides for USB FSLS PHY single-ended inputs +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_disable_vref_override(void) +{ + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_vref_override = 0; +} + +/** +* @brief Enable override of USB FSLS PHY's pull up/down resistors +* +* @param vals Override values to set +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_pull_override(const usb_serial_jtag_pull_override_vals_t *vals) +{ + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_dp_pullup = vals->dp_pu; + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_dp_pulldown = vals->dp_pd; + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_dm_pullup = vals->dm_pu; + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_dm_pulldown = vals->dm_pd; + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_pad_pull_override = 1; +} + +/** +* @brief Disable override of USB FSLS PHY pull up/down resistors +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_disable_pull_override(void) +{ + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_pad_pull_override = 0; +} + +/** +* @brief Sets the strength of the pullup resistor +* +* @param strong True is a ~1.4K pullup, false is a ~2.4K pullup +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_pullup_strength(bool strong) +{ + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_pullup_value = strong; +} + +/** +* @brief Check if USB FSLS PHY pads are enabled +* +* @return True if enabled, false otherwise +*/ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_phy_is_pad_enabled(void) +{ + return USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_usb_pad_enable; +} + +/** +* @brief Enable the USB FSLS PHY pads +* +* @param enable Whether to enable the USB FSLS PHY pads +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_pad(bool enable) +{ + USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_usb_pad_enable = enable; +} + +/* ----------------------------- RCC Functions ----------------------------- */ + +/** +* @brief Enable the bus clock for USJ module +* @param clk_en True if enable the clock of USJ module +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_enable_bus_clock(bool clk_en) +{ + PCR.usb_device_conf.usb_device_clk_en = clk_en; +} + +/** +* @brief Reset the USJ module +*/ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_reset_register(void) +{ + PCR.usb_device_conf.usb_device_rst_en = 1; + PCR.usb_device_conf.usb_device_rst_en = 0; +} + +/** +* Get the enable status of the USJ module +* +* @return Return true if USJ module is enabled +*/ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_module_is_enabled(void) +{ + return (PCR.usb_device_conf.usb_device_clk_en && !PCR.usb_device_conf.usb_device_rst_en); +} + + + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in index ac6207ccb1..f83ca47b78 100644 --- a/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in @@ -23,6 +23,10 @@ config SOC_ASYNC_MEMCPY_SUPPORTED bool default y +config SOC_USB_SERIAL_JTAG_SUPPORTED + bool + default y + config SOC_EFUSE_KEY_PURPOSE_FIELD bool default y diff --git a/components/soc/esp32h21/include/soc/interrupts.h b/components/soc/esp32h21/include/soc/interrupts.h index 57d40ef512..956228b14a 100644 --- a/components/soc/esp32h21/include/soc/interrupts.h +++ b/components/soc/esp32h21/include/soc/interrupts.h @@ -53,7 +53,7 @@ typedef enum { ETS_UART1_INTR_SOURCE, ETS_LEDC_INTR_SOURCE, ETS_TWAI0_INTR_SOURCE, - ETS_USB_INTR_SOURCE, + ETS_USB_SERIAL_JTAG_INTR_SOURCE, ETS_RMT_INTR_SOURCE, ETS_I2C_EXT0_INTR_SOURCE, ETS_I2C_EXT1_INTR_SOURCE, diff --git a/components/soc/esp32h21/include/soc/soc_caps.h b/components/soc/esp32h21/include/soc/soc_caps.h index aca845d3ec..75ffb0d7a9 100644 --- a/components/soc/esp32h21/include/soc/soc_caps.h +++ b/components/soc/esp32h21/include/soc/soc_caps.h @@ -34,7 +34,7 @@ // #define SOC_IEEE802154_SUPPORTED 1 // #define SOC_IEEE802154_BLE_ONLY 1 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 -// #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 //TODO: [ESP32H21] IDF-11616 +#define SOC_USB_SERIAL_JTAG_SUPPORTED 1 // #define SOC_TEMP_SENSOR_SUPPORTED 1 //TODO: [ESP32H21] IDF-11624 // #define SOC_SUPPORTS_SECURE_DL_MODE 1 // #define SOC_ULP_SUPPORTED 1 diff --git a/docs/docs_not_updated/esp32h21.txt b/docs/docs_not_updated/esp32h21.txt index 4185144994..619e8c81f8 100644 --- a/docs/docs_not_updated/esp32h21.txt +++ b/docs/docs_not_updated/esp32h21.txt @@ -5,7 +5,6 @@ api-guides/wifi-expansion.rst api-guides/deep-sleep-stub.rst api-guides/app_trace.rst api-guides/esp-wifi-mesh.rst -api-guides/usb-serial-jtag-console.rst api-guides/core_dump.rst api-guides/lwip.rst api-guides/esp-ble-mesh/ble-mesh-faq.rst diff --git a/docs/en/api-guides/usb-serial-jtag-console.rst b/docs/en/api-guides/usb-serial-jtag-console.rst index 9cfa09f24f..ea97d5a0c2 100644 --- a/docs/en/api-guides/usb-serial-jtag-console.rst +++ b/docs/en/api-guides/usb-serial-jtag-console.rst @@ -19,8 +19,8 @@ Generally, ESP chips implement a serial port using UART and can be connected to Hardware Requirements ===================== -{IDF_TARGET_USB_DP_GPIO:default="Not Updated!",esp32c3="19",esp32s3="20", esp32c6="13", esp32h2="27", esp32p4="25/27", esp32c5="14", esp32c61="13", esp32h4="14"} -{IDF_TARGET_USB_DM_GPIO:default="Not Updated!",esp32c3="18",esp32s3="19", esp32c6="12", esp32h2="26", esp32p4="24/26", esp32c5="13", esp32c61="12", esp32h4="13"} +{IDF_TARGET_USB_DP_GPIO:default="Not Updated!",esp32c3="19",esp32s3="20", esp32c6="13", esp32h2="27", esp32p4="25/27", esp32c5="14", esp32c61="13", esp32h4="14", esp32h21="18"} +{IDF_TARGET_USB_DM_GPIO:default="Not Updated!",esp32c3="18",esp32s3="19", esp32c6="12", esp32h2="26", esp32p4="24/26", esp32c5="13", esp32c61="12", esp32h4="13", esp32h21="17"} Connect {IDF_TARGET_NAME} to the USB port as follows: diff --git a/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md b/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md index 19186803b9..5ff6f835db 100644 --- a/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md +++ b/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | # USB SERIAL JTAG Echo Example