|
| 1 | +# SWD flashing — RAM state contract |
| 2 | + |
| 3 | +When flashing Buddy firmware via SWD (e.g. with `st-flash` + ST-Link), the |
| 4 | +default flow is **incomplete on its own** and can leave the printer in a |
| 5 | +confused or stuck state on the next boot. This page documents the missing |
| 6 | +clear sequence and explains why. |
| 7 | + |
| 8 | +## TL;DR |
| 9 | + |
| 10 | +After `st-flash write`, run **before** the MCU reset: |
| 11 | + |
| 12 | +```tcl |
| 13 | +# OpenOCD script (interface/stlink.cfg + target/stm32f4x.cfg) |
| 14 | +
|
| 15 | +# 1. Reset boot-firmware data exchange in shared RAM |
| 16 | +# (DataExchange struct in src/common/data_exchange.cpp, |
| 17 | +# mapped to section .boot_fw_data_exchange at 0x20000000) |
| 18 | +mwb 0x20000000 0x00 ; fw_update_flag = FwAutoUpdate::off |
| 19 | +mwb 0x20000001 0x01 ; appendix_status (set to "present") |
| 20 | +mwb 0x20000002 0x00 ; fw_signature |
| 21 | +mwb 0x20000003 0x01 ; bootloader_valid |
| 22 | +
|
| 23 | +# 2. Enable backup-SRAM clock and PWR access |
| 24 | +mmw 0x40023830 0x00040000 0 ; RCC_AHB1ENR |= BKPSRAMEN (bit 18) |
| 25 | +mmw 0x40007000 0x00000100 0 ; PWR_CR |= DBP (bit 8) |
| 26 | +
|
| 27 | +# 3. Clear the first 16 bytes of backup SRAM |
| 28 | +# (power-panic storage in src/common/power_panic_storage_bkpsram.cpp) |
| 29 | +mww 0x40024000 0x00000000 |
| 30 | +mww 0x40024004 0x00000000 |
| 31 | +mww 0x40024008 0x00000000 |
| 32 | +mww 0x4002400C 0x00000000 |
| 33 | +
|
| 34 | +# 4. NVIC system reset via AIRCR (writes the VECTKEY + SYSRESETREQ) |
| 35 | +mww 0xE000ED0C 0x05FA0004 |
| 36 | +shutdown |
| 37 | +``` |
| 38 | + |
| 39 | +Skip step 1 and the bootloader may interpret stale RAM as a request to |
| 40 | +re-flash from USB, freezing at "50%" with no BBF to flash. Skip step 3 |
| 41 | +and the firmware may interpret stale backup SRAM as a recoverable |
| 42 | +power-panic from a prior session. |
| 43 | + |
| 44 | +## Why st-flash alone isn't enough |
| 45 | + |
| 46 | +The xBuddy STM32F427 has three RAM regions that survive an SWD flash: |
| 47 | + |
| 48 | +| Region | Address | Used by | |
| 49 | +| ----------------- | ------------- | ---------------------------------------- | |
| 50 | +| Shared SRAM | `0x20000000` | DataExchange between bootloader & FW | |
| 51 | +| Main SRAM | `0x20000020+` | Normal heap/stack | |
| 52 | +| Backup SRAM | `0x40024000` | Power-panic state (`MAGIC_VALID_VALUE`) | |
| 53 | + |
| 54 | +`st-flash write` only touches the application area in internal flash |
| 55 | +(`0x08020000` onwards). It does NOT clear any of the SRAM regions |
| 56 | +above, and it does NOT issue the same kind of cold-boot reset the |
| 57 | +printer performs via its power switch. |
| 58 | + |
| 59 | +The result is that on the next boot, both the bootloader and the main |
| 60 | +firmware see whatever values were in RAM when SWD started talking to |
| 61 | +the MCU — which is usually leftover state from the firmware that was |
| 62 | +running just before the flash. Two specific failure modes: |
| 63 | + |
| 64 | +### 1. False firmware-update trigger (shared SRAM) |
| 65 | + |
| 66 | +The DataExchange struct at `0x20000000` starts with: |
| 67 | + |
| 68 | +```cpp |
| 69 | +struct __attribute__((packed)) DataExchange { |
| 70 | + FwAutoUpdate fw_update_flag; // 1 byte, enum |
| 71 | + uint8_t appendix_status; |
| 72 | + uint8_t fw_signature; |
| 73 | + uint8_t bootloader_valid; |
| 74 | + ... |
| 75 | +}; |
| 76 | +``` |
| 77 | + |
| 78 | +`FwAutoUpdate` is an `enum class : uint8_t` with values like `on=0xAA`, |
| 79 | +`off=0x00`, `older=0x55`, `specified=0xBB`. The bootloader reads this |
| 80 | +byte during boot to decide whether to re-flash from `firmware.bbf` on |
| 81 | +USB. If the leftover byte happens to match one of the "do an update" |
| 82 | +values (~3% chance per random byte across the enum range), the |
| 83 | +bootloader hangs trying to flash a file that isn't there — the |
| 84 | +infamous "stuck at 50%" symptom. |
| 85 | + |
| 86 | +Clearing the first four bytes to `00 01 00 01` puts the bootloader |
| 87 | +back in the normal "no update requested, appendix present, signed" |
| 88 | +state. |
| 89 | + |
| 90 | +### 2. False power-panic recovery (backup SRAM) |
| 91 | + |
| 92 | +`backup_sram_data_t` at `0x40024000` ends with a 32-bit `magic_valid` |
| 93 | +field set to `0xFA0746DC` whenever there's recoverable state. The |
| 94 | +firmware also checks CRCs over the data, so a truly random garbage |
| 95 | +match is extraordinarily unlikely (~1/2³² × CRC odds). In practice |
| 96 | +this is much less of a problem than the shared-RAM case — but the |
| 97 | +power-panic path takes long enough to evaluate that even a *correct* |
| 98 | +"no panic recorded" determination delays boot. Clearing the magic |
| 99 | +upfront skips the check entirely. |
| 100 | + |
| 101 | +If you only want to fix one thing, fix shared SRAM. |
| 102 | + |
| 103 | +## Reference openocd script |
| 104 | + |
| 105 | +A working end-to-end SWD flash including the steps above is in the |
| 106 | +project's `flash_coreone.sh` (downstream — not in the upstream tree). |
| 107 | +The relevant openocd invocation is: |
| 108 | + |
| 109 | +```sh |
| 110 | +openocd -f interface/stlink.cfg -f target/stm32f4x.cfg \ |
| 111 | + -c "init; halt" \ |
| 112 | + -c "mwb 0x20000000 0x00; mwb 0x20000001 0x01; mwb 0x20000002 0x00; mwb 0x20000003 0x01" \ |
| 113 | + -c "mmw 0x40023830 0x00040000 0; mmw 0x40007000 0x00000100 0" \ |
| 114 | + -c "mww 0x40024000 0x00000000; mww 0x40024004 0x00000000; mww 0x40024008 0x00000000; mww 0x4002400C 0x00000000" \ |
| 115 | + -c "mww 0xE000ED0C 0x05FA0004" \ |
| 116 | + -c "shutdown" |
| 117 | +``` |
| 118 | + |
| 119 | +## Notes |
| 120 | + |
| 121 | +- A hard power-cycle (turn the printer off at the wall, wait ~5 s, on |
| 122 | + again) accomplishes the same thing as the openocd sequence, because |
| 123 | + all SRAM regions lose state without standby power on the V_BAT pin. |
| 124 | + The openocd path exists so the SWD flow can be fully scripted |
| 125 | + without physical access to the power switch. |
| 126 | +- These details apply specifically to the xBuddy STM32F427-based |
| 127 | + printers (Core One/+, MK4, MK3.9, MK3.5, …). Other Buddy variants |
| 128 | + (Mini, XL) may have different RAM layouts. |
0 commit comments