espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.49k stars 7.26k forks source link

USB enumeration fails due to lack of USB_USBRST interrupt when PSRAM enabled and USB host is Bluetooth speaker (IDFGH-8009) #9519

Closed espradio closed 2 years ago

espradio commented 2 years ago

Environment

Problem Description

USB enumeration fails due to lack of USB_USBRST interrupt when(All of below true)

When trying USB mass storage with bluetooth speaker based USB host( No issue seen with WindowPC or Linux PC), its been found the USB enumeration fails due to USB_USBRST. I am able to reproduce the issue with tusb_serial_device example application in IDF.

Expected Behavior

Completes the USB enumeration

Actual Behavior

USB enumeration failes to due to lack USB_USBRST interrupt

Steps to reproduce

Able to reproduce the issue with tusb_serial_device example application in IDF v4.4.2 or master. Please find patch to show USB_USBRST not coming as expected Patch for v4.4.2

1. Tinyusb
diff --git a/components/tinyusb/additions/src/portable/espressif/esp32sx/dcd_esp32sx.c b/components/tinyusb/additions/src/portable/espressif/esp32sx/dcd_esp32sx.c
index 5cd9b3e355..8e656f87e2 100644
--- a/components/tinyusb/additions/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ b/components/tinyusb/additions/src/portable/espressif/esp32sx/dcd_esp32sx.c
@@ -157,6 +157,7 @@ static void enum_done_processing(void)
   }
 }

