Skip to main content
Visitor II
October 19, 2018
Question

USB DFU bootloader : start from source.

  • October 19, 2018
  • 2 replies
  • 2176 views

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 ?

    This topic has been closed for replies.

    2 replies

    Graduate II
    October 19, 2018

    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. ​

    SlanAuthor
    Visitor II
    October 19, 2018

    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__);
    	}
    }

    Visitor II
    February 25, 2021

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

    Visitor II
    March 18, 2023

    Same here - any luck with this?