Simple bootloader

Hi,

 

I need to add a simple bootloader to my product.

To start understanding how things work in Synergy, I created two projects in a new workspace: Bootloader and Application.

Bootloader blinks a LED each seconds. Application blinks a LED each 2 seconds.

 

Then, I edited the S3A7.Id file inside the Application. They are like this now:

Bootloader:

MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x0100000 /* 1M */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0030000 /* 192K */
DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x0004000 /* 16K */
QSPI_FLASH (rx) : ORIGIN = 0x60000000, LENGTH = 0x4000000 /* 64M, Change in QSPI section below also */
}

 

 

Application:

MEMORY
{
FLASH (rx) : ORIGIN = 0x00080000, LENGTH = 0x0080000 /* 1M */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0030000 /* 192K */
DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x0004000 /* 16K */
QSPI_FLASH (rx) : ORIGIN = 0x60000000, LENGTH = 0x4000000 /* 64M, Change in QSPI section below also */
}

 

I can download and debug the Bootloader just fine, but I can't debug the Application.

When trying to debug it the initial file that is opened by the debbuger says "No source available for" and it never reaches the breakpoint inserted at the first line of the thread.

I am not trying to jump between the two programs yet. I am only trying to download and debug a program in a address different of 0x00000000.

  • Mad River,

    The problem is that on the ARM -M arch. the program start address is at the reset vector +4 and the Stack pointer is at the reset vector. I solve this issue by having the bootloader installed in the target and then having the boot loader check to see if an app is loaded and if so, jump into the app image. To debug the target with the bootloader installed, download/debug the app and reset the target, then press run. The code will run in the bootloader and then call the app and break at app's reset and then main. The code snippet that handles the call to the app also cleans up any interrupts and stack stuff. Please see code below:

    static void execute_user_code(uint32_t address)
    {
    ssp_feature_t ssp_feature = {{(ssp_ip_t) 0U}};
    fmi_event_info_t event_info = {(IRQn_Type) 0U};

    main_fnptr *p_jump_to_app; // Function pointer main that will be used to jump to application

    __disable_irq();

    /* Disable the stack monitor */
    R_SPMON->MSPMPUPT = 0xA500; /* Enable access to Main Stack Pointer Monitor Access Control Register */
    R_SPMON->PSPMPUPT = 0xA500; /* Enable access to Process Stack Pointer Monitor Access Control Register */

    R_SPMON->MSPMPUCTL_b.ENABLE = 0; /* disable the Main stack monitor */
    R_SPMON->PSPMPUCTL_b.ENABLE = 0; /* disable the Process stack monitor */

    SysTick->CTRL = 0; /* Disable the systick timer */
    NVIC_DisableIRQ ( SysTick_IRQn ); /* Disable the systick timer IRQ */
    NVIC_ClearPendingIRQ( SysTick_IRQn ); /* Clear any pending systick timer IRQ */


    /** Disable and clear interrupts of USBFS */
    R_USBFS->INTENB0 = 0;
    R_USBFS->INTENB1 = 0;
    R_USBFS->BRDYENB = 0;
    R_USBFS->NRDYENB = 0;
    R_USBFS->BEMPENB = 0;
    R_USBFS->INTENB1 = 0;
    R_USBFS->INTSTS0 = 0;
    R_USBFS->INTSTS1 = 0;
    R_USBFS->BRDYSTS = 0;
    R_USBFS->NRDYSTS = 0;
    R_USBFS->BEMPSTS = 0;

    /** Disables pull-up of D- line for USBFS so the bus line is to be SE0(Single Ended0) and detached. */
    R_USBFS->SYSCFG_b.DPRPU = 0;

    R_BSP_SoftwareDelay(10,BSP_DELAY_UNITS_MILLISECONDS);

    /** Clear FIFOs of USBHS */
    R_USBFS->CFIFOCTR_b.BCLR = 1;
    R_USBFS->D0FIFOCTR_b.BCLR = 1;
    R_USBFS->D1FIFOCTR_b.BCLR = 1;


    R_USBFS->PIPE1TRE_b.TRCLR = 1U;
    R_USBFS->PIPE2TRE_b.TRCLR = 1U;
    R_USBFS->PIPE3TRE_b.TRCLR = 1U;
    R_USBFS->PIPE4TRE_b.TRCLR = 1U;
    R_USBFS->PIPE5TRE_b.TRCLR = 1U;
    R_USBHS->PIPE1CTR = 0U;
    R_USBFS->PIPE2CTR = 0U;
    R_USBFS->PIPE3CTR = 0U;
    R_USBFS->PIPE4CTR = 0U;
    R_USBFS->PIPE5CTR = 0U;
    R_USBFS->PIPE6CTR = 0U;
    R_USBFS->PIPE7CTR = 0U;
    R_USBFS->PIPE8CTR = 0U;
    R_USBFS->PIPE9CTR = 0U;
    R_USBFS->DCPCFG = 0U;
    R_USBFS->DCPMAXP = 0U;
    R_USBFS->DCPCTR = 0U;
    for (uint16_t i = 0U; i < 9U; i++)
    {
    R_USBFS->PIPESEL = i;
    R_USBFS->PIPECFG = 0U;
    R_USBFS->PIPEMAXP = 0U;
    }

    /** Disables operation of USBFS. */
    R_USBFS->SYSCFG_b.USBE = 0;

    R_BSP_SoftwareDelay(10,BSP_DELAY_UNITS_MILLISECONDS);

    /** Halts clock of USBFS. */
    R_USBFS->SYSCFG_b.SCKE = 0;

    /** Disables interrupt of USBFS. */
    ssp_feature.id = SSP_IP_USB;
    ssp_feature.channel = 0U;
    g_fmi_on_fmi.eventInfoGet(&ssp_feature, SSP_SIGNAL_USB_INT, &event_info);
    NVIC_DisableIRQ(event_info.irq);

    R_BSP_ModuleStop(&ssp_feature);

    R_ELC_Disable();

    /*
    * Clear all interrupts!
    *
    */
    for (uint32_t i = 0; i<96; i++)
    {
    R_ICU->IELSRn[i] = 0;
    }
    for (uint32_t i = 0; i<8; i++)
    {
    NVIC->ICER[i] = 0xFFFFFFFF;
    NVIC->ICPR[i] = 0xFFFFFFFF;
    }
    for (uint32_t i = 0; i<16; i++)
    {
    R_ICU->IRQCRn[i] = 0;
    }
    /* Ensure that when we jump we're using the Main Stack Pointer */
    __set_CONTROL(0);

    p_jump_to_app = (main_fnptr*)(address+4);
    SCB->VTOR = (address & 0x1FFFFF80);
    __DSB();

    /** Set stack here. */
    __set_MSP(*((uint32_t*)(address)));

    /** Jump to image*/
    (*p_jump_to_app)();

    }

    -Gary
  • I am looking at an example (downloader_usb_cdc_blocking) that puts the Application at address 0x00280000:
    MEMORY
    {
    FLASH (rx) : ORIGIN = 0x00280000, LENGTH = 0x0180000 /* 4M */
    RAM (rwx) : ORIGIN = 0x1FFE0000, LENGTH = 0x00A0000 /* 640K */
    DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x0010000 /* 64K */
    QSPI_FLASH (rx) : ORIGIN = 0x60000000, LENGTH = 0x4000000 /* 64M, Change in QSPI section below also */
    SDRAM (rwx) : ORIGIN = 0x90000000, LENGTH = 0x2000000 /* 32M */
    }

    Then, "inside Debug Configurations > downloader_usb_cdc_blocking Debug > Startup > Run Commands" there are the following lines:
    set $sp = *0x280000
    set $pc = *0x280004
    set {int}0xe000ed08 = 0x280000

    As my own Application is stored at 0x00080000, I inserted the following in my project:
    set $sp = *0x80000
    set $pc = *0x80004
    set {int}0xe000ed08 = 0x80000

    Now, the Startup_S3A7.c file is opened when debbuger start, after that the main.c file is opened, after that it shows "No source available for "0x0".

    What am I missing?
    What is "{int}0xe000ed08" in the command lines?

  • In reply to garyj:

    Hi Gary,

    Thank you very much for your answer.

     

    I tried to compile your code, but somethings are missing.

    Here are the generated errors:

  • In reply to Mad River:

    Mad River,

    I just cut/pasted the code out of context - if your not using USB then remove all references to that IP from the code.

    #define APP_START_ADDR 0x00080000
    typedef int (*main_fnptr)(void); // Prototype for function pointer to the image

    .
    .
    .
    execute_user_code(APP_START_ADDR);

    Don't worry about no source at the address space of the bootloader.
    Remove the run commands - they are not needed.

    -Gary
  • In reply to garyj:

    Hi Gary,

     

    Thank you very much! It worked now.

    I am able to debug the application!

     

    About the USB part that I removed in this first test.

    My bootloader will use the SPI driver to access a external flash memory where the new application firmware will be stored and the flash driver to overwrite the application firmware.

    My application will use ThreadX and several peripherals (UART, SPI, USB, etc).

    What must be disabled in the bootloader code in order to correctly jump to the application?

    You made a lot of manual disabling in your jump code, isn't a easier way to do that? Something like a "disable all interrupts"?

  • In reply to Mad River:

    Hello Mad River, Gary,

    Can I just outline that if you're using flashloader framework and the client application has an instance of sf_firmware_image_mcu framework (which places application header data at 0x800 from the base of the application in section ".sf_firmware_image_file_header") you can start any application that was programmed through the bootloader (applications programmed through the debugger won't work with this) using appStart bootloader API call. This performs a CRC check of the application before setting up the initial stack pointer, vector offset and jumping to the application.

    Regards
  • In reply to Renesas Karol:

    Hi Karol,

    Is there a example project or a Application Note of how to use the flashloader framework.

    What would be the best solution to work with this during development phase (as it can't run application programmed by debugger)?
  • In reply to Mad River:

    Hello Mad River,

    You can find 4 example applications in the archive with the Flashloader Framework Add-on. I shared an alternative example (without serial interface but with USB Mass Storage) in the following thread: renesasrulz.com/.../27211 . For debugging, you can dispatch your projects using the debugger with additional 3 settings, as specified earlier. Later on, I recommend verifying the behavoiur of the programmer module by programming in application in BCH format (these are created using the MOT converter which is also part of the package) as this would reflect on how the solution would work in real-world application.

    Regards
  • In reply to garyj:

    garyj
    Mad River,

    I just cut/pasted the code out of context - if your not using USB then remove all references to that IP from the code.

    #define APP_START_ADDR 0x00080000
    typedef int (*main_fnptr)(void); // Prototype for function pointer to the image

    .
    .
    .
    execute_user_code(APP_START_ADDR);

    Don't worry about no source at the address space of the bootloader.
    Remove the run commands - they are not needed.

    -Gary
     

    Hi Gary,

     

    After some time idle, I came back to the project.

     

    Well, I am using only the SPI HAL drivers (one instance of r_rspi and one instance of r_sci_spi).

    In your code, you do a lot of work to disable the USB before jumping to the application.

    Should I do similar work to disable the SPI drivers before jump?

    Can I only call the close function in the driver api?

  • In reply to Mad River:

    Mad River,

    Yes, you can remove the USB related code in the code snippet that I sent - calling the close API for the SPI should disable the interrupts for that module.

    -Gary
  • In reply to garyj:

    Hey Gary,
    It looks like you have pretty much completed what I'm working on, at least in part. I need to boot to bootloader, check for thumbdrive, if new image there copy to QSPI (for various reasons), then copy from QSPI to FLASH, then jump to FLASH.
    I was having trouble jumping to my app until I saw your code above - figured it was something like that, thanks for putting that together. I had been using the jumpToApp from the simple bootloader example that does it over CDC with xmodem.

    I'm mostly there, but was just wondering if you can share your code or if you already have, where is it?.