cancel
Showing results for 
Search instead for 
Did you mean: 

USB DFU bootloader : start from source.

Slan
Associate II

Hello,

I am trying to restart a STM32L072 into DFU bootloader mode (using STM32 LoRa Discovery kit) .

The bootloader is working and I can use it to flash my firmware using a jumper between BOOT0 and VCC.

Now I would like to enter bootloader from source. I used instruction from https://www.youtube.com/watch?v=cvKC-4tCRgw, https://stm32f4-discovery.net/2017/04/tutorial-jump-system-memory-software-stm32/ and various other sources.

I am running FreeRTOS, and I don't know any proper way to shut it down, so what I do is writing a byte into backup register, then trigger a reset. On startup, right after HAL_Init() and before SystemClock_Config(), I check this byte. If set to 'R', I do the following :

  • RCC / systick reset
  • Disabling IRQ
  • Reset system flash memory
  • Reset Vector table
  • Set stack pointer to the adress in 0x1FF00000 (start of SystemMemory, according to AN2606)
  • Jump to 0x1FF00004
 
int main(void)
{
  HAL_Init();
 
  bootloader_trigger_if_requested();
 
  // Main continue to init MCU and start FreeRTOS, not relevant here.
 
}
 
 
void bootloader_trigger_if_requested(void){
	RTC_HandleTypeDef RtcHandle;
	RtcHandle.Instance = RTC;
	if(HAL_RTCEx_BKUPRead(&RtcHandle, BOOTLOADER_REQUEST_BACKUP_REGISTER) == 'R'){
		HAL_PWR_EnableBkUpAccess();
		HAL_RTCEx_BKUPWrite(&RtcHandle, BOOTLOADER_REQUEST_BACKUP_REGISTER, 0);
		HAL_PWR_DisableBkUpAccess();
		bootloader_init();
	}
}
 
 
/*!
 * @brief	Calling this will trigger the bootloader. Should be called only after a reset, to ensure no peripheral/IT/task/... will interfere.
 *
 */
static void bootloader_init(void){
 
	jump_to_bootloader = (void (*)(void)) (*((uint32_t *)(0x1FF00004)));
 
	HAL_RCC_DeInit();
	//Reset systick
	SysTick->CTRL = 0;
	SysTick->LOAD = 0;
	SysTick->VAL = 0;
 
	/**
	 * Step: Disable all interrupts
	 */
	__disable_irq();
 
	/* ARM Cortex-M Programming Guide to Memory Barrier Instructions.*/
	__DSB();
 
	__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
 
	SCB->VTOR=0;    //Reset vector table
 
 
	//Set Main Stack Pointer to it's default value
	__set_MSP(*(__IO uint32_t*) 0x1FF00000);
	jump_to_bootloader();
}

Bootloader does not start, and my program reset. If I did not reset backup register, bootloader_init() run multiple times, if I do reset backup register, my application work as usual.

What did I miss ?

5 REPLIES 5

You're supposed to turn off the interrupts you have turned on, not disable them on the processor, the processor doesn't normally start with them disabled this way.​

Make sure the syscfg clock is enabled and memory maps appropriately. Step the code and check the transition. ​

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Slan
Associate II

Thanks for your reply.

I removed the __disable_irq() call, there is no software enabled interrupt anyway as I call this code at reset. Just to be safe, I call it before HAL_Init(), it is now the first call when main start.

The clock was part of the problem, as it was in reset state (I thought the bootloader init code would take care of initializations). I now set the clock to HSI16, with no PLL. I also enabled HSI48 (which is used for USB)

