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.

CC2642R-Q1: Runtime BIM/CCFG Copy During Task Execution from RAM Code

Part Number: CC2642R-Q1

Hello everyone,

I’d like to get expert feedback on whether the following runtime flash-copy approach is safe and reliable on the CC26x2 device family under normal operating conditions (assuming no unexpected reset or power loss).


Goal

We aim to copy an updated BIM image and CCFG region, as well as an updated certificate block, from a temporary staging area in flash (0x34000) to their final destinations (0x54000–0x57FFF), triggered by a CAN message during runtime.


System Context

  • Device: TI CC26x2 (running TI-RTOS)

  • Flash operations performed using TI Flash API (driverlib)

  • The staging area (0x34000–0x35FFF) is written earlier by OTA update as a ready-to-run binary image.

  • The structure is as follows:

    • 0x34000 → Certificate page

    • 0x35000 → New BIM + CCFG image

  • Final destinations:

    • 0x54000 → Certificate (final copy)

    • 0x56000 → BIM + CCFG (final copy)

  • Write protection is not enabled for BIM/CCFG regions during this procedure.


Code Overview

This function is triggered at runtime by a CAN message.
It runs successfully so far without errors or unexpected behavior.

uint8_t res = copyBimToFinal(true);

__attribute__((section(".ti_ram_code")))
bool copyBimToFinal(bool isTaskRunning)
{
    uint8_t* src = (uint8_t*)0x34000;
    uint8_t* dst = (uint8_t*)0x54000;
    uint32_t i;
    uint32_t dataBuf[32]; // 128-byte buffer

    UInt key = Hwi_disable();
    if (isTaskRunning)
        Task_disable();

    // 1. Erase destination pages (including CCFG)
    if (FlashSectorErase(0x54000) != FAPI_STATUS_SUCCESS)
        return false;
    if (FlashSectorErase(0x56000) != FAPI_STATUS_SUCCESS)
        return false;

    // 2. Copy in 128-byte chunks
    for (i = 0; i < 0x4000; i += sizeof(dataBuf))
    {
        uint32_t j;
        for (j = 0; j < sizeof(dataBuf); j++)
        {
            ((uint8_t*)dataBuf)[j] = src[i + j];
        }

        if (FlashProgram((uint8_t*)dataBuf, (uint32_t)(dst + i), sizeof(dataBuf)) != FAPI_STATUS_SUCCESS)
            return false;
    }

    for (i = 0; i < 100000; i++) {} // Small delay

    if (isTaskRunning)
        Task_enable();
    Hwi_restore(key);

    return true;
}

The function is placed into RAM using:

.ti_ram_code : {
    *(.ti_ram_code)
} > SRAM

Design Rationale

Because flash operations on CC26x2 block CPU access to flash memory during erase and program operations, this function is explicitly moved to RAM to avoid instruction fetch conflicts.

Additionally:

  • Hwi_disable() and Task_disable() prevent flash access or preemption from other parts of the system during programming.

  • All operations are done sequentially (erase → program) in small chunks to minimize memory use.


Question

Under these conditions (normal operation, no power failure scenarios), is this approach considered safe and compliant with TI’s flash programming requirements?

Specifically:

  1. Are there any hidden risks with executing this code from RAM during runtime while other tasks are temporarily disabled?

  2. Does TI recommend any additional synchronization or precautions when performing flash operations from RAM in a multitasking RTOS environment?

  3. Is this the preferred approach to update BIM and CCFG regions dynamically (without rebooting into a dedicated bootloader context)?

At present, this implementation works perfectly in practice — no crashes, verification failures, or flash corruption observed — but I would like to confirm its correctness and potential limitations from an architectural standpoint.


Thank you for any insights, documentation references, or examples you can provide.

Best regards,
Yusuf Ünlü

    • he staging area (0x34000–0x35FFF) is written earlier by OTA update as a ready-to-run binary image.

    • The structure is as follows:

      • 0x34000 → Certificate page

      • 0x35000 → New BIM + CCFG image

    The staging area from 0x34000 to 0x37FFF is prepared earlier by the OTA update as a ready-to-run binary image.

    The memory layout is as follows:

    • 0x34000–0x35FFF: Certificate page

    • 0x36000–0x37FFF: BIM and CCFG image

    Note: The original reference to 0x35000 was incorrect; the BIM + CCFG region starts at 0x36000.

  • Hello,

    Thanks for detailed explanation of your question..

    I have a couple of suggestions.

    FlashProgram api is low level and NVS[Non-Volatile Storage driver interface] is high level/thread safe API.

    NVS manages the necessary flash operations internally, NVS APIs uses FlashProgram APIs too.

    In our examples, if system uses rtos, we use NVS and for non-rtos systems, we use FlashProgram APIs.

    In your case, you can run flash_init->flash_open->write_flash->flash_close

    This will also verify the written bytes. Otherwise, chunk handling looks good to me.

    In syscfg->NVS->Add flash regions and sizes

    static bool isOpen = false;
    static NVS_Handle nvsHandle;
    static NVS_Attrs regionAttrs;
    static NVS_Params nvsParams;

    void flash_init(void)
    {
    NVS_init();
    NVS_Params_init(&nvsParams);
    }

    bool flash_open(void)
    {
    if (!isOpen)
    {
        nvsHandle = NVS_open(CONFIG_NVSINTERNAL1, &nvsParams);
        if (nvsHandle != NULL)
        {
            isOpen = true;
            // Also read the region's attribute
            NVS_getAttrs(nvsHandle, &regionAttrs);
        }
    }
    
    return (isOpen);
    }

    void flash_close(void)
    {
    if (isOpen)
    {
    NVS_close(nvsHandle);
    isOpen = false;
    }
    }

    uint8_t writeFlash(uint_least32_t addr, uint8_t *pBuf, size_t len)
    {
    uint8_t flashStat = FLASH_FAILURE;
    if(isOpen)
    {
    if(NVS_write(nvsHandle, addr, pBuf, len, NVS_WRITE_PRE_VERIFY | NVS_WRITE_POST_VERIFY)
    == NVS_STATUS_SUCCESS)
    {
    flashStat = FLASH_SUCCESS;
    }
    }
    return (flashStat);
    }

  • Hello,

    Thank you for the detailed explanation and suggestions.

    Actually, I initially tried using the NVS-based approach as you described — calling flash_init -> flash_open -> write_flash -> flash_close.
    It worked perfectly for other flash regions in my system, but for some reason, whenever I attempted to modify the BIM/CCFG area using this method, the board froze and became unresponsive.

    I haven’t yet identified the root cause of that behavior, which is why I implemented the current approach described in my question — moving the copy function entirely into RAM and performing the Flash API operations directly.

    From your perspective, apart from the missing “verify written bytes” step, do you see any technical risks or mistakes in this RAM-based implementation?
    So far, it has been stable and reliable in all my tests, but I’d like to ensure it’s architecturally sound and aligned with TI’s best practices.

  • I see, it seems using Flash API makes sense in your case.

    Another good practice can be handling potential erros.

    For example, using malloc for dataBuf,  

     size_t bufferSize = 32 * sizeof(uint32_t);
    
        // 2. Allocate the memory using malloc.
        // The result is cast to a pointer of the correct type (uint32_t*).
        uint32_t* dataBuf = (uint32_t*)malloc(bufferSize);
    
        // 3. Check if the allocation was successful.
        if (dataBuf == NULL) {
            // If malloc fails, it returns NULL.
            fprintf(stderr, "Memory allocation failed!\n");
            return 1; // Exit with an error code
        }


    Use memcpy_s instead of for(j) loop and check memcpy_s return on each iteration.