+static QueueHandle_t int_queue;

 /*------------------------------------------------------------------*/
 /* Controller API
@@ -165,6 +166,10 @@ void dcd_init(uint8_t rhport)
 {
   ESP_LOGV(TAG, "DCD init - Start");

+  int_queue = xQueueCreate(256, sizeof(uint32_t));
+  if (int_queue == NULL)
+      ESP_LOGE(TAG, "Failed to create q for for logging int status");
+
   // A. Disconnect
   ESP_LOGV(TAG, "DCD init - Soft DISCONNECT and Setting up");
   USB0.dctl |= USB_SFTDISCON_M; // Soft disconnect
@@ -726,6 +731,16 @@ static void handle_epin_ints(void)
   }
 }

+static int count;
+
+void dump_dcd_ints(void)
+{
+   uint32_t stat;
+
+   while (xQueueReceive(int_queue, &stat, pdMS_TO_TICKS(1000) != pdFALSE)) {
+       printf("######### order=%d int_stat=%x\n", count++, stat);
+   }
+}

 static void _dcd_int_handler(void* arg)
 {
@@ -735,6 +750,8 @@ static void _dcd_int_handler(void* arg)
   const uint32_t int_msk = USB0.gintmsk;
   const uint32_t int_status = USB0.gintsts & int_msk;

+  xQueueSendFromISR(int_queue, &int_status, false);
+
   if (int_status & USB_USBRST_M) {
     // start of reset
     ESP_EARLY_LOGV(TAG, "dcd_int_handler - reset");f
  1. tusb_serial_device example
    
    diff --git a/main/tusb_serial_device_main.c b/main/tusb_serial_device_main.c
    index bafc064..01de0c1 100644
    --- a/main/tusb_serial_device_main.c
    +++ b/main/tusb_serial_device_main.c
    @@ -48,6 +48,8 @@ void tinyusb_cdc_line_state_changed_callback(int itf, cdcacm_event_t *event)
     ESP_LOGI(TAG, "Line state changed! dtr:%d, rst:%d", dtr, rst);
    }

+void dump_dcd_ints(void); + void app_main(void) { ESP_LOGI(TAG, "USB initialization"); @@ -71,4 +73,6 @@ void app_main(void) CDC_EVENT_LINE_STATE_CHANGED, &tinyusb_cdc_line_state_changed_callback)); ESP_LOGI(TAG, "USB initialization DONE");

Debug Logs

Working case:

######### order=0 int_stat=400
######### order=1 int_stat=0
######### order=2 int_stat=800
######### order=3 int_stat=801000
######### order=4 int_stat=2000
######### order=5 int_stat=10
######### order=6 int_stat=10
######### order=7 int_stat=80000
######### order=8 int_stat=40000
######### order=9 int_stat=40000
######### order=10 int_stat=10
######### order=11 int_stat=10
######### order=12 int_stat=80000
######### order=13 int_stat=10
######### order=14 int_stat=10

Failure case:

######### order=0 int_stat=400
######### order=1 int_stat=0

Not able to get 0x800 USB reset interrupt when it failes

Bluetooth speaker has enough power to drive ESP32-S3 by making sure bluetooth speaker is connected to charging port while doing the experiment.

Attaching Test image based on v4.4.2 tusb_serial_device.bin.zip

espradio commented 2 years ago

Any update on this?

tore-espressif commented 2 years ago

Hello @espradio Thank you very much for the detailed bug report. However, it is difficult to reproduce, as it requires specific USB Host. As you mentioned, the enumeration works fine on the 'big OSes'.

Just to clarify:

Not able to get 0x800 USB reset interrupt when it failes

0x800 is USB suspend interrupt 0x801000 is USB reset interrupt

The best way to debug this is to use a USB bus analyzer, then you could see whether the reset is issued and when it is issued.

If you don't have the analyzer available, there are few thing that are worth trying. Please try combinations of the following:

  1. set your project to use Quad PSRAM (`Component config -> ESP PSRAM -> SPI RAM config -> Mode). Quad mode has shorter init time.
  2. disable SPI RAM test on init (Component config -> ESP PSRAM -> SPI RAM config -> Run memory test on SPI RAM initialization). This will speed up PSRAM init.
  3. disable USB Serial JTAG (Component config -> ESP System Settings -> Channel for console secondary output). USB Serial JTAG share USB PHY with USB-OTG peripheral, this could cause a problem during ESP boot and USB enumeration with certain hosts

Regards, Tomas

espradio commented 2 years ago

Hi @tore-espressif

Second option worked. Looks like this USB host is sensitive to call init after the power up. If I disable option 2, There is 400ms savings and it boots in ~300ms vs 700ms.

Thanks a lot for reply.

BTW. If I do option 1, Following issue happens. Looks like ESP32-S3-N8R8 does not support Quad. Any pointer for this.

Failure config

CONFIG_SPIRAM=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_QUAD=y
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
CONFIG_SPIRAM_MEMTEST=n

Working config

CONFIG_SPIRAM=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
CONFIG_SPIRAM_MEMTEST=n

Failure log for option 1. You can close this issue in either case 1. Just though of getting feedback on 1.

ELF file SHA256: 9d1f40b6c9c4e78d

Rebooting...

abort() was called at PC 0x403753fd on core 0
0x403753fd: call_start_cpu0 at esp-idf/components/esp_system/port/cpu_start.c:414 (discriminator 3)

Backtrace:0x40375aa6:0x3fceb2700x4037e3a5:0x3fceb290 0x403858ea:0x3fceb2b0 0x403753fd:0x3fceb320 0x403cd90c:0x3fceb340 0x403cdd75:0x3fceb380 0x403c99cd:0x3fceb4b0 0x40045c01:0x3fceb570  |<-CORRUPTED
0x40375aa6: panic_abort at esp-idf/components/esp_system/panic.c:402

0x4037e3a5: esp_system_abort at esp-idf/components/esp_system/esp_system.c:128

0x403858ea: abort at esp-idf/components/newlib/abort.c:46

0x403753fd: call_start_cpu0 at esp-idf/components/esp_system/port/cpu_start.c:414 (discriminator 3)
tore-espressif commented 2 years ago

@espradio Thank you for all the details. I'm happy it works for you now.

Looks like this USB host is sensitive to call init after the power up.

Hm, interesting. That shouldn't happen. Anyway, since your USB host is specific and there is a simple working workaround, I won't make any changes in our implementation for now.

BTW. If I do option 1, Following issue happens.

My bad, I could swear that Octal SPIRAM worked in Quad mode too, but it fails on my machine too. I'll check internally with SPIRAM team.

If you still want to run RAM test on startup, you can experiment with other optimizations too. There is a section in our documentation about Improving startup time.

Alvin1Zhang commented 2 years ago

Thanks for reporting, feel free to reopen.