UDD_Send() (uotghs_device.c) has an unbounded busy-wait on TXINI — permanent MCU hang if host doesn't set it (native USB CDC line-state related)
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 52/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 領域
- embedded-iot
調査の方向性
system/libsam/source/uotghs_device.c で UDD_Send、UDD_WaitIN、UDD_WaitOUT、UDD_WaitForINOrOUT を読み始め、続いて USBCore.cpp と CDC.cpp を通じてそれらの呼び出し元をたどります。提供された sketch とホスト設定でネイティブ CDC のハングを再現します。完了条件は、USB flag が欠落していても無限にスピンしなくなり、影響を受ける送信/待機パスが一貫して転送を報告または中止することです。
索引モデルが issue の本文から書いたものです。
説明
Summary
UDD_Send() in system/libsam/source/uotghs_device.c contains an unbounded busy-wait loop with no timeout, waiting for the TXINI (Transmit IN complete) flag on the target endpoint. If the host does not set this flag (e.g. around a USB line-state change such as DTR/RTS toggling on the native CDC port), the MCU hangs permanently in this loop, with interrupts still enabled and no way to recover except a full reset/power cycle.
uint32_t UDD_Send(uint32_t ep, const void* data, uint32_t len)
{
const uint8_t *ptr_src = data;
uint8_t *ptr_dest = (uint8_t *) &udd_get_endpoint_fifo_access8(ep);
uint32_t i;
while( UOTGHS_DEVEPTISR_TXINI != (UOTGHS->UOTGHS_DEVEPTISR[ep] & UOTGHS_DEVEPTISR_TXINI )) {}
...
(https://github.com/arduino/ArduinoCore-sam/blob/master/system/libsam/source/uotghs_device.c)
This is called from USBD_Send() in USBCore.cpp, which is the underlying function used by every SerialUSB.write()/println() call (via Serial_::write in CDC.cpp), as well as HID reports.
Related but similarly unbounded waits exist elsewhere in the same file (UDD_WaitIN, UDD_WaitOUT, UDD_WaitForINOrOUT) — all are plain while(...); with no timeout or bail-out condition.
How I found this
I have an Arduino Due (genuine, Rev3) that reliably hangs during extended native-USB operation on specific Windows 11 hosts (newer Intel xHCI controllers — Tiger Lake/Alder Lake generation). Full investigation history, including USB traffic capture (Wireshark/USBPcap) and elimination of third-party software as a cause, is documented here: https://github.com/arduino/ArduinoCore-sam/issues/71#issuecomment-5382181174
Using an ST-Link V2 + OpenOCD + GDB attached via the DEBUG (SWD) header, I was able to halt the MCU while it was hung (native USB unresponsive, but the rest of loop() — an independent LED blink — still running, i.e. not a full lockup: DHCSR.S_LOCKUP was 0, core was in normal Thread mode with interrupts enabled).
Register/symbol dump at the hang:
pc = 0x00081b06 -> inside UDD_Send+18
lr = 0x00080e99 -> called from USBD_Send() at USBCore.cpp:204
xpsr = 0x01000000 -> Thread mode, not inside an ISR
primask/faultmask = 0 -> interrupts not disabled
info line *0x00080e99 resolved cleanly to USBCore.cpp:204 inside USBD_Send, confirming the call chain Serial_::write → USBD_Send → UDD_Send, stuck spinning on the TXINI wait with no way out.
Reliable(-ish) repro
A minimal sketch (no HID/Joystick needed, plain CDC is enough):
bool state;
uint32_t Tim;
uint32_t TimLog;
void setup() {
pinMode(13, OUTPUT);
delay(1000);
SerialUSB.println(1);
}
void loop() {
if (millis() - Tim >= 500) {
Tim = millis();
digitalWrite(13, state);
state = !state;
}
if (millis() - TimLog >= 5000) {
TimLog = millis();
SerialUSB.println(millis());
}
}
- Left running for ~15-25 minutes on an affected Windows 11 host: hangs organically.
- Faster/more reliable trigger: from the host, open the native CDC COM port via .NET
System.IO.Ports.SerialPortwithout settingDtrEnable/RtsEnabletotruebefore.Open()— this toggles the CDC line state in a way that reliably triggers the hang within seconds in my testing. - Does not reproduce on Linux or in Windows Safe Mode on the same physical hardware — consistent with the theory that it's a host-timing-dependent race on whether
TXINIgets set before the firmware's next attempt to send.
Suggested direction for a fix
At minimum, every unbounded while(...) wait in uotghs_device.c (UDD_Send, UDD_WaitIN, UDD_WaitOUT, UDD_WaitForINOrOUT) should have a bounded timeout (e.g. based on millis() or a cycle counter) and return an error/abort the transfer instead of spinning forever when the expected hardware flag never arrives. I understand this changes the function signatures/call sites (currently void/unconditional uint32_t return used as byte count, not status) — happy to discuss/help test a patch if a maintainer can advise on the preferred approach (e.g. optional timeout parameter, or a global "USB write timeout" behavior similar to how other Serial implementations use setTimeout()).
Environment
- Board: Arduino Due (genuine, Rev3, native USB port)
- Core: Arduino SAM Boards (32-bit ARM Cortex-M3), package version installed via Boards Manager — 1.6.12
- Debug setup: ST-Link V2 (clone) via the onboard 4-pin SWD DEBUG header, OpenOCD 0.12.0, arm-none-eabi-gdb 4.8.3 (bundled with Arduino IDE's SAM toolchain)
- Host: Windows 11 (build 26100), Intel USB 3.10/3.20 xHCI controllers (
PCI\VEN_8086&DEV_51ED,PCI\VEN_8086&DEV_461E)
Happy to provide more register dumps, the .elf/.map files, or the full Wireshark capture if useful.
- 主要言語
- HTML
- スター
- 91
- フォーク
- 112
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
arduino/ArduinoCore-sam のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
arduino/ArduinoCore-sam#129 ·
-
難易度 3/5 半日 初心者へのやさしさ 62/100
arduino/ArduinoCore-sam#154 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 35/100
arduino/ArduinoCore-sam#151 · コメント 5 件 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 35/100
arduino/ArduinoCore-sam#147 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 42/100
arduino/ArduinoCore-sam#146 ·
arduino/ArduinoCore-sam の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
facebookincubator/muse-gadget-sdk#226 ·
メンテナーはふだん 1 日以内に返信
-
btnr (and keyr)オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
InfiniTimeOrg/InfiniTime#2492 ·
-
system: coco
難易度 1/5 1時間未満 初心者へのやさしさ 90/100
FujiNetWIFI/fujinet-config#274 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
espressif/esp-matter#1892 ·