TMS320F28P659DK-Q1: firmware upgradation scheme

Part Number: TMS320F28P659DK-Q1

Tool/software:

Hi,

I am implementing firmware upgradation on TMS320F28P659DK8PTP using a custom bootloader.

  1. Currently, I am able to boot from the bootloader app in Bank0 and switch to the application stored in Bank1 & Bank2 (since the application size is larger than 256 KB). In this case, the .cmd file places the code starting from Bank1.

  2. When a new firmware arrives via Standard CAN, I use the Flash API to write it into Bank3 & Bank4. For this slot, the .cmd file places the code starting from Bank3.

So effectively I have:

  • Slot A → Bank1 & Bank2

  • Slot B → Bank3 & Bank4

My doubt is

Suppose, from the bootloader, I determine the currently active slot using an EEPROM flag — let’s say it is Slot B.
I then receive new firmware and write it to Slot A, and switch execution to Slot A.
My question is: when the code starts executing from Slot A, how does it select the appropriate .cmd file for Slot A? 

  • Hello,

    Selecting the appropriate .cmd for Slot A or Slot B is up to you (the user) at compile time for the application. This can be done by having two separate build configurations in CCS for two different application versions, toggling between Slot A/B linker command files depending on the currently active slot.

    Please let me know if this explanation makes sense.

    Best,

    Matt

  • MEMORY
    {
       BEGIN            : origin = 0x0A0000, length = 0x000002  // <-- Updated codestart to BANK2
    
       BOOT_RSVD        : origin = 0x000002, length = 0x0001AF
       RAMM0            : origin = 0x0001B1, length = 0x00024F
       RAMM1            : origin = 0x000400, length = 0x000400
    
       RAMD0            : origin = 0x00C000, length = 0x002000
       RAMD1            : origin = 0x00E000, length = 0x002000
       RAMD2            : origin = 0x01A000, length = 0x002000
       RAMD3            : origin = 0x01C000, length = 0x002000
       RAMD4            : origin = 0x01E000, length = 0x002000
       RAMD5            : origin = 0x020000, length = 0x002000
    
       RAMLS0           : origin = 0x008000, length = 0x000800
       RAMLS1           : origin = 0x008800, length = 0x000800
       RAMLS2           : origin = 0x009000, length = 0x000800
       RAMLS3           : origin = 0x009800, length = 0x000800
       RAMLS4           : origin = 0x00A000, length = 0x000800
       RAMLS5           : origin = 0x00A800, length = 0x000800
       RAMLS6           : origin = 0x00B000, length = 0x000800
       RAMLS7           : origin = 0x00B800, length = 0x000800
       RAMLS8           : origin = 0x022000, length = 0x002000
       RAMLS9           : origin = 0x024000, length = 0x002000
    
       RAMGS0           : origin = 0x010000, length = 0x002000
       RAMGS1           : origin = 0x012000, length = 0x002000
       RAMGS2           : origin = 0x014000, length = 0x002000
       RAMGS3           : origin = 0x016000, length = 0x002000
       RAMGS4           : origin = 0x018000, length = 0x002000
    
       /* Flash Banks */
      // FLASH_BANK0     : origin = 0x080000, length = 0x20000
       FLASH_BANK1     : origin = 0x0A0002, length = 0x1FFFE
       FLASH_BANK2     : origin = 0x0C0000, length = 0x20000
       FLASH_BANK3     : origin = 0x0E0000, length = 0x20000  // <-- Uncommented
    
       CPU1TOCPU2RAM    : origin = 0x03A000, length = 0x000400
       CPU2TOCPU1RAM    : origin = 0x03B000, length = 0x000400
    
       CLATOCPURAM      : origin = 0x001480, length = 0x000080
       CPUTOCLARAM      : origin = 0x001500, length = 0x000080
       CLATODMARAM      : origin = 0x001680, length = 0x000080
       DMATOCLARAM      : origin = 0x001700, length = 0x000080
    
       CANA_MSG_RAM     : origin = 0x049000, length = 0x000800
       CANB_MSG_RAM     : origin = 0x04B000, length = 0x000800
       //RESET            : origin = 0x3FFFC0, length = 0x000002
    }
    
    SECTIONS
    {
      appstart       : > BEGIN, ALIGN(8)   // NEW
    
    
    
       .text           : >> FLASH_BANK1 | FLASH_BANK2, ALIGN(8)
       .cinit          : >> FLASH_BANK1 | FLASH_BANK2, ALIGN(8)
       .const          : >> FLASH_BANK1 | FLASH_BANK2, ALIGN(8)
       .switch         : >> FLASH_BANK1 | FLASH_BANK2, ALIGN(8)
       .reset : > FLASH_BANK1, ALIGN(8)   /* Redirect reset section to app region */
    
    
       .ramfuncs : LOAD = FLASH_BANK1,
                   RUN = RAMLS0,
                   LOAD_START(_RamfuncsLoadStart),
                   LOAD_SIZE(_RamfuncsLoadSize),
                   LOAD_END(_RamfuncsLoadEnd),
                   RUN_START(_RamfuncsRunStart),
                   RUN_END(_RamfuncsRunEnd),
                   PAGE = 0
    
       .stack           : > RAMM1
    
    #if defined(__TI_EABI__)
       .bss             : >>  RAMD0 | RAMD1 | RAMD2 | RAMD3
       .freertosStaticStack : > RAMD1, type=NOINIT
       .bss:output      : > RAMLS3
       .init_array      : > FLASH_BANK1, ALIGN(8)
       .const           : > FLASH_BANK1, ALIGN(8)
       .data            : > RAMLS5
       .sysmem          : > RAMGS0
    #else
       .pinit           : > FLASH_BANK1, ALIGN(8)
       .ebss            : >> RAMLS5 | RAMLS6
       .econst          : > FLASH_BANK1, ALIGN(8)
       .esysmem         : > RAMLS5
    #endif
    
       ramgs0 : > RAMGS0, type=NOINIT
       ramgs1 : > RAMGS1, type=NOINIT
       ramgs2 : > RAMGS2, type=NOINIT
    
       MSGRAM_CPU1_TO_CPU2 > CPU1TOCPU2RAM, type=NOINIT
       MSGRAM_CPU2_TO_CPU1 > CPU2TOCPU1RAM, type=NOINIT
    
    #if defined(__TI_EABI__)
       .TI.ramfunc : {} LOAD = FLASH_BANK1,
                        RUN = RAMLS0,
                        LOAD_START(RamfuncsLoadStart),
                        LOAD_SIZE(RamfuncsLoadSize),
                        LOAD_END(RamfuncsLoadEnd),
                        RUN_START(RamfuncsRunStart),
                        RUN_SIZE(RamfuncsRunSize),
                        RUN_END(RamfuncsRunEnd),
                        ALIGN(8)
    #else
       .TI.ramfunc : {} LOAD = FLASH_BANK1,
                        RUN = RAMLS0,
                        LOAD_START(_RamfuncsLoadStart),
                        LOAD_SIZE(_RamfuncsLoadSize),
                        LOAD_END(_RamfuncsLoadEnd),
                        RUN_START(_RamfuncsRunStart),
                        RUN_SIZE(_RamfuncsRunSize),
                        RUN_END(_RamfuncsRunEnd),
                        ALIGN(8)
    #endif
    }
    
    /*
    //===========================================================================
    // End of file.
    //===========================================================================
    

    Hi Matt,

    I need to do fimrware upgadation in this mcu cleanly...

    so if the current slot is A , and the new firmware is in slot B, the new firmare should contain the .cmd file for the bank3 and bank4??
    entry point should be bank3 ??

    and 

    if the current slot is B , and the new firmware is in slot A, the new firmare should contain the .cmd file for the bank1 and bank2??
    entry point should be bank1 ??

    Always the developer should track the slot in which the current firmware runs??

    I have successfully written the code(.cmd with bank1 & bank2) in bank1 and bank2 to jump to the application i have used the below function..

    Is this the correct way to use it?
    Or
    Please let me know how can i jump to the new fimrware what are the configurations i need to do when i build the new fimrware and also how should i jump to that applicatin from bootloader??

    void jumpToApp(uint32_t address)
    {
    DINT;
    EALLOW;
    SysCtl_disableWatchdog();
    EDIS;

    SYSTEM_LOG_UART(LOG, __func__, "WD disabled \r\n");

    IER = 0x0000;
    IFR = 0x0000;


    SYSTEM_LOG_UART(LOG, __func__, "stack pointer reset \r\n");

    // asm(" MOV SP, #0x07FF"); // Optional: Stack pointer reset (adjust if needed)

    SYSTEM_LOG_UART(LOG, __func__, "Jumping to application\r\n");

    // ((void (*)(void))BANK_3)(); // Direct jump
    ((void (*)(void))address)();

    SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64);
    SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // Reset on timeout


    SysCtl_enableWatchdog();

    while(1);
    }


    Note:- i have added .cmd of my application


    also please let meknow the address that i shoudl write (for slot A)the application is it 0xa0000 or 0xa0002 ??
    at which addresses i shpuld do erase,write,jumptoapp ??

    The same jumptoapp is working if i have flashed the bootloader and application uisng CCS...In CCS .out is writing to flash and here i have used 

    hex2000 -boot -sci8 -a -o firmware_upgrade.bin firmware_upgrade.out

    this above eqn to make .bin files and that only we are writing to flash using FAPI APIs





  • Hello,

    This expert is currently out of office. Please expect a delay in response until later this week upon returning. 
    Best Regards,

    Allison

  • Hello,

    so if the current slot is A , and the new firmware is in slot B, the new firmare should contain the .cmd file for the bank3 and bank4??
    entry point should be bank3 ??

    and 

    if the current slot is B , and the new firmware is in slot A, the new firmare should contain the .cmd file for the bank1 and bank2??
    entry point should be bank1 ??

    Yes, your understanding is correct. You will need to adjust the entry point/.cmd according to which slot (i.e. flash banks) the new firmware will be programmed into.

    Always the developer should track the slot in which the current firmware runs??

    Yes, that is correct.

    Note:- i have added .cmd of my application

    One thing to note: If you look into the memory map for the reset vector, you'll find that address 0x003F_FFC0 is in Boot ROM which users cannot program. Reset is always fetched from that location. In linker cmd file, .reset should be mapped to the RESET section (reset vector) but it's not used (DSECT). 

    .reset              : > RESET,     PAGE = 0, TYPE = DSECT /* not used, */

    also please let meknow the address that i shoudl write (for slot A)the application is it 0xa0000 or 0xa0002 ??

    0xA0000 is typically reserved for the codestartbranch (i.e. codestart) which re-initializes the stack pointer and runs through the c_int00 routine. Please ensure that this location is branched to, it is the entry point for the application. 

    0xA0002 can be used to write the application code to for the slot A application.

    The same jumptoapp is working if i have flashed the bootloader and application uisng CCS...In CCS .out is writing to flash and here i have used 

    hex2000 -boot -sci8 -a -o firmware_upgrade.bin firmware_upgrade.out

    Please use the On-Chip Flash tool in CCS to verify that the application is being programmed correctly correct. This E2E FAQ explains how to access the tool (step 1) and verify the application (step 15).

    Please also verify that you are branching to the codestart of the next application version (e.g. for slot A at 0xA0000).

    Best,

    Matt

  • Hi Matt
    Thank you for the reply...

    "0xA0002 can be used to write the application code to for the slot A application"

    Means when i write to flash the starting address should be 0xA0002 ???


    What i have done earlier with CCS
    1. Made a custom bootloader which will be flashed to bank0 - on chip flahs setting only for bank0
    2. Made application which will be flashed to Bank1  - onchip flash only for bank1

    Hope on chip flash configuration means erasing and programming enabling ... That doing correcly...

    After flashing  when i rebootted the board,
    the bootloader started and it jumped to the application - I got log


    What i exactly need to do --- This is where i am stuck (application getting via CAN, not flashing via CCS)
    1. I need to get the binary from a host processor via CAN, and write to the flash memory and boot that application. same .cmd only used.
    2. In bootloader side i am receiving the data and writing to the flash 1KB by 1KB(CRC checked correctly transfering)
    3. before writing to flash i am making

    data received - chunk_len_prc(mostly 1KB, for last chunk only it will be less than 1KB)

    uint16_t wordCount = (chunk_len_prc + 1) / 2;  

    for (i = 0; i < wordCount; i++)
    {
    uint8_t low = (2*i < chunk_len_prc) ? rx_chunk_buffer[2*i] : 0xFF;
    uint8_t high = (2*i + 1 < chunk_len_prc) ? rx_chunk_buffer[2*i + 1] : 0xFF;
    wordBuffer[i] = ((uint16_t)high << 8) | low;
    }

    //writing to flash


    uint16_t wordsPerCall = 32; // 64 bytes
    uint16_t written = 0;

    while (written < wordCount) {
    uint16_t remaining = wordCount - written;
    uint16_t batchSize = (remaining >= wordsPerCall) ? wordsPerCall : remaining;
    Example_ProgramAllBankUsing512bitAutoECC(target_address,&wordBuffer[written],batchSize);

    // Move address and word pointer forward
    target_address += batchSize; // each word = 2 bytes
    written += batchSize;
    SYSTEM_LOG_UART(LOG, __func__, "1111111inside while target address = 0x%08" PRIx32 "\r\n", target_address);
    SYSTEM_LOG_UART(LOG, __func__, "2222222222 remaining = %u ,batchSize = %u written = %u \r\n",remaining,batchSize,written);

    }


    This is how i am writiing to flash

    when the trasfer is done i am calling the same jumptoapp(0xa0000);


    The binary i am trnsfering is a .txt file now

    hex2000 -boot -b -o firmware_upgrade.txt firmware_upgrade.out

    Is this correct or should we transfer firmware_upgrade.out itself?



    I tried the below jumptoapp and dumpflash

    void dumpFlash(uint32_t addr, uint16_t words)
    {
    volatile uint16_t *p = (volatile uint16_t *)addr;
    uint16_t i;

    SYSTEM_LOG_UART(LOG, __func__, "Dumping flash from 0x%08lx:\r\n", addr);

    for (i = 0; i < words; i++)
    {
    if (i % 8 == 0) // 8 words per line
    {
    SYSTEM_LOG_UART(LOG, __func__, "\r\n0x%08lx : ", (uint32_t)(addr + i*2));
    }

    SYSTEM_LOG_UART(LOG, __func__, "%04X ", p[i]);
    }
    SYSTEM_LOG_UART(LOG, __func__, "\r\n");
    }

    void jumpToApp(uint32_t address)
    {
    DINT;
    EALLOW;
    SysCtl_disableWatchdog();
    EDIS;

    SYSTEM_LOG_UART(LOG, __func__, "WD disabled\r\n");

    IER = 0x0000;
    IFR = 0x0000;

    SYSTEM_LOG_UART(LOG, __func__, "Jumping to application at 0x%08lx\r\n", address);

    dumpFlash(0x000A0000, 64);

    // Direct jump to codestart
    ((void (*)(void))address)();

    // If we ever return, halt
    SYSTEM_LOG_UART(LOG, __func__, "ERROR: Application returned!\r\n");
    while (1);
    }

    output
    LOG (jumpToApp): WD disabled
    LOG (jumpToApp): Jumping to application at 0x000a0000
    LOG (dumpFlash): Dumping flash from 0x000a0000:
    LOG (dumpFlash):
    0x000a0000 : LOG (dumpFlash): 08AA LOG (dumpFlash): 0000 LOG (dumpFlash): 0000
    0x000a0010 : LOG (dumpFlash): 0000 LOG (dumpFlash): 000A LOG (dumpFlash): 0000
    0x000a0020 : LOG (dumpFlash): 003C LOG (dumpFlash): 000A LOG (dumpFlash): 6600
    0x000a0030 : LOG (dumpFlash): 41C8 LOG (dumpFlash): 0000 LOG (dumpFlash): 41E0
    0x000a0040 : LOG (dumpFlash): 000A LOG (dumpFlash): 0000 LOG (dumpFlash): 0048
    0x000a0050 : LOG (dumpFlash): 000A LOG (dumpFlash): 0010 LOG (dumpFlash): 0450
    0x000a0060 : LOG (dumpFlash): 000A LOG (dumpFlash): 4C2D LOG (dumpFlash): 000A
    0x000a0070 : LOG (dumpFlash): 0000 LOG (dumpFlash): 0036 LOG (dumpFlash): 0000






  • Hello,

    Means when i write to flash the starting address should be 0xA0002 ???

    Yes, it should start from 0xA0002, as defined in your linker command file. 

    Is this correct or should we transfer firmware_upgrade.out itself?

    Yes, this is also correct. We recommend transferring the binary/hex file. 

    Example_ProgramAllBankUsing512bitAutoECC(target_address,&wordBuffer[written],batchSize);

    Please ensure you're aligning the flash sections in your linker command file to 512-bit boundaries with ALIGN(32), since you're programming 512-bits at a time.

    Best,

    Matt