This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS570LS1224: Field-safe bootloader update with a “rescue stub”

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_stub section, 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_int00 at 0x0002_EB7C).

    • Else → branch to BL (_c_int00 at 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)

  1. Startup: copies F021 Flash API and required constants to SRAM (we never execute flash API from flash during erase/program).

  2. 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.

  3. 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).

  4. Switch to BL: either

    • do a clean branch to BL _c_int00 (disable IRQ/FIQ, DSB/ISB, set VBAR=0, then BX), or

    • trigger a warm reset (SYSECR) right after the vector patch, which is often simpler/cleaner on R-class.
      We’ve tested both.

  5. 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.

  • Hi Arslan,

    Apologies for the delayed response! 
    We have our own internal AI which can analyze all the documents related to controller and all the past issues to produce suggestions. On first level i used this AI for your questions and here are some useful suggestions i got from tool:

    The issue appears to be related to the interaction between flash programming, ECC (Error Correction Code), and cold boot behavior. Let me break down the key points and propose a solution:

    1. Flash Programming and ECC Considerations:
    • The TMS570LS1224 has a 144-bit programming width (128 bits data + 16 bits ECC) (3)
    • The bank data width is 16 bytes (128/8) (3)
    • When programming flash, the starting address plus number of bytes must not exceed the bank data width (3)
    1. Vector Table and Cold Boot Behavior:
    • The bootloader vectors must be at 0x0000_0000 for compatibility with deployed units
    • Only flash memory retains data after a cold reset (8)
    • The rescue stub approach is valid, but the implementation needs careful consideration of flash programming constraints
    1. Root Cause Analysis: The issue where "BL comes up once but doesn't boot on cold power-cycle" likely stems from:
    • ECC/phrase alignment sensitivity when programming the vector table
    • The 32-byte single write to 0x0000..0x001F may not be properly handling ECC generation
    • The flash programming width constraints may be affecting the vector table integrity
    1. Proposed Solution: Here's a modified approach that should address the cold boot issue:

    1. For the rescue stub implementation:
       - Program the first 32 bytes (0x0000-0x001F) in a single F021 call with AutoECC
       - Ensure the branch instruction at 0x0000 is properly aligned within the 16-byte bank width
       - Make all vector entries (0x00-0x1C) branch to the stub for consistency
    
    2. For flash programming:
       if ((Address % 16) + BytesToProgram <= 0x0F) {
          // Can program directly in one operation
          Flash_Program(Address, Data, BytesToProgram);
       } else {
          // Split the programming into bank-aligned chunks
          uint8_t firstChunkSize = 16 - (Address % 16);
          Flash_Program(Address, Data, firstChunkSize);
          Flash_Program(Address + firstChunkSize, 
                       Data + firstChunkSize,
                       BytesToProgram - firstChunkSize);
       }

    1. Additional Recommendations:
    • Verify ECC generation is enabled and properly configured
    • Consider using the Flash Emulating EEPROM (FEE) for status fields (5)
    • Implement proper clean handoff measures (disable IRQ/FIQ, DSB/ISB) before branching
    • Add validation of the programmed vector table contents after writing

    --
    Thanks & regards,
    Jagadish.