The cause of the reset loop was SCB->VTOR=0; I removed it and it seems the program jump to bootloader code (If I set a breakpoint at 0x1FF00405, debugger console keep writing :

Starting target CPU...
...Breakpoint reached @ address 0x1FF00404
Reading all registers
Read 4 bytes @ address 0x1FF00404 (Data = 0x47004800)
Read 2 bytes @ address 0x1FF00404 (Data = 0x4800)

However, no USB DFU shows up in windows peripheral manager. I'm not sure where is the vector table for the bootloader. I don't think it can share the application vector table, and I read somewhere on the web it should be set at 0, but address 0 redirect to application start : 0x00000000 reads 0x20005000, which is stack pointer at startup, and 0x00000004 redirect to Reset handler (0x08013F59) (this explain the application reset).

Just before the jump to bootloader, MSP is set at 0x200014D0, and the jump is set to 0x1FF00405, which are the values in 0x1FF00000 and 0x1FF00004

My code is now as follow :

int main(void)
{
  bootloader_trigger_if_requested();
  HAL_Init();
  //...
}
 
/*****************************************************/
/**                         Trigger bootloader code                                    **/
/*****************************************************/
void (*jump_to_bootloader)(void);
 
static void bootloader_init(void);
static void BootloaderClockInit(void);
 
void bootloader_request_on_next_reset(void){
	RTC_HandleTypeDef RtcHandle;
	RtcHandle.Instance = RTC;
 
	HAL_PWR_EnableBkUpAccess();
	HAL_RTCEx_BKUPWrite(&RtcHandle, BOOTLOADER_REQUEST_BACKUP_REGISTER, 'R');
	HAL_PWR_DisableBkUpAccess();
}
 
 
void bootloader_trigger_if_requested(void){
	RTC_HandleTypeDef RtcHandle;
	RtcHandle.Instance = RTC;
	if(HAL_RTCEx_BKUPRead(&RtcHandle, BOOTLOADER_REQUEST_BACKUP_REGISTER) == 'R'){
		__HAL_RCC_PWR_CLK_ENABLE();
		HAL_PWR_EnableBkUpAccess();
		HAL_RTCEx_BKUPWrite(&RtcHandle, BOOTLOADER_REQUEST_BACKUP_REGISTER, 0);
		HAL_PWR_DisableBkUpAccess();
		__HAL_RCC_PWR_CLK_DISABLE();
		bootloader_init();
	}
}
 
/*!
 * @brief	Calling this will trigger the bootloader. Should be called only after a reset, to ensure no peripheral/IT/task/... will interfere.
 *
 */
static void bootloader_init(void){
 
	jump_to_bootloader = (void (*)(void)) (*((uint32_t *)(0x1FF00004)));
 
	//HAL_RCC_DeInit();
	BootloaderClockInit();
	//Reset systick
	SysTick->CTRL = 0;
	SysTick->LOAD = 0;
	SysTick->VAL = 0;
 
	//No need to disable interrupt, this is call on startup only, before any initialization
	//__disable_irq();
 
	/* Probably not needed, but just to be sure.*/
	__DSB();
	__ISB();
	__DMB();
 
	__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
//	SCB->VTOR=0;
 
	//Set Main Stack Pointer to it's default value
	__set_MSP(*(__IO uint32_t*) 0x1FF00000);
 
        /* Probably not needed, but just to be sure.*/
	__DSB();
	__ISB();
	__DMB();
 
	jump_to_bootloader();
}
 
static void BootloaderClockInit(void){
	RCC_OscInitTypeDef RCC_OscInitStruct;
	RCC_ClkInitTypeDef RCC_ClkInitStruct;
 
	/**Configure the main internal regulator output voltage
	*/
	__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 
	/**Initializes the CPU, AHB and APB busses clocks
	*/
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
	RCC_OscInitStruct.HSIState = RCC_HSI_ON;
	RCC_OscInitStruct.HSICalibrationValue = 16;
	RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
	{
	_Error_Handler(__FILE__, __LINE__);
	}
 
	/**Initializes the CPU, AHB and APB busses clocks
	*/
	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
							  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
	{
	_Error_Handler(__FILE__, __LINE__);
	}
}

Were you able to get this working. Going through this process now.

Same here - any luck with this?

Try to call bootloader_init() from the beginning of SystemInit() located in Core/Src/system_stm32l0xx.c

And disable all IRQs, including pending interrupts

    for (int x = 0; x < 8; x++)
    {
        // Mask all IRQs controlled by a ICERx
        NVIC->ICER[x] = 0xFFFFFFFF;
        // Clear all pending IRQs controlled by a ICPRx
        NVIC->ICPR[x] = 0xFFFFFFFF;
    }