I have a project with a FreeRTOS application running on custom hardware (STM32G483VETS). The project generates two versions of the binary. App1 loads at 0x08000000,App2 (future enhancements and bug fixes) at 0x08040000.
At power on, the MCU boots into App1 running in flash. When instructed over the CAN bus, it disables all interrupts, de-initialises all peripherals, sets up the new stack pointer and jumps to App2 with a call such as:
jump_to_app(EXTENDED_START); // EXTENDED_START is 0x08040000
Code for jump_to_app:
typedef struct {
uint32_t stack_address; // Stack Pointer
application_t *function_ptr; // Program Counter
} jump_structure_t;
void jumpToApp(const uint32_t address)
{
const jump_structure_t *jump_vector_p = (jump_structure_t*) address;
DeInit_all_modules();
/* Jump, uses assembler to avoid stack optimisation */
asm("msr msp, %0; bx %1;" : : "r"(jump_vector_p->stack_address), "r"(jump_vector_p->function_ptr));
}
Code for disabling interrupts and de-initialising modules:
void DeInitAllModules()
{
/* Disable all interrupts */
__disable_irq();
/* De-initialise all modules in the opposite order they were
* initialised in main.c
*/
// MX_OPAMP3_Init();
HAL_OPAMP_DeInit(&hopamp3);
// MX_OPAMP1_Init();
HAL_OPAMP_DeInit(&hopamp1);
// MX_TIM16_Init();
HAL_TIM_PWM_DeInit(&htim16);
// MX_SPI4_Init();
HAL_SPI_DeInit(&hspi4);
// MX_SPI3_Init();
HAL_SPI_DeInit(&hspi3);
// MX_SPI2_Init();
HAL_SPI_DeInit(&hspi2);
// MX_SPI1_Init();
HAL_SPI_DeInit(&hspi1);
//MX_DMA_Init();
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn);
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn);
HAL_NVIC_DisableIRQ(DMA1_Channel3_IRQn);
HAL_NVIC_DisableIRQ(DMA1_Channel2_IRQn);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn);
// MX_DAC3_Init();
HAL_DAC_DeInit(&hdac3);
// MX_COMP2_Init();
HAL_COMP_DeInit(&hcomp2);
// MX_ADC5_Init();
HAL_ADC_DeInit(&hadc5);
// MX_TIM8_Init();
HAL_TIM_PWM_DeInit(&htim8);
// MX_TIM3_Init();
HAL_TIM_Base_DeInit(&htim3);
// MX_TIM1_Init();
HAL_TIM_Base_DeInit(&htim1);
// MX_RTC_Init();
HAL_RTC_DeInit(&hrtc);
// MX_ADC1_Init();
HAL_ADC_DeInit(&hadc1);
// MX_FDCAN1_Init();
HAL_FDCAN_DeInit(&hfdcan1);
// MX_GPIO_Init();
HAL_GPIO_DeInit(USR_LED_GPIO_Port, USR_LED_Pin);
HAL_GPIO_DeInit(ERR_LED_GPIO_Port, ERR_LED_Pin);
__HAL_RCC_GPIOG_CLK_DISABLE();
__HAL_RCC_GPIOF_CLK_DISABLE();
__HAL_RCC_GPIOE_CLK_DISABLE();
__HAL_RCC_GPIOD_CLK_DISABLE();
__HAL_RCC_GPIOC_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOA_CLK_DISABLE();
HAL_DeInit();
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
}
Up until the point where the jump happens, the IDE is using the ELF to display the C code, variables etc. but App2 has a separate ELF.
How do I keep debugging after the jump? Can I 'combine' the ELF files?
I am developing in STM32CubeIDE v1.9.0 and debugging using a J-Link Ultra+.
Thanks
Go to the debugging configuration (you find this this by clicking the downwards arrow right of the green bug symbol and selecting "Debug configurations" in the drop-down menu) and select the debugging configuration that you use for debugging.
Select the "Start" tab.
In the "Start" tab you can specify which ELF files are used for debugging and you can specify if these ELF files are used for Flashing or only for the debugging information.
At least entering the new application (this is the
asm
part...) I would debug on machine code (disassembly) level.To do this, you check the "black 'i' with a yellow arrow to the right" button.
I have not much experience with FreeRTOS, but are you sure that the
CONTROL
register (which specifies ifmsp
orpsp
is the stack pointer and if the CPU runs in privileged mode) has the correct value?If the CPU is in privileged mode, you even have to enter an exception handler to modify the
CONTROL
register...There is a screenshot in the Eclipse Wiki: I'm talking about ...