Stack error when bootloader jumps to image with flash driver

Hi,

e2Studio/SSP    7.5.1/1.7.8, S7G2

I have a working Thread-X application.  I'm struggling with adding the simple serial bootloader to it.  I've placed the image at 0x010200.   The bootloader jumps to it just fine.  However, as soon as I include the flash driver to the image HAL, the bootload jump fails with a stack error. 

I'm confused as to what stack in the Thread-X application is affected by the addition of the flash driver to HAL.  If one opens the configuration.xml file and selects BSP, the properties tab shows:

Main stack size, Process stack size, and Heap size

Is "main stack size" what is used by HAL?

Steve

Parents
  • Yes the Main Stack is used by a HAL only project. In a ThreadX based project, the Main Stack is used by interrupt handlers, and the Process Stack is used by ThreadX threads (the PSP is changed on a context switch to a different Thread, to use the Process Stack for that particular thread, and the PSP Stack Monitor addresses are also updated, as the HW Stack monitor is enabled by default).

    Don't forget to disable the Stack monitor in the bootloader (for MSP and/or PSP depending on whether the bootloader uses Threadx or not), just before jumping to the ThreadX application.

Reply
  • Yes the Main Stack is used by a HAL only project. In a ThreadX based project, the Main Stack is used by interrupt handlers, and the Process Stack is used by ThreadX threads (the PSP is changed on a context switch to a different Thread, to use the Process Stack for that particular thread, and the PSP Stack Monitor addresses are also updated, as the HW Stack monitor is enabled by default).

    Don't forget to disable the Stack monitor in the bootloader (for MSP and/or PSP depending on whether the bootloader uses Threadx or not), just before jumping to the ThreadX application.

