diff --git a/components/esp_system/include/esp_private/usb_console.h b/components/esp_system/include/esp_private/usb_console.h index 1243b1325c8c..0440b016974a 100644 --- a/components/esp_system/include/esp_private/usb_console.h +++ b/components/esp_system/include/esp_private/usb_console.h @@ -50,14 +50,46 @@ esp_err_t esp_usb_console_init(void); */ ssize_t esp_usb_console_write_buf(const char* buf, size_t size); +/** + * @brief Wait until all buffered USB CDC output is written + * + * @return ssize_t Number of bytes written, or -1 if the driver is not initialized + */ ssize_t esp_usb_console_flush(void); +/** + * @brief Read data from USB CDC + * + * May read less data than requested. + * + * @param buf Buffer to read data into + * @param buf_size Size of the buffer + * @return ssize_t Number of bytes written into the buffer, or -1 if the driver is not initialized + */ ssize_t esp_usb_console_read_buf(char* buf, size_t buf_size); +/** + * @brief Get the number of bytes available for reading from USB CDC + * + * @return ssize_t Number of bytes available, or -1 if the driver is not initialized + */ ssize_t esp_usb_console_available_for_read(void); +/** + * @brief Check if data can be written into USB CDC + * + * @return true if data can be written now without blocking + */ bool esp_usb_console_write_available(void); +/** + * @brief Set RX/TX callback functions to be called from ISR + * + * @param rx_cb RX callback function + * @param tx_cb TX callback function + * @param arg callback-specific context pointer + * @return ESP_OK if the callbacks were set, ESP_ERR_INVALID_STATE if the driver is not initialized + */ esp_err_t esp_usb_console_set_cb(esp_usb_console_cb_t rx_cb, esp_usb_console_cb_t tx_cb, void* arg); #ifdef __cplusplus diff --git a/components/esp_system/port/CMakeLists.txt b/components/esp_system/port/CMakeLists.txt index d14df8b8fba7..3e3d88b6a798 100644 --- a/components/esp_system/port/CMakeLists.txt +++ b/components/esp_system/port/CMakeLists.txt @@ -12,6 +12,10 @@ if(CONFIG_SOC_BOD_SUPPORTED) list(APPEND srcs "brownout.c") endif() +if(CONFIG_ESP_CONSOLE_USB_CDC) + list(APPEND srcs "usb_console.c") +endif() + add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/soc/esp32s2/CMakeLists.txt b/components/esp_system/port/soc/esp32s2/CMakeLists.txt index 03b7d6659d8e..2adf51698a47 100644 --- a/components/esp_system/port/soc/esp32s2/CMakeLists.txt +++ b/components/esp_system/port/soc/esp32s2/CMakeLists.txt @@ -22,9 +22,6 @@ endif() add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) -if(CONFIG_ESP_CONSOLE_USB_CDC) - target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/usb_console.c") -endif() #ld_include_highint_hdl is added as an undefined symbol because otherwise the #linker will ignore highint_hdl.S as it has no other files depending on any diff --git a/components/esp_system/port/soc/esp32s3/CMakeLists.txt b/components/esp_system/port/soc/esp32s3/CMakeLists.txt index bb4f4f1726d8..c910e6d3ea8a 100644 --- a/components/esp_system/port/soc/esp32s3/CMakeLists.txt +++ b/components/esp_system/port/soc/esp32s3/CMakeLists.txt @@ -23,9 +23,6 @@ endif() add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) -if(CONFIG_ESP_CONSOLE_USB_CDC) - target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/usb_console.c") -endif() #ld_include_highint_hdl is added as an undefined symbol because otherwise the #linker will ignore panic_highint_hdl.S as it has no other files depending on any diff --git a/components/esp_system/port/soc/esp32s3/usb_console.c b/components/esp_system/port/soc/esp32s3/usb_console.c deleted file mode 100644 index 31dbac2a7d57..000000000000 --- a/components/esp_system/port/soc/esp32s3/usb_console.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "esp_system.h" -#include "esp_intr_alloc.h" -#include "esp_private/usb_console.h" -#include "soc/periph_defs.h" -#include "soc/rtc_cntl_reg.h" -#include "soc/usb_struct.h" -#include "soc/usb_reg.h" -#include "spinlock.h" -#include "hal/soc_hal.h" -#include "esp_rom_uart.h" -#include "esp_rom_sys.h" -#include "esp32s3/rom/usb/usb_dc.h" -#include "esp32s3/rom/usb/cdc_acm.h" -#include "esp32s3/rom/usb/usb_dfu.h" -#include "esp32s3/rom/usb/usb_device.h" -#include "esp32s3/rom/usb/usb_os_glue.h" -#include "esp32s3/rom/usb/usb_persist.h" -#include "esp32s3/rom/usb/chip_usb_dw_wrapper.h" - -#define CDC_WORK_BUF_SIZE (ESP_ROM_CDC_ACM_WORK_BUF_MIN + CONFIG_ESP_CONSOLE_USB_CDC_RX_BUF_SIZE) - -typedef enum { - REBOOT_NONE, - REBOOT_NORMAL, - REBOOT_BOOTLOADER, - REBOOT_BOOTLOADER_DFU, -} reboot_type_t; - - -static reboot_type_t s_queue_reboot = REBOOT_NONE; -static int s_prev_rts_state; -static intr_handle_t s_usb_int_handle; -static cdc_acm_device *s_cdc_acm_device; -static char s_usb_tx_buf[ACM_BYTES_PER_TX]; -static size_t s_usb_tx_buf_pos; -static uint8_t cdcmem[CDC_WORK_BUF_SIZE]; -static esp_usb_console_cb_t s_rx_cb; -static esp_usb_console_cb_t s_tx_cb; -static void *s_cb_arg; - -#ifdef CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF -static portMUX_TYPE s_write_lock = portMUX_INITIALIZER_UNLOCKED; -void esp_usb_console_write_char(char c); -#define ISR_FLAG ESP_INTR_FLAG_IRAM -#else -#define ISR_FLAG 0 -#endif // CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF - - -/* Optional write lock routines; used only if esp_rom_printf output via CDC is enabled */ -static inline void write_lock_acquire(void); -static inline void write_lock_release(void); - -/* The two functions below need to be revisited in the multicore case TODO ESP32-S3 IDF-2048*/ -_Static_assert(SOC_CPU_CORES_NUM == 1, "usb_osglue_*_int is not multicore capable"); - -/* Called by ROM to disable the interrupts - * Non-static to allow placement into IRAM by ldgen. - */ -void esp_usb_console_osglue_dis_int(void) -{ - if (s_usb_int_handle) { - esp_intr_disable(s_usb_int_handle); - } -} - -/* Called by ROM to enable the interrupts - * Non-static to allow placement into IRAM by ldgen. - */ -void esp_usb_console_osglue_ena_int(void) -{ - if (s_usb_int_handle) { - esp_intr_enable(s_usb_int_handle); - } -} - -/* Delay function called by ROM USB driver. - * Non-static to allow placement into IRAM by ldgen. - */ -int esp_usb_console_osglue_wait_proc(int delay_us) -{ - if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING || - !xPortCanYield()) { - esp_rom_delay_us(delay_us); - return delay_us; - } - if (delay_us == 0) { - /* We should effectively yield */ - vPortYield(); - return 1; - } else { - /* Just delay */ - int ticks = MAX(delay_us / (portTICK_PERIOD_MS * 1000), 1); - vTaskDelay(ticks); - return ticks * portTICK_PERIOD_MS * 1000; - } -} - -/* Called by ROM CDC ACM driver from interrupt context./ - * Non-static to allow placement into IRAM by ldgen. - */ -void esp_usb_console_cdc_acm_cb(cdc_acm_device *dev, int status) -{ - if (status == USB_DC_RESET || status == USB_DC_CONNECTED) { - s_prev_rts_state = 0; - } else if (status == ACM_STATUS_LINESTATE_CHANGED) { - uint32_t rts, dtr; - cdc_acm_line_ctrl_get(dev, LINE_CTRL_RTS, &rts); - cdc_acm_line_ctrl_get(dev, LINE_CTRL_DTR, &dtr); - if (!rts && s_prev_rts_state) { - if (dtr) { - s_queue_reboot = REBOOT_BOOTLOADER; - } else { - s_queue_reboot = REBOOT_NORMAL; - } - } - s_prev_rts_state = rts; - } else if (status == ACM_STATUS_RX && s_rx_cb) { - (*s_rx_cb)(s_cb_arg); - } else if (status == ACM_STATUS_TX && s_tx_cb) { - (*s_tx_cb)(s_cb_arg); - } -} - -/* Non-static to allow placement into IRAM by ldgen. */ -void esp_usb_console_dfu_detach_cb(int timeout) -{ - s_queue_reboot = REBOOT_BOOTLOADER_DFU; -} - -/* USB interrupt handler, forward the call to the ROM driver. - * Non-static to allow placement into IRAM by ldgen. - */ -void esp_usb_console_interrupt(void *arg) -{ - usb_dc_check_poll_for_interrupts(); - /* Restart can be requested from esp_usb_console_cdc_acm_cb or esp_usb_console_dfu_detach_cb */ - if (s_queue_reboot != REBOOT_NONE) { - esp_restart(); - } -} - -/* Call the USB interrupt handler while any interrupts are pending, - * but not more than a few times. - * Non-static to allow placement into IRAM by ldgen. - */ -void esp_usb_console_poll_interrupts(void) -{ - const int max_poll_count = 10; - for (int i = 0; (USB0.gintsts & USB0.gintmsk) != 0 && i < max_poll_count; i++) { - usb_dc_check_poll_for_interrupts(); - } -} - -/* This function gets registered as a restart handler. - * Prepares USB peripheral for restart and sets up persistence. - * Non-static to allow placement into IRAM by ldgen. - */ -void esp_usb_console_before_restart(void) -{ - esp_usb_console_poll_interrupts(); - usb_dc_prepare_persist(); - if (s_queue_reboot == REBOOT_BOOTLOADER) { - chip_usb_set_persist_flags(USBDC_PERSIST_ENA); - REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); - } else if (s_queue_reboot == REBOOT_BOOTLOADER_DFU) { - chip_usb_set_persist_flags(USBDC_BOOT_DFU); - REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); - } else { - chip_usb_set_persist_flags(USBDC_PERSIST_ENA); - esp_usb_console_poll_interrupts(); - } -} - -/* Reset some static state in ROM, which survives when going from the - * 2nd stage bootloader into the app. This cleans some variables which - * indicates that the driver is already initialized, allowing us to - * initialize it again, in the app. - */ -static void esp_usb_console_rom_cleanup(void) -{ - /* TODO ESP32-S3 IDF-2987 */ - // extern char rom_usb_dev, rom_usb_dev_end; - // extern char rom_usb_dw_ctrl, rom_usb_dw_ctrl_end; - - // uart_acm_dev = NULL; - // memset((void *) &rom_usb_dev, 0, &rom_usb_dev_end - &rom_usb_dev); - // memset((void *) &rom_usb_dw_ctrl, 0, &rom_usb_dw_ctrl_end - &rom_usb_dw_ctrl); -} - -esp_err_t esp_usb_console_init(void) -{ - esp_err_t err; - err = esp_register_shutdown_handler(esp_usb_console_before_restart); - if (err != ESP_OK) { - return err; - } - - esp_usb_console_rom_cleanup(); - - /* Install OS hooks */ - s_usb_osglue.int_dis_proc = esp_usb_console_osglue_dis_int; - s_usb_osglue.int_ena_proc = esp_usb_console_osglue_ena_int; - s_usb_osglue.wait_proc = esp_usb_console_osglue_wait_proc; - - /* Install interrupt. - * In case of ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF: - * Note that this the interrupt handler has to be placed into IRAM because - * the interrupt handler can also be called in polling mode, when - * interrupts are disabled, and a write to USB is performed with cache disabled. - * Since the handler function is in IRAM, we can register the interrupt as IRAM capable. - * It is not because we actually need the interrupt to work with cache disabled! - */ - err = esp_intr_alloc(ETS_USB_INTR_SOURCE, ISR_FLAG | ESP_INTR_FLAG_INTRDISABLED, - esp_usb_console_interrupt, NULL, &s_usb_int_handle); - if (err != ESP_OK) { - esp_unregister_shutdown_handler(esp_usb_console_before_restart); - return err; - } - - /* Initialize USB / CDC */ - s_cdc_acm_device = cdc_acm_init(cdcmem, CDC_WORK_BUF_SIZE); - usb_dc_check_poll_for_interrupts(); - - /* Set callback for handling DTR/RTS lines and TX/RX events */ - cdc_acm_irq_callback_set(s_cdc_acm_device, esp_usb_console_cdc_acm_cb); - cdc_acm_irq_state_enable(s_cdc_acm_device); - - /* Set callback for handling DFU detach */ - usb_dfu_set_detach_cb(esp_usb_console_dfu_detach_cb); - - /* Enable interrupts on USB peripheral side */ - USB0.gahbcfg |= USB_GLBLLNTRMSK_M; - - /* Enable the interrupt handler */ - esp_intr_enable(s_usb_int_handle); - -#ifdef CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF - /* Install esp_rom_printf handler */ - ets_install_putc1(&esp_usb_console_write_char); -#endif // CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF - - return ESP_OK; -} - -/* Non-static to allow placement into IRAM by ldgen. - * Must be called with the write lock held. - */ -ssize_t esp_usb_console_flush_internal(size_t last_write_size) -{ - if (s_usb_tx_buf_pos == 0) { - return 0; - } - assert(s_usb_tx_buf_pos >= last_write_size); - ssize_t ret; - size_t tx_buf_pos_before = s_usb_tx_buf_pos - last_write_size; - int sent = cdc_acm_fifo_fill(s_cdc_acm_device, (const uint8_t*) s_usb_tx_buf, s_usb_tx_buf_pos); - if (sent == last_write_size) { - /* everything was sent */ - ret = last_write_size; - s_usb_tx_buf_pos = 0; - } else if (sent == 0) { - /* nothing was sent, roll back to the original state */ - ret = 0; - s_usb_tx_buf_pos = tx_buf_pos_before; - } else { - /* Some data was sent, but not all of the buffer. - * We can still tell the caller that all the new data - * was "sent" since it is in the buffer now. - */ - ret = last_write_size; - memmove(s_usb_tx_buf, s_usb_tx_buf + sent, s_usb_tx_buf_pos - sent); - s_usb_tx_buf_pos = s_usb_tx_buf_pos - sent; - } - return ret; -} - -ssize_t esp_usb_console_flush(void) -{ - if (s_cdc_acm_device == NULL) { - return -1; - } - write_lock_acquire(); - int ret = esp_usb_console_flush_internal(0); - write_lock_release(); - return ret; -} - -ssize_t esp_usb_console_write_buf(const char* buf, size_t size) -{ - if (s_cdc_acm_device == NULL) { - return -1; - } - if (size == 0) { - return 0; - } - write_lock_acquire(); - ssize_t tx_buf_available = ACM_BYTES_PER_TX - s_usb_tx_buf_pos; - ssize_t will_write = MIN(size, tx_buf_available); - memcpy(s_usb_tx_buf + s_usb_tx_buf_pos, buf, will_write); - s_usb_tx_buf_pos += will_write; - - ssize_t ret; - if (s_usb_tx_buf_pos == ACM_BYTES_PER_TX || buf[size - 1] == '\n') { - /* Buffer is full, or a newline is found. - * For binary streams, we probably shouldn't do line buffering, - * but text streams are likely going to be the most common case. - */ - ret = esp_usb_console_flush_internal(will_write); - } else { - /* nothing sent out yet, but all the new data is in the buffer now */ - ret = will_write; - } - write_lock_release(); - return ret; -} - -ssize_t esp_usb_console_read_buf(char *buf, size_t buf_size) -{ - if (s_cdc_acm_device == NULL) { - return -1; - } - if (!esp_usb_console_read_available()) { - return 0; - } - int bytes_read = cdc_acm_fifo_read(s_cdc_acm_device, (uint8_t*) buf, buf_size); - return bytes_read; -} - -esp_err_t esp_usb_console_set_cb(esp_usb_console_cb_t rx_cb, esp_usb_console_cb_t tx_cb, void *arg) -{ - if (s_cdc_acm_device == NULL) { - return ESP_ERR_INVALID_STATE; - } - s_rx_cb = rx_cb; - if (s_rx_cb) { - cdc_acm_irq_rx_enable(s_cdc_acm_device); - } else { - cdc_acm_irq_rx_disable(s_cdc_acm_device); - } - s_tx_cb = tx_cb; - if (s_tx_cb) { - cdc_acm_irq_tx_enable(s_cdc_acm_device); - } else { - cdc_acm_irq_tx_disable(s_cdc_acm_device); - } - s_cb_arg = arg; - return ESP_OK; -} - -bool esp_usb_console_read_available(void) -{ - if (s_cdc_acm_device == NULL) { - return false; - } - return cdc_acm_rx_fifo_cnt(s_cdc_acm_device) > 0; -} - -bool esp_usb_console_write_available(void) -{ - if (s_cdc_acm_device == NULL) { - return false; - } - return cdc_acm_irq_tx_ready(s_cdc_acm_device) != 0; -} - - -#ifdef CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF -/* Used as an output function by esp_rom_printf. - * The LF->CRLF replacement logic replicates the one in esp_rom_uart_putc. - * Not static to allow placement into IRAM by ldgen. - */ -void esp_usb_console_write_char(char c) -{ - char cr = '\r'; - char lf = '\n'; - - if (c == lf) { - esp_usb_console_write_buf(&cr, 1); - esp_usb_console_write_buf(&lf, 1); - } else if (c == '\r') { - } else { - esp_usb_console_write_buf(&c, 1); - } -} -static inline void write_lock_acquire(void) -{ - portENTER_CRITICAL_SAFE(&s_write_lock); -} -static inline void write_lock_release(void) -{ - portEXIT_CRITICAL_SAFE(&s_write_lock); -} - -#else // CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF - -static inline void write_lock_acquire(void) -{ -} - -static inline void write_lock_release(void) -{ -} -#endif // CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF diff --git a/components/esp_system/port/soc/esp32s2/usb_console.c b/components/esp_system/port/usb_console.c similarity index 92% rename from components/esp_system/port/soc/esp32s2/usb_console.c rename to components/esp_system/port/usb_console.c index c1875c2a4466..7e5dc5b7a7af 100644 --- a/components/esp_system/port/soc/esp32s2/usb_console.c +++ b/components/esp_system/port/usb_console.c @@ -28,6 +28,7 @@ #include "esp_rom_uart.h" #include "esp_rom_sys.h" #include "esp_rom_caps.h" +#ifdef CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/usb/usb_dc.h" #include "esp32s2/rom/usb/cdc_acm.h" #include "esp32s2/rom/usb/usb_dfu.h" @@ -35,7 +36,15 @@ #include "esp32s2/rom/usb/usb_os_glue.h" #include "esp32s2/rom/usb/usb_persist.h" #include "esp32s2/rom/usb/chip_usb_dw_wrapper.h" - +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/usb/usb_dc.h" +#include "esp32s3/rom/usb/cdc_acm.h" +#include "esp32s3/rom/usb/usb_dfu.h" +#include "esp32s3/rom/usb/usb_device.h" +#include "esp32s3/rom/usb/usb_os_glue.h" +#include "esp32s3/rom/usb/usb_persist.h" +#include "esp32s3/rom/usb/chip_usb_dw_wrapper.h" +#endif #define CDC_WORK_BUF_SIZE (ESP_ROM_CDC_ACM_WORK_BUF_MIN + CONFIG_ESP_CONSOLE_USB_CDC_RX_BUF_SIZE) @@ -61,8 +70,17 @@ static esp_timer_handle_t s_restart_timer; static const char* TAG = "usb_console"; +/* This lock is used for two purposes: + * - To protect functions which write something to USB, e.g. esp_usb_console_write_buf. + * This is necessary since these functions may be called by esp_rom_printf, so the calls + * may preempt each other or happen concurrently. + * (The calls coming from regular 'printf', i.e. via VFS layer, are already protected + * by a mutex in the VFS driver.) + * - To implement "osglue" functions of the USB stack. These normally require interrupts + * to be disabled. However on multi-core chips a critical section is necessary. + */ +static portMUX_TYPE s_lock = portMUX_INITIALIZER_UNLOCKED; #ifdef CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF -static portMUX_TYPE s_write_lock = portMUX_INITIALIZER_UNLOCKED; void esp_usb_console_write_char(char c); #define ISR_FLAG ESP_INTR_FLAG_IRAM #else @@ -74,8 +92,6 @@ void esp_usb_console_write_char(char c); static inline void write_lock_acquire(void); static inline void write_lock_release(void); -/* The two functions below need to be revisited in the multicore case */ -_Static_assert(SOC_CPU_CORES_NUM == 1, "usb_osglue_*_int is not multicore capable"); /* Other forward declarations */ void esp_usb_console_before_restart(void); @@ -85,9 +101,7 @@ void esp_usb_console_before_restart(void); */ void esp_usb_console_osglue_dis_int(void) { - if (s_usb_int_handle) { - esp_intr_disable(s_usb_int_handle); - } + portENTER_CRITICAL_SAFE(&s_lock); } /* Called by ROM to enable the interrupts @@ -95,9 +109,7 @@ void esp_usb_console_osglue_dis_int(void) */ void esp_usb_console_osglue_ena_int(void) { - if (s_usb_int_handle) { - esp_intr_enable(s_usb_int_handle); - } + portEXIT_CRITICAL_SAFE(&s_lock); } /* Delay function called by ROM USB driver. @@ -450,11 +462,11 @@ void esp_usb_console_write_char(char c) } static inline void write_lock_acquire(void) { - portENTER_CRITICAL_SAFE(&s_write_lock); + portENTER_CRITICAL_SAFE(&s_lock); } static inline void write_lock_release(void) { - portEXIT_CRITICAL_SAFE(&s_write_lock); + portEXIT_CRITICAL_SAFE(&s_lock); } #else // CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF diff --git a/components/esp_system/system_init_fn.txt b/components/esp_system/system_init_fn.txt index 93c6687425b6..0818eedf8455 100644 --- a/components/esp_system/system_init_fn.txt +++ b/components/esp_system/system_init_fn.txt @@ -31,7 +31,7 @@ # usb_console needs to create an esp_timer at startup. # This can be done only after esp_timer initialization, which is now in init_components0. -220: esp_usb_console_init_restart_timer in components/esp_system/port/soc/esp32s2/usb_console.c on BIT(0) +220: esp_usb_console_init_restart_timer in components/esp_system/port/usb_console.c on BIT(0) # usb_serial_jtag needs to create and acquire a PM clock at startup. # This makes more sense to be done after esp_pm_impl_init, which is initialized in init_components0.