arduino / arduino/ArduinoCore-renesas
goBootloader() does not enter the bootloader from a native-USB (SerialUSB) sketch on UNO R4 WiFi - a watchdog reset with the identical magic write does
- Dominant language
- C
- Stars
- 193
- Forks
- 112
- PR merge metrics
- No merged PRs in 30d
Description
### Summary
On the UNO R4 WiFi, calling the core's `goBootloader()` from a sketch that uses the **RA4M1 native USB** (`__USBStart()` + `SerialUSB`, enumerating `2341:006D`) does **not** enter the bootloader: no `2341:1002` bootloader device ever appears and the board becomes unflashable without a physical double-tap of RESET.
Keeping the magic write **byte-for-byte identical** and changing **only the reset source** — a watchdog reset instead of `NVIC_SystemReset()` — enters the bootloader reliably (reproduced many times; `bossac` upload then succeeds).
From a **bridge-mode** sketch (default `Serial`, `2341:1002`) the stock `goBootloader()` works correctly. So the failure is specific to the native-USB configuration.
This matters for headless/CI use: with a native-USB sketch there is currently no software path back into the bootloader (the 1200 bps touch is also unavailable — the toolchain aims it at the bridge PID, and the board's own `CheckSerialReset()` is on the port that is absent in that mode), so an automated upload loop requires physically touching the board.
### Environment
- Board: Arduino UNO R4 WiFi (RA4M1 / R7FA4M1AB), factory bootloader (never reflashed)
- Core: `framework-arduinorenesas-uno` via PlatformIO `renesas-ra@1.8.0`
- Host: Windows 10
- Upload path: `bossac` over the ESP32-S3 bridge
### Steps to reproduce
Sketch (native USB):
```cpp
#include
#include "boot.h"
void setup() {
__USBStart(); // route USB to the RA4M1 native port -> 2341:006D
SerialUSB.dtr();
SerialUSB.begin(115200);
delay(2000);
}
void loop() {
static uint32_t t = 0;
if (millis() - t >= 1000) { t = millis(); SerialUSB.print("HB "); SerialUSB.println(millis()/1000); }
if (SerialUSB.available()) {
if (SerialUSB.read() == 'X') {
SerialUSB.println("entering bootloader");
SerialUSB.flush();
delay(50);
goBootloader(); // <-- core function
}
}
}
```
1. Flash, confirm the heartbeat on `2341:006D`.
2. Send `X`.
3. **Observed:** no `2341:1002` bootloader device appears; the board does not become flashable. (An upload
attempt fails; only a physical double-tap of RESET recovers it.)
4. **Expected:** the board enters the BOSSA bootloader and enumerates as `2341:1002`.
### Workaround that works (same magic, different reset)
```cpp
#include
static void enterBootloaderViaWdt() {
R_SYSTEM->PRCR = (uint16_t)BSP_PRV_PRCR_PRC1_UNLOCK; // identical to goBootloader()
BOOT_DOUBLE_TAP_DATA = DOUBLE_TAP_MAGIC; // identical
R_SYSTEM->PRCR = (uint16_t)BSP_PRV_PRCR_LOCK; // identical
((R_USB_FS0_Type *)R_USB_FS0_BASE)->SYSCFG_b.DPRPU = 0; // identical
WDT.begin(50); // <-- instead of NVIC_SystemReset()
while (1) {} // let the watchdog fire
}
```
With this, the board enters the bootloader (`2341:1002` appears within ~1–2 s) and `bossac` uploads succeed. Reproduced repeatedly, including in a fully automated upload loop.
### What differs
Only the reset source. Everything else — the PRCR unlock/lock, the write of `DOUBLE_TAP_MAGIC` (`0x07738135`) to `BOOT_DOUBLE_TAP_DATA`, the `DPRPU = 0` USB detach — is identical, because the workaround is a copy of `goBootloader()` with `NVIC_SystemReset()` swapped for a watchdog reset.
Since the magic write is the same in both cases and the watchdog path *does* enter the bootloader, the write itself clearly takes effect. The difference appears to be in how the two reset sources interact with the native-USB configuration (backup-register retention across `SYSRESETREQ`? the USB MUX / port state after a software reset?). I have not been able to determine the mechanism from the outside, and I'd rather not guess in an issue — happy to run any diagnostic you suggest on the bench.
### Suggested fix
If the mechanism is confirmed, either make `goBootloader()` use a reset source that works in both configurations, or document that it is unsupported from native-USB sketches.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at goBootloader() in boot.h and compare its NVIC_SystemReset() path with the reported watchdog-reset workaround. Reproduce the native-USB sketch using __USBStart() and SerialUSB, then verify whether the board enumerates as 2341:1002 and accepts a bossac upload; done means reliable bootloader entry without a physical reset.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, cpp
- Domain
- embedded-iot
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100