cancel
Showing results for 
Search instead for 
Did you mean: 

Leave GPIO pin state when jumping to bootloader

JMill.1
Associate III

I have been using this solution to jump to the ROM bootloader and that is working fine. However, it only works if the chip is coming out of reset and none of the peripherals are initialized, FreeRTOS scheduler not running, etc. Basically the chip needs a fresh restart in order for this method to reliably get to the bootloader.

This means I need to write a magic number to a RAM location, call NVIC_SystemReset(), then invoke the linked code. However, in my application, I would like to leave on external circuit enabled while this happens, which means I would like to leave one GPIO pulled high while in bootloader. When I call the reset function, it (obviously) resets all the GPIO to high-impedance input and I lose the state of the external circuit.

Is there any way to 1) call some version of NVIC_SystemReset() that is less aggressive about resetting everything, or 2) modify the linked code so I can jump to the bootloader from the FreeRTOS task?

Thanks,

Jamie

5 REPLIES 5

1) No

2) Sure, you have control of the MCU, you can jump or transfer control any place you want.

You'd want to disable interrupts at their sources, not at the MCU level, and you'd also want the MCU in the SYSTEM/PRIVILEGED rather than PROCESS/UNPRIVILEGED state, and not have any hierarchy stacked up in the NVIC, ie don't call from an interrupt, EXTI, FAULT or SVC. Have the clocks and PLLs in the reset state.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
MM..1
Chief III

If is complex and complicated switch all to prepared mode, exist IWDG or WWDG resets marked with flags, that you can use to jump into boot immediately after reset.

JMill.1
Associate III

Yes, I think I am not resetting enough things to get it into a proper mode ready for the jump. Here is my code snippet which is called from a FreeRTOS task:

/* Set the address of the entry point to bootloader */

volatile uint32_t BootAddr = 0x1FF09800;

/* Disable all interrupts */

__disable_irq();

// Stop DMA and reset UART

HAL_UART_DMAStop(DebugUart);

HAL_UART_DeInit(DebugUart);

/* Disable Systick timer */

HAL_SuspendTick();

/* Set the clock to the default state */

HAL_RCC_DeInit();

/* Clear Interrupt Enable Register & Interrupt Pending Register */

uint8_t i;

for (i=0;i<5;i++) {

NVIC->ICER[i]=0xFFFFFFFF;

NVIC->ICPR[i]=0xFFFFFFFF;

}

/* Re-enable all interrupts */

__enable_irq();

/* Set up the jump to booloader address + 4 */

SysMemBootJump = (void (*)(void)) (*((uint32_t *) ((BootAddr + 4))));

/* Set the main stack pointer to the bootloader stack */

__set_MSP(*(uint32_t *)BootAddr);

/* Call the function to jump to bootloader location */

SysMemBootJump();

/* Jump is done successfully */

while(1);

I consistently get "Break at address "0x1ff0b4cc" with no debug information available, or outside of program code" as soon as I open the COM port to start the bootload process. If I run the exact same code from main first thing before even the HAL_Init() is called, no problem, it works.

Piranha
Chief II

When the stack pointer (MSP) is changed, the local variables are no longer valid, including the SysMemBootJump pointer. The only way to do it reliably in C is to make that variable static/global. But the recommended way is to do it with a few lines of assambler:

https://community.st.com/s/question/0D50X0000AFpTmUSQV/using-nvicsystemreset-in-bootloaderapplication-jumps

Deinitializing the whole system is asking for a trouble... Maybe it's OK to put a pull-up on that line? If no, I would consider adding an external SR latch or something appropriate.

meimurugan
Associate II

Hi all,

How did you resolve this issue.

 

 

Thanks,