Skip to content

Commit b0a7973

Browse files
authored
feat(hwcdc): Fixes HWCDC fw uploading (espressif#9660)
1 parent 5492733 commit b0a7973

File tree

4 files changed

+65
-22
lines changed

4 files changed

+65
-22
lines changed

Diff for: cores/esp32/HWCDC.cpp

+61-19
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "esp_intr_alloc.h"
2424
#include "soc/periph_defs.h"
2525
#include "hal/usb_serial_jtag_ll.h"
26+
#include "esp_private/startup_internal.h"
27+
#include "esp_freertos_hooks.h"
2628

2729
ESP_EVENT_DEFINE_BASE(ARDUINO_HW_CDC_EVENTS);
2830

@@ -33,8 +35,47 @@ static intr_handle_t intr_handle = NULL;
3335
static volatile bool connected = false;
3436
static xSemaphoreHandle tx_lock = NULL;
3537

36-
static volatile unsigned long lastSOF_ms;
37-
static volatile uint8_t SOF_TIMEOUT;
38+
// SOF in ISR causes problems for uploading firmware
39+
//static volatile unsigned long lastSOF_ms;
40+
//static volatile uint8_t SOF_TIMEOUT;
41+
// detecting SOF from a timer seems to work with esptool.py
42+
static volatile bool s_usb_serial_jtag_conn_status;
43+
static volatile uint32_t remaining_allowed_no_sof_ticks;
44+
#define USJ_DISCONNECT_CONFIRM_PERIOD_MS 5
45+
#define ALLOWED_NO_SOF_TICKS pdMS_TO_TICKS(USJ_DISCONNECT_CONFIRM_PERIOD_MS)
46+
47+
static void IRAM_ATTR usb_serial_jtag_sof_tick_hook(void)
48+
{
49+
// SOF packet is sent by the HOST every 1ms on a full speed bus
50+
// Between two consecutive tick hooks, there will be at least 1ms (selectable tick rate range is 1 - 1000Hz)
51+
// Therefore, SOF intr bit must have be raised at every tick hook if it is connected to a HOST
52+
// Here, the strategy is: Always assume USB Serial/JTAG is connected until we are sure it is not connected
53+
// Consider it is disconnected only if SOF intr bit is not raised within (ALLOWED_NO_SOF_TICKS + 1) tick periods
54+
bool sof_received = USB_SERIAL_JTAG.int_raw.sof_int_raw == 1;
55+
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF);
56+
57+
if (s_usb_serial_jtag_conn_status != sof_received) {
58+
if (!sof_received) {
59+
if (remaining_allowed_no_sof_ticks > 0) {
60+
remaining_allowed_no_sof_ticks--;
61+
} else {
62+
s_usb_serial_jtag_conn_status = false;
63+
}
64+
} else {
65+
s_usb_serial_jtag_conn_status = true;
66+
remaining_allowed_no_sof_ticks = ALLOWED_NO_SOF_TICKS;
67+
}
68+
}
69+
70+
}
71+
72+
// runs on Core 0
73+
ESP_SYSTEM_INIT_FN(usb_serial_jtag_conn_status_init, BIT(0))
74+
{
75+
s_usb_serial_jtag_conn_status = true;
76+
remaining_allowed_no_sof_ticks = ALLOWED_NO_SOF_TICKS;
77+
esp_register_freertos_tick_hook(usb_serial_jtag_sof_tick_hook);
78+
}
3879

3980
// timeout has no effect when USB CDC is unplugged
4081
static uint32_t tx_timeout_ms = 100;
@@ -86,7 +127,7 @@ static void hw_cdc_isr_handler(void *arg) {
86127
if (tx_ring_buf != NULL && usb_serial_jtag_ll_txfifo_writable() == 1) {
87128
// We disable the interrupt here so that the interrupt won't be triggered if there is no data to send.
88129
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
89-
size_t queued_size;
130+
size_t queued_size = 0;
90131
uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(tx_ring_buf, &queued_size, 64);
91132
// If the hardware fifo is avaliable, write in it. Otherwise, do nothing.
92133
if (queued_buff != NULL) { //Although tx_queued_bytes may be larger than 0. We may have interrupt before xRingbufferSend() was called.
@@ -128,19 +169,19 @@ static void hw_cdc_isr_handler(void *arg) {
128169
connected = false;
129170
}
130171

131-
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SOF) {
132-
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF);
133-
lastSOF_ms = millis();
134-
}
172+
// if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SOF) {
173+
// usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF);
174+
// lastSOF_ms = millis();
175+
// }
135176

136177
if (xTaskWoken == pdTRUE) {
137178
portYIELD_FROM_ISR();
138179
}
139180
}
140181

