cancel
Showing results for 
Search instead for 
Did you mean: 

Jump to Bootloader to UART Programming - Timeout error

FMass.1
Associate III

Hi, I need to create a system for which it is possible to update the firmware remotely.
My system communicates with a serial port (RS422) with a PC, and through this serial I would also like to update the firmware. Obviously without moving the BOOT0 pin, I'm talking about a finished product closed in a case.

What I would like to achieve is that when a specific command is received on the serial port, for example "FUP\r" the MCU goes into a mode where it is possible to update the FW via the serial port.

I tried this code found in various forums that talk about this topic:

 

 

void JumpToBootloader (void) {
	void (*SysMemBootJump)(void);
	volatile uint32_t addr = 0x1FFF0000;

    /**
     * Step: Disable RCC, set it to default (after reset) settings
     *       Internal clock, no PLL, etc.
     */
    HAL_RCC_DeInit();
    HAL_DeInit(); // add by ctien


	/* Disable all interrupts */
	__disable_irq();

	/* Disable Systick timer */
	SysTick->CTRL = 0;
	SysTick->LOAD = 0;
	SysTick->VAL = 0;

	__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();    //Call HAL macro to do this for you

	/* Clear Interrupt Enable Register & Interrupt Pending Register */
	for (uint32_t i=0;i<5;i++)
	{
		NVIC->ICER[i]=0xFFFFFFFF;
		NVIC->ICPR[i]=0xFFFFFFFF;
	}

	/* Re-enable all interrupts */
	__enable_irq();

	/* Set up the jump to boot loader address + 4 */
	SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));

	/* Set the main stack pointer to the boot loader stack */
	__set_MSP(*(uint32_t *)addr);

	/* Call the function to jump to boot loader location */
	SysMemBootJump();
}

 

 

Then in main loop:

 

 

memset(cmdRxBuffer, 0x00, sizeof(cmdRxBuffer));
	HALtmp_Status = HAL_UART_Receive(&DATA_INTERFACE, cmdRxBuffer, 4, 100); 

	  if(HALtmp_Status == HAL_OK ) {
		  printf("Received: %s\r\n", cmdRxBuffer);

		if( 	cmdRxBuffer[0] == 'F' &&
				cmdRxBuffer[1] == 'U' &&
				cmdRxBuffer[2] == 'P' &&
				cmdRxBuffer[3] == '\r') {
			printf("Update FW\r\n");
			JumpToBootloader();
		}
	  }

 

 

Indeed, when the command is received, the MCU enters the memory area 0x1FFFxxxx, so in theory it is in the boot loader zone.
In that situation I tried using STM32CubeProgrammer, but I always get a timeout error if I try to program the FW.

I have several doubts:
1 - Is the code I wrote correct? Do I need to change something?
2 - Is the procedure I use correct? What I do is: I connect with a serial terminal (Realterm) -> I send the command "FUP\r" -> I disconnect the serial terminal to leave the serial port free for the CUbeProgrammer -> Open STM32CubeProgrammer and try to program the MCU.
3 - Are there any constraints on the configuration of the serial port, for example I would like to use DMA in my application, does this conflict with programming via the serial port? Should I use a UART dedicated only to FW updating?
4 - Is there an easier way to do what I need to do?

I'm using a NUCLEO-L432KC board and UART2.

Someone can help me?

2 REPLIES 2

The bootloader expects all resources being in reset state, e.g. pins, clocks, peripherals. I don't know if HAL_Deinit() does that, I don't use Cube, but I doubt it.

You can also debug the bootloader, even if you don't have the sources, at least initially it's quite straighforward and reading peripherals' registers (GPIO, UART in your case) is the same as in normal debugging (with the same caveats).

You may also consider writing your own bootloader.

JW

I saw that there are many posts that do this thing with USB, so I thought it was simple enough with UART too, for example this one:

https://community.st.com/t5/stm32-mcus/how-to-jump-to-system-bootloader-from-application-code-on-stm32/ta-p/49424

Writing a custom bootloader seems excessive to me for such a simple task. I think this is the only solution?