feat(usb_serial_jtag): Add usb serial jtag support for esp32h4

This commit is contained in:
C.S.M
2025-07-21 18:32:52 +08:00
parent 8886097fe4
commit df8a9d26c2
17 changed files with 361 additions and 23 deletions

View File

@@ -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"]
- if: IDF_TARGET in ["esp32p4", "esp32c5", "esp32h4"]
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"]
- if: IDF_TARGET in ["esp32p4", "esp32c5", "esp32h4"]
temporary: true
reason: No runners.
depends_components:

View File

@@ -1,2 +1,2 @@
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |

View File

@@ -1,2 +1,2 @@
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |

View File

@@ -188,7 +188,7 @@ static inline void usb_serial_jtag_ll_txfifo_flush(void)
*
* @param enable Enable USJ JTAG bridge
*/
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_jtag_bridge(bool enable)
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_jtag_bridge(bool enable)
{
USB_SERIAL_JTAG.conf0.usb_jtag_bridge_en = enable;
}

View File

@@ -189,7 +189,7 @@ static inline void usb_serial_jtag_ll_txfifo_flush(void)
*
* @param enable Enable USJ JTAG bridge
*/
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_jtag_bridge(bool enable)
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_jtag_bridge(bool enable)
{
USB_SERIAL_JTAG.conf0.usb_jtag_bridge_en = enable;
}

View File

@@ -188,7 +188,7 @@ static inline void usb_serial_jtag_ll_txfifo_flush(void)
*
* @param enable Enable USJ JTAG bridge
*/
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_jtag_bridge(bool enable)
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_jtag_bridge(bool enable)
{
USB_SERIAL_JTAG.conf0.usb_jtag_bridge_en = enable;
}

View File

@@ -189,7 +189,7 @@ static inline void usb_serial_jtag_ll_txfifo_flush(void)
*
* @param enable Enable USJ JTAG bridge
*/
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_jtag_bridge(bool enable)
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_jtag_bridge(bool enable)
{
USB_SERIAL_JTAG.conf0.usb_jtag_bridge_en = enable;
}

View File

@@ -0,0 +1,335 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#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

View File

@@ -192,7 +192,7 @@ static inline void usb_serial_jtag_ll_txfifo_flush(void)
*
* @param enable Enable USJ JTAG bridge
*/
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_jtag_bridge(bool enable)
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_jtag_bridge(bool enable)
{
USB_SERIAL_JTAG.conf0.usb_jtag_bridge_en = enable;
}

View File

@@ -191,7 +191,7 @@ static inline void usb_serial_jtag_ll_txfifo_flush(void)
*
* @param enable Enable USJ JTAG bridge
*/
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_jtag_bridge(bool enable)
FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_jtag_bridge(bool enable)
{
USB_SERIAL_JTAG.conf0.usb_jtag_bridge_en = enable;
}

View File

@@ -27,6 +27,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

View File

@@ -46,7 +46,7 @@
// #define SOC_BT_SUPPORTED 1
// #define SOC_IEEE802154_SUPPORTED 1
#define SOC_ASYNC_MEMCPY_SUPPORTED 1
// #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 // TODO: [ESP32H4] IDF-12396
#define SOC_USB_SERIAL_JTAG_SUPPORTED 1
// #define SOC_TEMP_SENSOR_SUPPORTED 1 // TODO: [ESP32H4] IDF-12404
// #define SOC_SUPPORTS_SECURE_DL_MODE 1
// #define SOC_ULP_SUPPORTED 0 // TODO: [ESP32H4] IDF-12396

View File

@@ -969,12 +969,12 @@ typedef struct {
volatile usb_serial_jtag_serial_ep_timeout1_reg_t serial_jtag_serial_ep_timeout1;
uint32_t reserved_074[3];
volatile usb_serial_jtag_date_reg_t serial_jtag_date;
} usb_dev_t;
} usb_serial_jtag_dev_t;
extern usb_dev_t USB_SERIAL_JTAG;
extern usb_serial_jtag_dev_t USB_SERIAL_JTAG;
#ifndef __cplusplus
_Static_assert(sizeof(usb_dev_t) == 0x84, "Invalid size of usb_dev_t structure");
_Static_assert(sizeof(usb_serial_jtag_dev_t) == 0x84, "Invalid size of usb_dev_t structure");
#endif
#ifdef __cplusplus

View File

@@ -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

View File

@@ -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"}
{IDF_TARGET_USB_DM_GPIO:default="Not Updated!",esp32c3="18",esp32s3="19", esp32c6="12", esp32h2="26", esp32p4="24/26", esp32c5="13", esp32c61="12"}
{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"}
Connect {IDF_TARGET_NAME} to the USB port as follows:

View File

@@ -19,8 +19,8 @@ ESP 芯片通常使用 UART 实现串口,并可以通过外部 USB-UART 桥接
硬件要求
=====================
{IDF_TARGET_USB_DP_GPIO:default="未更新!",esp32c3="19",esp32s3="20", esp32c6="13", esp32h2="27", esp32p4="25/27", esp32c5="14", esp32c61="13"}
{IDF_TARGET_USB_DM_GPIO:default="未更新!",esp32c3="18",esp32s3="19", esp32c6="12", esp32h2="26", esp32p4="24/26", esp32c5="13", esp32c61="12"}
{IDF_TARGET_USB_DP_GPIO:default="未更新!",esp32c3="19",esp32s3="20", esp32c6="13", esp32h2="27", esp32p4="25/27", esp32c5="14", esp32c61="13", esp32h4="14"}
{IDF_TARGET_USB_DM_GPIO:default="未更新!",esp32c3="18",esp32s3="19", esp32c6="12", esp32h2="26", esp32p4="24/26", esp32c5="13", esp32c61="12", esp32h4="13"}
将 {IDF_TARGET_NAME} 连接到 USB 端口,连接方式如下:

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
# USB SERIAL JTAG Echo Example