141-
inline bool HWCDC::isPlugged(void)
182+
bool HWCDC::isPlugged(void)
142183
{
143-
return (lastSOF_ms + SOF_TIMEOUT) >= millis();
184+
return s_usb_serial_jtag_conn_status; //(lastSOF_ms + SOF_TIMEOUT) >= millis();
144185
}
145186

146187
bool HWCDC::isCDC_Connected()
@@ -151,10 +192,10 @@ bool HWCDC::isCDC_Connected()
151192
if (!isPlugged()) {
152193
connected = false;
153194
running = false;
154-
SOF_TIMEOUT = 5; // SOF timeout when unplugged
195+
// SOF_TIMEOUT = 5; // SOF timeout when unplugged
155196
return false;
156-
} else {
157-
SOF_TIMEOUT = 50; // SOF timeout when plugged
197+
//} else {
198+
// SOF_TIMEOUT = 50; // SOF timeout when plugged
158199
}
159200

160201
if (connected) {
@@ -232,11 +273,12 @@ static void ARDUINO_ISR_ATTR cdc0_write_char(char c) {
232273
xRingbufferSend(tx_ring_buf, (void*) (&c), 1, tx_timeout_ms / portTICK_PERIOD_MS);
233274
}
234275
usb_serial_jtag_ll_txfifo_flush();
276+
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
235277
}
236278

237279
HWCDC::HWCDC() {
238-
lastSOF_ms = 0;
239-
SOF_TIMEOUT = 5;
280+
// lastSOF_ms = 0;
281+
// SOF_TIMEOUT = 5;
240282
}
241283

242284
HWCDC::~HWCDC(){
@@ -286,8 +328,8 @@ void HWCDC::begin(unsigned long baud)
286328
}
287329

288330
// the HW Serial pins needs to be first deinited in order to allow `if(Serial)` to work :-(
289-
deinit();
290-
delay(10); // USB Host has to enumerate it again
331+
//deinit();
332+
//delay(10); // USB Host has to enumerate it again
291333

292334
// Configure PHY
293335
// USB_Serial_JTAG use internal PHY
@@ -300,7 +342,7 @@ void HWCDC::begin(unsigned long baud)
300342
USB_SERIAL_JTAG.conf0.usb_pad_enable = 1;
301343
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
302344
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT
303-
| USB_SERIAL_JTAG_INTR_BUS_RESET | USB_SERIAL_JTAG_INTR_SOF);
345+
| USB_SERIAL_JTAG_INTR_BUS_RESET /*| USB_SERIAL_JTAG_INTR_SOF*/);
304346
if(!intr_handle && esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_isr_handler, NULL, &intr_handle) != ESP_OK){
305347
isr_log_e("HW USB CDC failed to init interrupts");
306348
end();
@@ -554,9 +596,9 @@ void HWCDC::setDebugOutput(bool en)
554596
{
555597
if(en) {
556598
uartSetDebug(NULL);
557-
ets_install_putc1((void (*)(char)) &cdc0_write_char);
599+
ets_install_putc2((void (*)(char)) &cdc0_write_char);
558600
} else {
559-
ets_install_putc1(NULL);
601+
ets_install_putc2(NULL);
560602
}
561603
}
562604

Diff for: cores/esp32/USBCDC.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,9 @@ void USBCDC::setDebugOutput(bool en)
432432
{
433433
if(en) {
434434
uartSetDebug(NULL);
435-
ets_install_putc1((void (*)(char)) &cdc0_write_char);
435+
ets_install_putc2((void (*)(char)) &cdc0_write_char);
436436
} else {
437-
ets_install_putc1(NULL);
437+
ets_install_putc2(NULL);
438438
}
439439
}
440440

Diff for: cores/esp32/esp32-hal-uart.c

+1
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ void uart_install_putc()
778778
ets_install_putc1(NULL);
779779
break;
780780
}
781+
ets_install_putc2(NULL);
781782
}
782783

783784
// Routines that take care of UART mode in the HardwareSerial Class code

Diff for: libraries/ESP32/examples/HWCDC_Events/HWCDC_Events.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ void loop() {
8585
Serial0.print(HWCDC_Status());
8686

8787
if (USBSerial) {
88-
USBSerial.printf(" [%ld] connected\n\r", counter);
88+
USBSerial.printf(" [%d] connected\n\r", counter);
8989
}
9090
// sends all bytes read from UART0 to USB Hardware Serial
9191
while (Serial0.available()) USBSerial.write(Serial0.read());

0 commit comments

Comments
 (0)