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.

TMS320F280025C: Properly switch between different application code

Part Number: TMS320F280025C
Other Parts Discussed in Thread: ASH

Hi, Gurus

I'm working on firmware upgrade using I2C protocol, now I want to run new code after upgrade progress.

I want to know the proper method to switch between two different individual CCS project for firmware upgrade.

Assume I have two CCS projects:

"Main_App" contain code selection logic, I2C upgrade kernel and old application code located at flash address 0x81000.

"New_App" for new application which only blink LED located at flash address 0x88000.

Flash section15 0x8F000 is for EEPROM-liked storage for some firmware information data.

* F280025C only has one bank of flash, 0x80000 to 0x8FFFFF

After software reset (using SysCtl_resetDevice()), the XRS pin geting low for 45uS, and can not boot to the new application.

So I found the related post: TMS320F28388D: Device fails to boot up after firmware upgrade. - C2000 microcontrollers forum - C2000Tm︎ microcontrollers - TI E2E support forums

But it only mention its the flashAPI issue,I think it's not my case.

Because even I build the New_App using CCS, and uploaded it in section8-15 to ensure there is not flash problem during my upgrade transmission,

I try to jump to new code using my code selection logic in Main_App, it has the same behavior as below:

CH1: XRS CH2: GPIO5

The code selection logic I build is to read the flash address 0x8F0000 back and check is the flash bank has been modified.

I use simple asm("    LB 0x88000") to do the job.

Here is the code in Main_App:

const uint32_t fw_branch_addr   = 0x08F000;     // FW status flash address


