现象
今天在给ESP32S3烧录固件之后发现一个问题
原本的检测串口是否打开的代码失效了
原本代码会阻塞直到电脑打开串口监视器, 而现在则是一旦连接到电脑就跳出
排查过程
排查后发现在HWCDC.h中对于HWCDC将运算符重载为HWCDC::isCDC_Connected(), 同时HWCDC::isConnected() 也内联到HWCDC::isCDC_Connected()
而HWCDC::isCDC_Connected() 内部的逻辑是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| bool HWCDC::isCDC_Connected() { static bool running = false;
if (!isPlugged()) { connected = false; running = false; return false; }
if (connected) { running = false; return true; }
if (running == false && !connected) { usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); }
usb_serial_jtag_ll_txfifo_flush(); running = true; return false; }
|
这里的connected变量因为误判在上电时为True (具体原因我也不清楚)
我尝试了 pioarduino-espressif32 的很多版本的平台(55.03.311, 55.03.31-2, 54.03.21), 但是无一例外全部不行, 但是在Arduino IDE中编译的固件则没有此问题, 且以前我使用PIO编译出来的固件也没有任何问题, 所以说可能是个玄学bug(?)
解决方案
在Serial.begin()之前加一个Serial.end()
Serial.end()的实现是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void HWCDC::end() { usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK); usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_LL_INTR_MASK); esp_intr_free(intr_handle); intr_handle = NULL; if (tx_lock != NULL) { vSemaphoreDelete(tx_lock); tx_lock = NULL; } setRxBufferSize(0); setTxBufferSize(0); if (arduino_hw_cdc_event_loop_handle) { esp_event_loop_delete(arduino_hw_cdc_event_loop_handle); arduino_hw_cdc_event_loop_handle = NULL; } HWCDC::deinit(this); setDebugOutput(false); connected = false; }
|
会把connected置为 false
最终初始化代码为
1 2 3 4 5 6 7 8
| Serial.end(); Serial.begin(115200);
while(!Serial);
|
这样就不会再上电就返回 true 啦
如果还不行的话可以试试 给图灵和冯诺依曼老祖点根香 检查ARDUINO_USB_MODE 宏是否定义且等于1 (Arduino IDE 是 “工具” -> “USB CDC On Boot: “ -> “Enable”)
相似案例
fix(usb_hw_serial): fixes connected state after sketch is uploaded by SuGlider · Pull Request #12184 · espressif/arduino-esp32