1
\$\begingroup\$

I am developing a bootloader and have some trouble jumping from the bootloader to the application. As far as I can see the problem is because I am doing certain initializations in the bootloader which are then also performed in the application. I posted a question about this on the TI forums (https://e2e.ti.com/support/microcontrollers/other/f/908/p/894608/3308592#3308592) but I am not getting any responses so I am looking for another way to fix it.
My idea now is to start the bootloader, download the application image, save it to flash memory and then instead of jumping to the application I want to restart the device and jump to the application before any sort of initialization has been done. I am not sure if this will work but I have been stuck on the jump from bootloader to application for a while now and finally want to make some progress.

For this to work the bootloader will have to somehow know it should jump to the application before any initialization. As far as I know it is not possible to simply write to a single byte somewhere in flash memory because it will require erasing a whole block and the block size on the device I am using is 8KB large. It seems like a waste to reserve 8KB on a device, just so I can save a simple value to pass on between system resets.

Does anyone have any tips on how I could accomplish this?

I am developing for the CC2652R1F using Code Composer Studio along with the TI v18.12.5.LTS compiler.

EDIT:
I tried using kkrambo's situation but it seems not to be working correctly.
I edited my linker command file to include a .boot_cfg section in RAM with a size of four. I put the new linker command file further below.
I then created a global variable uint32_t config in my file along with #pragma DATA_SECTION(config, ".boot_cfg"); to link it to that section, but I am not sure if I did that correctly. After that I tried reading the value, then changing and then resetting the system to see if it worked. This is the code I used:

    if (config == 0) {
        GPIO_write(CONFIG_GPIO_LED_RED, CONFIG_GPIO_LED_ON);
        sleep(2);
        config = 2;
        SysCtrlSystemReset();
    } else {
        GPIO_write(CONFIG_GPIO_LED_GREEN, CONFIG_GPIO_LED_ON);
        while(1) {}
    }

When I just flash the bootloader so I would not have to reset the device using the debugger because I think it might reset the power I see the red light turn on, then the value should change and the system should reset and then hopefully I would see the green light go on, but neither lights turned on. So I think the SysCtrlSystemReset() function might not be working probably.
So I tried going through the bootloader step by step, then after the config = 2; statement I used the CPU reset button in the IDE to go back to the beginning, but then when I come back to the if statement the value is still 0.

Linker Command File:

--stack_size=1024   /* C stack is also used for ISR stack */

--heap_size=256

/* Retain interrupt vector table variable                                    */
--retain=g_pfnVectors
/* Override default entry point.                                             */
--entry_point ResetISR
/* Allow main() to take args                                                 */
--args 0x8
/* Suppress warnings and errors:                                             */
/* - 10063: Warning about entry point not being _c_int00                     */
/* - 16011, 16012: 8-byte alignment errors. Observed when linking in object  */
/*   files compiled using Keil (ARM compiler)                                */
--diag_suppress=10063,16011,16012

#define FLASH_BASE              0x0
#define FLASH_SIZE              0x58000
#define RAM_BASE                0x20000000
#define RAM_CFG_BASE            0x20013FFC
#define RAM_CFG_SIZE            0x4 // reserve 4 bytes of ram for bootloader config
#define RAM_SIZE                0x14000 - RAM_CFG_SIZE
#define GPRAM_BASE              0x11000000
#define GPRAM_SIZE              0x2000

#define FLASH_START             FLASH_BASE

#define PAGE_SIZE               0x2000

#define BOOT_BASE               0x50000
#define BOOT_END                FLASH_CCFG_START - 1
#define BOOT_SIZE               ((BOOT_END) - (BOOT_BASE) + 1)

#define APP_BASE                0x0
#define APP_END                 BOOT_BASE
#define APP_SIZE                BOOT_BASE

#define FLASH_CCFG_START        0x00057FA8
#define FLASH_CCFG_END          (FLASH_START + FLASH_SIZE - 1)
#define FLASH_CCFG_SIZE         ((FLASH_CCFG_END) - (FLASH_CCFG_START) + 1)

/* System memory map */

MEMORY
{

    BOOT (RWX)  : origin = BOOT_BASE, length = BOOT_SIZE

    APP (RWX) : origin = APP_BASE, length = APP_SIZE

    FLASH_CCFG (RX) : origin = FLASH_CCFG_START, length = FLASH_CCFG_SIZE

    /* Application uses internal RAM for data */
    SRAM (RWX) : origin = RAM_BASE, length = RAM_SIZE
    RAM_CFG (RWX) : origin = RAM_CFG_BASE, length = RAM_CFG_SIZE
    /* Application can use GPRAM region as RAM if cache is disabled in the CCFG
    (DEFAULT_CCFG_SIZE_AND_DIS_FLAGS.SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM = 0) */
    GPRAM (RWX): origin = GPRAM_BASE, length = GPRAM_SIZE
}



/* Create global constant that points to top of stack */
/* CCS: Change stack size under Project Properties    */
__STACK_TOP = __stack + __STACK_SIZE;


/* Section allocation in memory */

SECTIONS
{
    .intvecs        :   > BOOT_BASE
    .text           :   > BOOT
    .TI.ramfunc     : {} load=BOOT, run=SRAM, table(BINIT)
    .const          :   > BOOT
    .constdata      :   > BOOT
    .rodata         :   > BOOT
    .binit          :   > BOOT
    .cinit          :   > BOOT
    .pinit          :   > BOOT
    .init_array     :   > BOOT
    .emb_text       :   > BOOT
    .ccfg           :   > FLASH_CCFG (HIGH)

    .boot_cfg       :   > RAM_CFG
    .vtable         :   > SRAM
    .vtable_ram     :   > SRAM
     vtable_ram     :   > SRAM
    .data           :   > SRAM
    .bss            :   > SRAM
    .sysmem         :   > SRAM
    .stack          :   > SRAM (HIGH)
    .nonretenvar    :   > SRAM

    .gpram          :   > GPRAM

}
\$\endgroup\$
  • \$\begingroup\$ Use a separate serial EEPROM? \$\endgroup\$ – Dave Tweed Apr 7 at 15:06
  • \$\begingroup\$ @DaveTweed We do have an EEPROM connected over SPI, but I am not sure how to communicate with it without using Texas Instruments API which requires the initialization I believe to be causing the jump issues. \$\endgroup\$ – Vincent Kenbeek Apr 7 at 15:09
  • 2
    \$\begingroup\$ @VincentKen Figure it out. Fastest and easiest route. \$\endgroup\$ – DKNguyen Apr 7 at 15:16
  • \$\begingroup\$ The API might be (re)initializing the SPI interface -- which shouldn't be a problem -- but if it is modifying the contents of your EEPROM, it is seriously broken! \$\endgroup\$ – Dave Tweed Apr 7 at 15:18
  • 1
    \$\begingroup\$ I don't understand. Under what conditions would you not call Board_init() before doing anything else? If it's doing something you don't want, then you need to modify it. \$\endgroup\$ – Dave Tweed Apr 7 at 16:32
3
\$\begingroup\$

You can create a custom section in RAM that does not get initialized during startup so the values from before the soft reset or jump remain afterwards. This works only for soft resets and jumps. If power is removed (hard reset) then the values in this section will be uninitialized.

Your system has startup code that sets up the C runtime environment before calling main. Your project may be using the default startup code provided by your toolchain. The default startup code likely initializes the .bss section to zero and initializes the variables in the .data section by copying from the .rodata section. If your bootloader and application are compiled as separate projects then they each have their own startup code, .bss, .data, and .rodata sections sections.

Your project may also be using the default linker script provided by your toolchain. The default linker script provides for the memory sections including .bss, .data, and .rodata. You can customize the linker script for your projects and add a custom section named .myspecialsection. You can locate .myspecialsection at a fixed address and size so that both the bootloader and application use the same memory for this section. You can make it so that .myspecialsection is not initialized by the startup code. And you can statically allocate variables and locate them in .myspecialsection. Now the bootloader or application can write a value into .myspecialsection and soft reset or jump to the other program and the values in .myspecialsection will maintain their values. This is how you can pass data values between the bootloader and application or vice-versa.

Read the linker manual to get specifics about how to create a section, how to locate and size it, how to make it uninitialized, and how to locate variables in the section.

Also, consider using a checksum on the data in .myspecialsection to avoid using the data when it is uninitialized.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I added an edit to my question to show the results I got when trying this. I am not sure if I did it correctly \$\endgroup\$ – Vincent Kenbeek Apr 7 at 16:01
  • 2
    \$\begingroup\$ Check the address of the config variable in the debugger. Is the address within the .boot_cfg section like you expect? Also check to see if the startup code is initializing the .boot_cfg section. Do you need some sort of "NOINIT" modifier somewhere in the linker script? \$\endgroup\$ – kkrambo Apr 7 at 16:17
  • \$\begingroup\$ Adding TYPE=NOINIT to the section definition seems to have fixed it. But while looking for ways to initiate a soft reset I came across the HAL_SYSTEM_RESET() which in its comments says that the CC26xx system has not been designed to handle soft resets and soft resets will make the system unstable and to use hard resets instead. \$\endgroup\$ – Vincent Kenbeek Apr 7 at 16:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.