void main(void)
{
#ifdef mov2ram
    memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
    memcpy(&IQfuncsRunStart, &IQfuncsLoadStart, (size_t)&IQfuncsLoadSize);
    InitFlash();
    InitFlashAPI();
#endif

    DeviceInit();               // Initialize device, including CPUTimer
    PeripheralInit();           // Initialize MCU peripheral

    App_branch();               // If new firmware installed, jump to new firmware

    VarInit();                  // Initialize variables
    Init_I2C();                 // Initialize I2C protocol and GPIO
    Init_SPI();                 // Initialize SPI protocol and GPIO

    while(1)
    {
            switch (system_status){
            case(NORMAL):                   // Normal operation
                // Do some normal thing
                break;

            case(UPGRADING):                // Upgrade operation
                // Do some upgrade thing
                break;

            case(ERROR):                    // System error operation
                break;

            case(REBOOT):                   // Software reset the device
                DELAY_US(1000);
                SysCtl_resetDevice();
                break;
    }
}

// @brief   branch to 0x88000 if firmware status is MODIFIED

void App_branch(void){
    if(check_fw_branch() == MODIFIED)
        asm("  LB 0x088000");
}

/* @brief   check firmware status from flash to determine entry point
 * @param   none
 * @return  FIRMWARE_STATUS  MODIFIED: told Appbranch() jump to updated firmware (0x088000)
 *          FIRMWARE_STATUS  ORIGINAL: told Appbranch() not jump
 */
uint16_t check_fw_branch(void){
    uint16_t fw_branch = ORIGINAL;
    uint16_t flash_data;
    flash_data = *((uint16_t*)fw_branch_addr);
    if(flash_data != fw_branch)
        return MODIFIED;
    else
        return ORIGINAL;
}

When received all New_App package, the system go into REBOOT case and do the software reset.

But after that, it can not go into New_App properly.

For cmd file of Main_App:

MEMORY
{
   BOOT_RSVD		: origin = 0x00000002, length = 0x00000126
   RAMM0           	: origin = 0x00000128, length = 0x000002D8
   RAMM1            : origin = 0x00000400, length = 0x000003F8     /* on-chip RAM block M1 */

   RAMLS4567        : origin = 0x0000A000, length = 0x00002000
   RAMGS0           : origin = 0x0000C000, length = 0x00001000
   RESET            : origin = 0x003FFFC0, length = 0x00000002

   BOOTROM          : origin = 0x003F0000, length = 0x00008000
   BOOTROM_EXT      : origin = 0x003F8000, length = 0x00007FC0

#ifdef __TI_COMPILER_VERSION__
   #if __TI_COMPILER_VERSION__ >= 20012000
GROUP {      /* GROUP memory ranges for crc/checksum of entire flash */
   #endif
#endif

   BEGIN           	: origin = 0x080000, length = 0x000002	// default flash entry point
   /* Flash sectors */
   /* BANK 0 */
   FLASH_BANK0_SEC0  : origin = 0x080002, length = 0x000FFE	/* on-chip Flash */
   FLASH_BANK0_SEC1  : origin = 0x081000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC2  : origin = 0x082000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC3  : origin = 0x083000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC4  : origin = 0x084000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC5  : origin = 0x085000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC6  : origin = 0x086000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC7  : origin = 0x087000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC8  : origin = 0x088000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC9  : origin = 0x089000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC10 : origin = 0x08A000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC11 : origin = 0x08B000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC12 : origin = 0x08C000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC13 : origin = 0x08D000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC14 : origin = 0x08E000, length = 0x001000	/* on-chip Flash */
   FW_STATUS         : origin = 0x08F000, length = 0x000008 /* on-chip Flash */
   FW_NUMBER		 : origin = 0x08F008, length = 0x000008 /* on-chip Flash */
   DEVICE_NUMBER     : origin = 0x08F010, length = 0x000018 /* on-chip Flash */
   FLASH_DATA1		 : origin = 0x08F028, length = 0x000040 /* on-chip Flash */
   FLASH_BANK0_SEC15 : origin = 0x08F068, length = 0x000F88	/* on-chip Flash */

   FLASH_BANK0_SEC15_DO_NOT_USE     : origin = 0x08FFF0, length = 0x000010  /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */

#ifdef __TI_COMPILER_VERSION__
  #if __TI_COMPILER_VERSION__ >= 20012000
}  crc(_table_name, algorithm=C28_CHECKSUM_16)
  #endif
#endif

}


SECTIONS
{
   codestart        : > BEGIN, ALIGN(8)
   .text            : >> FLASH_BANK0_SEC2 | FLASH_BANK0_SEC3 | FLASH_BANK0_SEC4,   ALIGN(8)
   .cinit           : > FLASH_BANK0_SEC1, ALIGN(8)//FLASH_BANK0_SEC1,  ALIGN(8)
   .switch          : > FLASH_BANK0_SEC1,  ALIGN(8)
   .reset           : > RESET,                  TYPE = DSECT /* not used, */

   .stack           : > RAMM0

   .init_array      : > FLASH_BANK0_SEC1, ALIGN(8)//FLASH_BANK0_SEC1,  ALIGN(8)
   .bss             : > RAMLS4567
   .bss:output      : > RAMLS4567
   .bss:cio         : > RAMGS0
   .const           : > FLASH_BANK0_SEC1,  ALIGN(8)
   .data            : > RAMLS4567
   .sysmem          : > RAMLS4567

    ramgs0 : > RAMGS0
	DataBufferSection :> RAMGS0, ALIGN(8)

    retain			: > FLASH_BANK0_SEC15,  ALIGN(8)	// storage const variables
	firmware_status : > FW_STATUS
	firmware_number : > FW_NUMBER
	device_number	: > DEVICE_NUMBER
	flash_data	 	: > FLASH_DATA1
    /*  Allocate IQ math areas: */
//   IQmath           : > RAMLS4567
   IQmath            : LOAD = FLASH_BANK0_SEC1,
   					   RUN = RAMGS0,
   					   LOAD_START(IQfuncsLoadStart),
   					   LOAD_END(_IQfuncsLoadEnd),
   					   LOAD_SIZE(IQfuncsLoadSize),
   					   RUN_START(IQfuncsRunStart),
   					   ALIGN(8)
   IQmathTables     : > RAMLS4567

  .TI.ramfunc      : LOAD = FLASH_BANK0_SEC1,
                  RUN = RAMGS0,
                  LOAD_START(RamfuncsLoadStart),
                  LOAD_SIZE(RamfuncsLoadSize),
                  LOAD_END(RamfuncsLoadEnd),
                  RUN_START(RamfuncsRunStart),
                  RUN_SIZE(RamfuncsRunSize),
                  RUN_END(RamfuncsRunEnd),
                  ALIGN(8)

   /* crc/checksum section configured as COPY section to avoid including in executable */
   .TI.memcrc          : type = COPY

}
/*
//===========================================================================
// End of file.
//===========================================================================
*/

For cmd file of New_App:

MEMORY
{
   BOOT_RSVD		: origin = 0x00000002, length = 0x00000126
   RAMM0           	: origin = 0x00000128, length = 0x000002D8
   RAMM1            : origin = 0x00000400, length = 0x000003F8     /* on-chip RAM block M1 */
   RAMLS4567        : origin = 0x0000A000, length = 0x00002000
   RAMGS0           : origin = 0x0000C000, length = 0x00001000
   RESET            : origin = 0x003FFFC0, length = 0x00000002


   BOOTROM          : origin = 0x003F0000, length = 0x00008000
   BOOTROM_EXT      : origin = 0x003F8000, length = 0x00007FC0
   
#ifdef __TI_COMPILER_VERSION__
   #if __TI_COMPILER_VERSION__ >= 20012000
GROUP {      /* GROUP memory ranges for crc/checksum of entire flash */
   #endif
#endif   
   BEGIN           	: origin = 0x088000, length = 0x000002
   FLASH_BANK0_SEC0  : origin = 0x080000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC1  : origin = 0x081000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC2  : origin = 0x082000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC3  : origin = 0x083000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC4  : origin = 0x084000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC5  : origin = 0x085000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC6  : origin = 0x086000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC7  : origin = 0x087000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC8  : origin = 0x088002, length = 0x000FFE	/* on-chip Flash */
   FLASH_BANK0_SEC9  : origin = 0x089000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC10 : origin = 0x08A000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC11 : origin = 0x08B000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC12 : origin = 0x08C000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC13 : origin = 0x08D000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC14 : origin = 0x08E000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC15 : origin = 0x08F000, length = 0x000FF0	/* on-chip Flash */
   FLASH_BANK0_SEC15_DO_NOT_USE     : origin = 0x08FFF0, length = 0x000010  /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
#ifdef __TI_COMPILER_VERSION__
  #if __TI_COMPILER_VERSION__ >= 20012000
}  crc(_ccs_flash_checksum, algorithm=C28_CHECKSUM_16)
  #endif
#endif

}


SECTIONS
{
   codestart        : > BEGIN, ALIGN(8)
   .text            : >> FLASH_BANK0_SEC9 | FLASH_BANK0_SEC10 | FLASH_BANK0_SEC11,   ALIGN(8)
   .cinit           : > FLASH_BANK0_SEC8,  ALIGN(8)
   .switch          : > FLASH_BANK0_SEC8,  ALIGN(8)
   .reset           : > RESET,                  TYPE = DSECT /* not used, */

   .stack           : > RAMM1

   .init_array      : > FLASH_BANK0_SEC8,  ALIGN(8)
   .bss             : > RAMLS4567
   .bss:output      : > RAMLS4567
   .bss:cio         : > RAMGS0
   .const           : > FLASH_BANK0_SEC8,  ALIGN(8)
   .data            : > RAMLS4567
   .sysmem          : > RAMLS4567

    ramgs0 : > RAMGS0

    /*  Allocate IQ math areas: */
//   IQmath           : > RAMLS4567
   IQmath            : LOAD = FLASH_BANK0_SEC8,
   					   RUN = RAMGS0,
   					   LOAD_START(IQfuncsLoadStart),
   					   LOAD_END(_IQfuncsLoadEnd),
   					   LOAD_SIZE(IQfuncsLoadSize),
   					   RUN_START(IQfuncsRunStart),
   					   ALIGN(8)
   IQmathTables     : > RAMLS4567

  .TI.ramfunc      : LOAD = FLASH_BANK0_SEC8,
                  RUN = RAMGS0,
                  LOAD_START(RamfuncsLoadStart),
                  LOAD_SIZE(RamfuncsLoadSize),
                  LOAD_END(RamfuncsLoadEnd),
                  RUN_START(RamfuncsRunStart),
                  RUN_SIZE(RamfuncsRunSize),
                  RUN_END(RamfuncsRunEnd),
                  ALIGN(8)

   /* crc/checksum section configured as COPY section to avoid including in executable */
   .TI.memcrc          : type = COPY

}
/*
//===========================================================================
// End of file.
//===========================================================================
*/

Also, I try to reverse the role between Main_App and New_App:

I first program the Main_App at 0x81000 and program New_App at 0x88000 using CCS, then after specific condition (such as counter = 0),

and run asm("    LB 0x80000") to jump to Main_Appand it works fine, the device can run all Main_App function.

I remember I asked about the implemention of new entry point setup: TMS320F280025C: Live Firmware Upgrade without using OTP memory - C2000 microcontrollers forum - C2000Tm︎ microcontrollers - TI E2E support forums

But I'm not sure is that only work when there is one project in the flash menory.

I survay the forum and find f28002x_codestartbranch.asm and boot28.c plays important role when device is booting, but not really understanding the mechanism and where to modify.

Conclusion, the question is:

1. How to switch the different, independent application in one flash bank but different address?

2. What is the detailed device boot sequence for firmware developmenting view?

Thanks for the support!

Best Reguards.

  • Hi Chun-Lin,

    Thanks for the questions. Here are some possibly things to consider:

    1) This sounds something similar to the BANK0_LDFU configuration where at the presence a new firmware upgrade, the revision value of the bank location is checked to see if it has changed. I would advise to take a look at the documentation for it here Live Firmware Update with Device Reset on C2000 MCUs (Rev. A) (ti.com)

    2) The detailed device boot sequence for firmware development can be found generally in the Serial Flash Programming of C2000 Microcontrollers (Rev. E) (ti.com) . You can also look at the LDFU guide posted before this on how the firmware update occurs for this device. The text files for flash_kernel_ex3_ldfu.c detail what happens when a revision is checked for branching.

    Regards,

    Charles

  • Hi, Charles

    Thanks for the fast reply.

    I walkthrough the LDFU example (fash_kernel_ex3_ldfu.c) again and also Live Firmware Update with Device Reset on C2000 MCUs (Rev. A) (ti.com)

    I have some question to clarify:

    1. Why Device_init() run twice?

    In demo project, bankSelect function (line 994) initialize the device twice, first is at beginning, this is reasonable because it need to be done so MCU can work, for received SCI message or something.

    But the second time it initialize the device when B0_KEY value not match the KEY (line 1207), why is this for? Is this related for PLL or other peripherial?

    2. Is the project located at 0x8EFF0 a completely different, individual project from project located at 0x08003B?

    Because I use F280025C which only have one bank flash, If I build two different project, even I set the code_start to different address, the device should begin from 0x80000 after builed-in bootROM choose flash boot.

    I noticed that in the demo code, the bankSelect() is set to force located at 0x80000, will the data at 0x80000 conflict with two different project? or the different project should have the same code at 0x80000?

    My situation might be a little different from the demo project which load new firmware fom SCI, but I can only use flashboot to start the program. 

    I use Intel-hex formatted .hex file generated by C2000Hex utility, then use Linux to transmit package to my device through I2C.

    As I know, the file contain the exact content of firmware written in the device flash so I can simply execute the data after programming into flash.

    Thanks for the support,

    Best Reguards.

  • Hi Chun-Lin,

    Answering your questions momentarily:

    1) The first device_init() is so that a flash kernel to RAM copy occurs. Even if there is no new firmware update, the device prepares itself just in case. The bank_select function acts as the primary device logic, so on device reset it will always check for a firmware update, and to do that it needs to initialize the device. The second device_init() is to check if each possible bank has the revision value. For F280025C case, there is just one bank.

    2) Yes, 0x8EFF0 is one of the alternative flash entry points, so for example if the device on reset does not require an update, it will branch to where the user application code resides. In this case, 0x8EFF0 was picked because it is a designed entry point, although you could have also chosen another entry point such as 0x84000, it is for you to configure. Figure 3-1 in the LDFU application note shows that the Bank selection logic, SCI kernel and Flash API will take up the top space for Bank0. The different user applications added to the bank should avoid using the same flash memory region as the Bank select logic/SCI kernel/Flash API. Available space starts from 0x82000 in the example.

    Regards,

    Charles

  • Thanks for the reply,

    It's a cleare answer for demo file.

    I found the properties of demo project set the linker's entry-point to bankSelect (properties>CCS Build>C2000 linker>Symbol Management>--entrypoint)

    I refer TMS320C28x Assembly Language Tools v22.6.0.LTS User's Guide (Rev. Y) (ti.com) pp.190, entry point section, it said I can assign one of four values to the entry point.

    Questions:

    1. I want to know more about how to set the entry point and in firmware update senario,

    also the detailed description of flash_kernel_ex3_codestartbranch.asm which didn't mention in application note but plays important role of whole branching.

    2. For the original question "What is the detailed device boot sequence for firmware developmenting view?" I'm meaning the general project startup sequence, not specificy for firmware upgrade purpose, Is there any documant to refer?

    Thanks for the support,

    Best Reguards.

  • Hi Chun-Lin,

    Transferring your questions to the LDFU expert for more detail. Will be able to respond as soon as tomorrow.

    Thanks,

    Charles

  • Chun-Lin,

    I read your requirements and questions, and understand what you are trying to implement.

    I am using Main_App and New_App are separate projects, each with their own main(). Is that correct?

    If yes, then each of these projects should contain the codestartbranch.asm. Because it contains code_start (mapped to the codestart section) which is the first code that is executed after exiting the Boot ROM code. So if you are in Flash boot mode, the default Flash entry point (0x80000) is where you want codestart to be mapped. And this is what you have done (looking at your main_app's linker .cmd file). From there, cint00 (the C initialization routine provided by the Compiler's RTS library) is called, which calls main(). Similarly, when you branch from the main_app to the New_app, the entry point is the codestart of New_app (0x88000), so you would need codestartbranch for this project as well, so it can run cint00 and call main() of New_app.

    Another thing to think about RAM memory overlaps between Main_app and New_app. If there are overlaps, then when you go from Main_app to New_app, you may lose some RAM memory context for the Main_app. Switching back to Main_app from New_app may then not work as expected. Not sure if this is something you are doing or need to do.

    For your specific problem:

    "When received all New_App package, the system go into REBOOT case and do the software reset.

    But after that, it can not go into New_App properly."

    Please debug and check if all the memory locations esp. 0x8F000 etc. have the desired values. Connect to the target using a target configuration file without Gel file (so that it doesn't reset the device), and then load Project symbols (of the project that you expect to be executing) and check where execution is.

    Thanks,

    Sira

  • Thanks for the reply, for the information I clearily know the boot sequence and solve the issue.

    In my case, I only need branch the App with device reset, so the RAM overlapping issue can be ignored, thanks for reminding!

    Thought I didn't use the dedugging technique you mention yet, I modify the App_branch function as below and do the thing I want to do.

    Here is the code for others who need help:

    // You need declare _c_int00 in C enviorement reference 
    // TMS320C28x Assembly Language Tools v21.6.0.LTS pp.242
    extern void _c_int00        (void);     // _c_int00 is defined in compiler's run-time library, declare here for App_branch usage
    
    void main(void){
    ...
    }
    
    /* @brief   branch to 0x88000 if branch_direction is not 0
     * @param   none
     * @return  none
     */
    #pragma CODE_SECTION(App_branch, "codestart");
    void App_branch(void){
        uint16_t branch_direction = 0;
    
        DeviceInit();               // Initialize device, including CPUTimer
    
        // branch_direction branch App to where
        branch_direction = HWREG((uint32_t)fw_branch_addr);
    
        if(branch_direction != 0)
            asm("   LB 0x88000");
        else
            _c_int00();
    }

    To do the thing, you need to set the linker entry point to App_branch, and modify the linker command file to put App_branch to 0x80000 so the device will execute this after reset.

    At the beginning I'm wondering how to go back from C enviorement to assembly code, I try use LB, LCR instruction but didn't work.

    Then I try just simple call _c_int00 can do the job and go through the normal initialization and execute Main_App.

     

    Thanks again for the help, Charles and Sira.

    Best Reguards.