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
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.
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.
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.
HAL only bootloader. Not ThreadX. Thanks!
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.
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. :-