Part Number: TMS570LS1224
Tool/software:
We must update the device bootloader (BL) itself in the field over CAN, without bricking units if power drops mid-update. All deployed units run a single BL with vectors at 0x0000_0000. We can’t change the memory layout in the fleet.
Why we chose a “rescue stub” (and not a dual-BL / A/B scheme)
-
Compatibility: Existing units expect the BL at 0x0000 (Sector0 vectors). Moving BL vectors or adding a second BL region would break deployed images and complicate servicing.
-
Flash budget & complexity: A/B (dual BL) needs extra reserved flash, duplicated init (VIM/ESM/MPU/cache), cross-signing/rollback logic. Our constraint is “minimal change, maximum safety”.
-
Fail-safe first instruction: A tiny stub placed outside Sector0 lets the very first fetch after reset decide: “BL valid? → jump BL; else → stay in updater to re-program BL.” That keeps the brick window small even if power dies during BL erase.
Components and addresses
-
Bootloader (BL): lives at Bank0/Sector0; vectors at 0x0000_0000; BL entry (
_c_int00) currently at 0x0000_8258 (from BL .map). -
BL Updater app: a small app that programs the new BL. Its own vectors are at 0x0002_0020; code from 0x0002_0140 upward; includes a rescue stub at 0x0002_0040 (separate
.rescue_stubsection, retained in the linker). -
Rescue stub (in updater): minimal ARM code. On reset:
-
Reads a check word in BL area (e.g. at 0x0000_0100).
-
If erased/invalid → branch to updater (
_c_int00at 0x0002_EB7C). -
Else → branch to BL (
_c_int00at 0x0000_8258). -
We also add clean hand-off measures (disable IRQ/FIQ, DSB/ISB) before branching.
-
How the BL Updater works today (step-by-step)
-
Startup: copies F021 Flash API and required constants to SRAM (we never execute flash API from flash during erase/program).
-
Patch Sector0 vectors once:
-
We erase Sector0 and then program 0x0000..0x001F in a single 32-byte F021 call (AutoECC on).
-
At 0x0000 we write a
B 0x0002_0040(long branch) so reset fetches the rescue stub first. -
We tried two variants for 0x04..0x1F:
(a) copy BL’s original words, or
(b) make all eight entries (0x00..0x1C) branch to the stub to catch any early exceptions.
-
-
Program BL body: we write the new BL from 0x0000_0020 upward in 4 KB chunks. We clamp erase/program ranges so Sector0 isn’t erased again (i.e. we don’t touch 0x0000..0x001F after the single 32-byte write).
-
Switch to BL: either
-
do a clean branch to
BL _c_int00(disable IRQ/FIQ, DSB/ISB, set VBAR=0, thenBX), or -
trigger a warm reset (SYSECR) right after the vector patch, which is often simpler/cleaner on R-class.
We’ve tested both.
-
-
Power constraints: we also have a supply check (KL30) to avoid attempting a BL flash when input is too low (we can hold power ~50 ms; a full BL erase+program is ~160 ms).
Observed behavior (the issue)
-
If we program the BL alone (via J-Flash), cold power-cycle boots BL every time.
-
If we run the updater, patch vectors, program BL body, and warm reset, BL comes up once (CAN banner is sent).
-
But on a cold power-cycle, BL doesn’t boot (no CAN banner).
-
A read-back shows the only difference vs a known-good BL image is the first 0x20 bytes (our patched vectors). If we restore the original BL 0x00..0x1F, cold boot works again.
-
If we attempt to program 0x0000 in smaller pieces, the F021 FSM may stall; writing the entire 32 bytes in one call avoids this (suggesting ECC/phrase alignment sensitivity).
What we’ve tried / considered
-
Making all 8 vector entries point to the stub (to avoid exceptions landing in half-initialized BL).
-
Doing a clean hand-off (disable IRQ/FIQ, DSB/ISB, VBAR write) before branching to BL.
-
Alternatively, vector patch then immediate warm reset to let BL start from a clean slate.
-
Ensuring the long branch at 0x0000 uses the correct imm24 to reach 0x0002_0040 (within ±32 MB; fine).
-
Confirming BL entry addresses from both .map files and keeping LSB=0 (ARM state).
Why not “jump from one BL to another BL” instead of a stub?
-
We only have one BL region at 0x0000 on deployed units. Introducing a second BL (A/B) would require a new vector strategy (relocate VBAR or mirror a second vector table) and respin the field layout.
-
The stub lets us keep all legacy assumptions (BL vectors at 0x0) yet still add a fail-safe decision at the earliest possible instruction.