Children
  • Jeremy,

    Thank you very much.

    Unfortunately, I asked my question poorly and so have some follow up questions.

    My bootloader is the simple serial bootloader from renesas, thus is not threaded.

    My application is a Thread-X app based upon a Renesas sample of a couple years ago.  It may well have been the threaded blinky sample app.  My app has 10 threads, plus the HAL "thread".  (I wonder of the accuracy of calling the HAL a thread, but that's how the IDE refers to it.)

    1. You wrote "In a ThreadX based project, the Main Stack is used by interrupt handlers,"   Would the main stack also be used if a HAL driver declared local storage within its functions?

    2. You also wrote "In a ThreadX based project, ...  and the Process Stack is used by ThreadX threads (the PSP is changed on a context switch to a different Thread, to use the Process Stack for that particular thread".   Within the application configuration.xml file, on the threads tab, the properties fields contain a stack size parameter.  How does this relate to the process stack to which you referred?  I've been running with a process stack size  of zero.  That seems incorrect.

    3. assuming I add the flash driver to the HAL thread, is it the process stack I need to worry about?

    4. Assuming I add the flash driver to a different thread, that thread's stack must be the one affected by the flash driver (except for flash driver interrupts, whose handlers would be on the main stack).

    5. When it is time for the application to download new code, I have been setting a flag in flash and then calling NVIC_SystemReset().  (I have disabled Data Flash Background Operation in the r_flash_hp properties.)  The NVIC reset seems a quick and complete method to reset the entire system back to a known state.  It seems to be working for me.  Is this ill advised?

    6. As the bootloader is HAL only, I disable only the MSP when jumping to the threaded app.  When returning to the bootloader, I disable nothing due to the heavy handed approach of the NVIC reset.

    As reference, the jump to application portion of the bootloader is below.

    Again, thank you, Jeremy.

    Steve

    user_app_fnptr *p_jump_to_app;                                                                       // Function pointer to the user application.

    p_jump_to_app = ((user_app_fnptr*)IMAGE_APP_ADDRESS_RUN) + 1U;    // Point to the start reset vector for the application.
    __disable_irq(); // Disable interrupts
    SCB->VTOR = (uint32_t)IMAGE_APP_ADDRESS_RUN;     // Update the vector table to the reset vector of the application.
    __DSB();                                                                                 //Complete all explicit memory accesses.

    // Disable the stack monitor before jumping
    R_SPMON->MSPMPUCTL = (uint16_t)0x0000;                    // disable MSP monitoring

    __set_MSP(*((uint32_t*)IMAGE_APP_ADDRESS_RUN));   //Set stack for the application
    (*p_jump_to_app)();                                                               //Jump to application
    __NOP();

  • This looks loosely correct.  The startup code expects a stacj pointer in the MSO and you're loading it.  Is that address you're using internal sram on the part, and not something that will disappear durinfmg startup like external DRAM. Does this bootloader use ThreadX? I don't see anthung shutting it down, stopping scheduling etc.

  • It isn't where in the configurator the component is defined that determines which stack is used, it is which thread the API is called in that determines the stack that is used. The size of the stack for a thread is not defined in the BSP tab, it is defined in the properties of the thread in the Threads tab. Each individual thread has it's own individual thread (or process) stack. If an MPU stack NMI interrupt occurs after the Flash driver is added to the ThreadX project, I would suggest increasing the size of the thread stack where the Flash driver is called.

  • I'm sorry, I still don't understand the relationship between the process stack and the individual thread stacks.  A coworker's theory is the thread stacks are all located within the process stack, so I increased the process stack size to the sum of all thread stack sizes.  The problem disappeared.

    I'd like to fully understand what happened.  Is my coworker right?  Or did we fix the problem for some other reason?

    Thank you.

    Steve

  • No, each thread has it's own stack memory allocated. On a context switch, the PSP (Process Stack Pointer) is updated to point to the current stack location for that Thread in it's own stack memory area (this is done in the PendSV handler in synergy/ssp/src/framework/el/tx/tx_src/synergy/tx_thread_schedule.c, you will need to have the ThreadX source code added to the project to have that file in your project). If you look at the map file for a project with multiple threads you can see the different thread stack memory areas :-

    .stack_dummy    0x200156d0     0x5000 load address 0x00050f98
                    0x200156d0                . = ALIGN (0x8)
                    0x200156d0                __StackLimit = .
     *(.stack*)
     .stack         0x200156d0     0x1000 ./synergy/ssp/src/bsp/cmsis/Device/RENESAS/S7G2/Source/startup_S7G2.o
     .stack.camera_thread
                    0x200166d0      0x400 ./src/synergy_gen/camera_thread.o
     .stack.colour_thread
                    0x20016ad0      0x400 ./src/synergy_gen/colour_thread.o
     .stack.g_ip0   0x20016ed0      0x800 ./src/synergy_gen/common_data.o
     .stack.dhcp_printf_thread
                    0x200176d0      0x800 ./src/synergy_gen/dhcp_printf_thread.o
     .stack.g_http_server0
                    0x20017ed0     0x2000 ./src/synergy_gen/http_setup_thread.o
                    0x20017ed0                g_http_server0_stack_memory
     .stack.http_setup_thread
                    0x20019ed0      0x400 ./src/synergy_gen/http_setup_thread.o
     .stack.jpeg_thread
                    0x2001a2d0      0x400 ./src/synergy_gen/jpeg_thread.o
                    0x2001a6d0                __StackTop = .
                    [!provide]                PROVIDE (__stack, __StackTop)
                    0x2001a6d0                __RAM_segment_used_end__ = ALIGN (__StackTop, 0x4)

    The memory areas for the different Thread stacks are all in the .stack section, but they could equally be scattered across the SRAM.

    and the size of each of these stack memory areas is defined in the configurator :-

    you can see the thread stack memory allocated in the generated code for this thread (src\synergy_gen\http_setup_thread.c) :-

    To trap the stack monitor NMI interrupt you can register a callback for the NMI MPU stack monitor interrupt :-

    void usr_nmi_hw_stack_callback(bsp_grp_irq_t irq)__attribute__((optimize("-O0")));

            R_BSP_GroupIrqWrite(BSP_GRP_IRQ_MPU_STACK, usr_nmi_hw_stack_callback);

    Then you can identify if it was the MSP or PSP stack that caused the overflow :-

        uint32_t psp;
        uint32_t msp;
        TX_THREAD * current_thread;
        CHAR * thread_name;

    void usr_nmi_hw_stack_callback(bsp_grp_irq_t irq)
    {
        SSP_PARAMETER_NOT_USED(irq);

        msp = __get_MSP();
        psp = __get_PSP();

        if ((R_SPMON->MSPMPUSA > msp) || (R_SPMON->MSPMPUEA < msp))
        {
            __BKPT(0); // MSP stack outside range. Interrupt/kernel stack overflow.
        }
        else if ((R_SPMON->PSPMPUSA > psp) || (R_SPMON->PSPMPUEA < psp))
        {
            current_thread = tx_thread_identify();
            thread_name = current_thread->tx_thread_name; //Identify the currently executing thread
            __BKPT(0); // PSP stack outside range. Thread stack overflow.
        }
        else
        {
        }
    }

    If it is the PSP stack that has caused the NMI MPU stack monitor to fire, then increase the size of the stack for that thread, e.g. :-