[FAQ] C2000 Bootloading Design Considerations

Other Parts Discussed in Thread: C2000WARE

This thread will discuss the best practices for custom bootloading on the following devices:

  • F2807x
  • F2837xS
  • F2837xD
  • F28004x
  • F2838x
  • F28002x
  • F28003x
  • F280013x
  • F280015x
  • F28P65x
  • F28P55x
  • F28E12x
  • Terminology

    ROM Bootloaders: Code loading utilities provided in the device's Boot ROM, restricted to only program RAM.

    Flash Kernels: Code loading intermediate loaded by the ROM Bootloader into RAM first, then used to program the on-chip flash. 

    Flash Bootloaders: Custom bootloader stored in on-chip flash to program flash contents directly. 

    Secondary Bootloader (SBL): Second-stage bootloader that runs after the primary boot flow in the ROM, intended to perform more complex actions (configure specific peripherals, verify code integrity, etc.).

    Getting Started

    Please refer to SPRUJH3 to understand bootloading offerings on C28x MCUs.

    Memory Management

    RAM Based Solution

    Given that the ROM bootloaders are limited to program the RAM only, flash kernels are employed as an intermediate to program firmware into the flash by leveraging the Flash API. Flash kernels are loaded into the RAM by ROM bootloader first and execution is transferred to the flash kernel. Then, the flash kernel can receive and download the application firmware to flash. More details can be found in Section 3.2 of SPRUJH3.

    TI offers flash kernel examples for the following peripherals and device families:

    SCI

    F2802x, F2803x, F2805x, F2806x, F2833x

    F2807x, F2837xD, F2837xS, F28004x, F2838x, F28002x, F28003x, F280013x, F280015x, F28P65x, F28P55x, F28E12x

    SPRABV4
    DCAN F28003x, F28P65x, F280015x SPRAD51
    MCAN F28003x, F28P65x, F28P55x SPRAD51
    USB F2837xD SPRACO7

    Flash Based Solution

    Instead of using a RAM kernel, which has to be re-downloaded every Power-On Reset (POR) using the ROM bootloaders, users can alternatively store a bootloader in the flash. On reset, the device can be configured to boot directly to flash to load/program code directly. This eliminates the need to download a flash kernel first with the ROM bootloaders by storing a bootloader in the flash (to persist after POR).

    The general recommendation is to modify the flash kernel's linker command file to execute from the flash instead of RAM (refer to Section 5.2 of SPRUJH3 for steps).

    There are also Live Firmware Update (LFU) solutions for certain device families, which have flash bootloaders implemented for reference:

    F28002x C2000Ware_XX_XX_XX_XX\driverlib\f28002x\examples\flash\flash_kernel_ex3_sci_flash_kernel SPRUIU8
    F28003x C2000Ware_XX_XX_XX_XX\driverlib\f28003x\examples\flash\flash_kernel_ex3_sci_flash_kernel SPRUIU9, TIDUEY4
    F28004x C2000Ware_XX_XX_XX_XX\driverlib\f28003x\examples\flash\flashapi_ex2_sci_kernel SPRUIU8, TIDUEY4
    F28P55x C2000Ware_XX_XX_XX_XX\driverlib\f28p55x\examples\flash\flash_kernel_ex3_sci_flash_kernel SPRUIU9
    F28P65x C2000Ware_XX_XX_XX_XX\driverlib\f28p65x\examples\c28x_dual\flash_kernel\can_flash_lfu_sbl_multi_f28p65x SPRUIU8, TIDUEY4

    Single vs. Multi Flash Bank Considerations

    To enable seamless transfer of control from old firmware to new firmware multi-bank flash support is a critical feature. The flash technology used on C28x devices does not permit simultaneous reads and writes to a given flash bank, so this model allows one bank to execute firmware, and other bank(s) to be programmed. Please consult the Flash Memory Map section in the Data Sheet for device-specific flash organization.

    With this in mind:

    • If a single-bank flash device is used, then it is necessary to execute the bootloader's flash operations from the RAM.
    • If LFU is required, then only relevant portions of the application need to run from RAM (e.g. any ISRs that are periodically called and might be called during a live update).
      • Note that depending on the application size, you may be able to only fit in one version of the application in flash.

    In summary, for the single flash bank use-case: a portion of the bootloader, a portion of the application (depending on if LFU is required), and the entire Flash API library (contained within the bootloader) needs to run from RAM.

    Configuring the Boot Mode

    Please refer to Section 2 in SPRUJH3 for details on how to configure the device boot configuration registers in the DCSM user OTP.

    If using a custom bootloader stored the flash, then "Boot to Flash" should be configured. Please ensure that the flash boot option pertains to the correct flash entry point (generally the bootloader's codestart).

    Programming Firmware to Flash

    Flash API Usage

    Please refer to this exhaustive E2E FAQ on C2000 Flash API Usage:  [FAQ] FAQ on Flash API usage for C2000 devices 

    Each device family has a device-specific Flash API reference guide, linked in C2000Ware at: C2000Ware_XX_XX_XX_XX\libraries\flash_api\device_family\docs

    Firmware Redundancy

    In multi-bank configurations, it is recommended for there to be redundancy in firmware to ensure the device can recover if power-failure is encountered during firmware update. This can be accomplished using bank selection logic (described below).

    In short, the 'KEY' value indicates if the flash bank's firmware is valid after program/verification procedures are complete. If this value is not written due to an interruption, then the device will not boot to the incomplete firmware and instead branch to the older, valid firmware version. Then, the user can re-attempt to program the new firmware.

    Branch to Application

    When branching from the bootloader to the application, the user should be performing a branch to the codestart of the application (to execute the application's codestartbranch.asm routine). If performing a LFU, then the user may need to branch to different entry points to perform various LFU functions. Generally, the most important thing is that the target branch address is absolute. 

    Below are a few methods to perform a branch:

    1) Direct Branching (Assembly Inline): 

    For jumping to a specific absolute flash address, inline assembly can be used to employ the LB instruction:

    Source: SPRU430

    Code Example:

    asm("    LB 0x080000"); // Long Branch to address


    2) Function Pointer (C-style):

    A function pointer can be cast and called:

    ((void(*)())(0x80000))(); // Direct jump to 0x80000

    Bank Selection Logic

    Bank selection logic allows the bootloader to determine which, if any, of the flash banks are programmed with valid application firmware, and which bank contains the most recent application firmware version. Thus, bank selection logic is the entry point of the software system, that is, it should be branched to first from the Boot ROM on reset. Please note that only one flash bank needs to store the bank selection logic. 

    In the LFU examples released by TI, bank selection logic is implemented using the following metadata (stored at a reserved location in each flash bank):

    • START – indicates that Flash erase is complete and program/verification is about to begin with a specific pattern (ex. 0x5B5B5B5B)
    • KEY – firmware in a bank is considered valid if this location contains a specific pattern (ex. 0x5A5A5A5A)
      • Only program this pattern after firmware program/verification is complete
    • REV – firmware revision number used by the bank selection logic to determine the latest firmware version in the flash banks

    On device reset, execution starts at the default boot to flash entry point, 0x80000, which is where the bank selection logic function is located. This function checks for valid applications in the flash banks, picks the recent most version, and branches to the corresponding firmware version’s entry point (codestart). The entry point is the gateway to the C runtime initialization routine and main() of the application.

    Please refer to SPRUIU8SPRUIU9, and TIDUEY4 for more details on the bank selection implementation.