global: add common function to start DFU and systeme memory

This commit is contained in:
King Kévin 2020-11-27 16:37:52 +01:00
parent de36c7f3a2
commit 06de8d0be9
2 changed files with 70 additions and 1 deletions

View File

@ -16,6 +16,8 @@
#include <libopencm3/stm32/rcc.h> // real-time control clock library
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/stm32/exti.h> // external interrupt defines
#include <libopencm3/stm32/syscfg.h> // system definitions
#include <libopencm3/usb/dwc/otg_fs.h> // USB OTG utilities
#include "global.h" // common methods
@ -201,6 +203,66 @@ void board_setup(void)
user_input_used = 0;
}
/** disconnect USB by sending a reset condition */
static void usb_disconnect(void)
{
if (OTG_FS_GUSBCFG & OTG_GUSBCFG_FDMOD) { // USB configured as device
// pull USB D+ low for a short while
OTG_FS_DCTL |= OTG_DCTL_SDIS; // disconnect DP pull-up to simulate a disconnect
// in case there is an external pull-up resistor, pull DP low
// I have no idea why, but once USB is configured, I can't use PA12/DP back as GPIO
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO12); // be sure the D+ pin can be used as GPIO output
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO12); // use push-pull output
gpio_clear(GPIOA, GPIO12); // pull D+ low
for (volatile uint32_t i = 0; i < 0x2000; i++); // USB disconnected must be at least 10 ms long, at most 100 ms
}
}
void system_memory(void)
{
usb_disconnect(); // disconnect from USB (if necessary)
// for more details, see https://stm32f4-discovery.net/2017/04/tutorial-jump-system-memory-software-stm32/
// deinit RCC (according to STM32CubeF4 source code)
RCC_CR |= RCC_CR_HSION; // enable high speed internal clock
while (!(RCC_CR & RCC_CR_HSIRDY)); // wait until clock is ready
RCC_CR |= (0x10U << RCC_CR_HSITRIM_SHIFT); // set HSITRIM[4:0] bits to the reset value
RCC_CFGR = 0;// reset CFGR register
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_HSI); // wait it till clock switch is ready
RCC_CR &= ~(RCC_CR_HSEON | RCC_CR_HSEBYP | RCC_CR_CSSON); // clear HSEON, HSEBYP and CSSON bits
while (RCC_CR & RCC_CR_HSERDY); // wait till HSE is disabled
RCC_CR &= ~RCC_CR_PLLON; // Clear PLLON bit
while (RCC_CR & RCC_CR_PLLRDY); // wait till PLL is disabled
//RCC_PLLCFGR = 0x24003010; // reset PLLCFGR register to default value (value for STM32F401)
RCC_CIR &= ~(RCC_CIR_LSIRDYIE | RCC_CIR_LSERDYIE | RCC_CIR_HSIRDYIE | RCC_CIR_HSERDYIE | RCC_CIR_PLLRDYIE); // disable all interrupts
RCC_CIR |= (RCC_CIR_LSIRDYC | RCC_CIR_LSERDYC | RCC_CIR_HSIRDYC | RCC_CIR_HSERDYC | RCC_CIR_PLLRDYC | RCC_CIR_CSSC); // clear all interrupt flags
RCC_CR &= ~RCC_CSR_LSION; // clear LSION bit
RCC_CSR |= RCC_CSR_RMVF; // reset all CSR flags
// switch to system memory
RCC_APB2ENR = RCC_APB2ENR_SYSCFGEN; // enable system configure clock (all others are not required)
cm_disable_interrupts(); // disable all interrupts
SYSCFG_MEMRM = 1; // map system memory to 0x0000 0000 (this bypasses the BOOT0 pin)
const uint32_t address = 0x1FFF0000; // system memory address
__asm__ volatile ("MSR msp,%0" : :"r"(*(uint32_t*)address)); // set stack pointer to address provided in the beginning of the bootloader (loaded into a register first)
(*(void(**)(void))((uint32_t)address + 4))(); // start system memory (by jumping to the reset function which address is stored as second entry of the vector table)
// we should not reach this point
}
void dfu_bootloader(void)
{
usb_disconnect(); // disconnect from USB (if necessary)
// set DFU magic to specific RAM location
__dfu_magic[0] = 'D';
__dfu_magic[1] = 'F';
__dfu_magic[2] = 'U';
__dfu_magic[3] = '!';
scb_reset_system(); // reset system (core and peripherals)
while (true); // wait for the reset to happen
}
#if defined(BUTTON_PIN)
/** interrupt service routine called when button is pressed */
void GPIO_EXTI_ISR(BUTTON_PIN)(void)

View File

@ -495,4 +495,11 @@ char user_input_get(void);
void user_input_store(char c);
/** setup board peripherals */
void board_setup(void);
/** start embedded bootloader (e.g. system memory)
* @warning the USB DFU bootloader does not start
* @note after jumping to the bootloader, the USB device is detected, but does not enumerate. I have no idea about the cause. Not configuring the USB did not solve the issue. Re-initializing RCC did not help. Even the STM32CodeMX generated code was not able to have a working USB DFU reboot. Calibrating HSI according to https://community.st.com/s/question/0D50X0000BG0TfH/stm32f4-usb-dfu-bootloader-not-working-reliably did not solve the issue. Maybe there is something with the board. Booting the embedded USB DFU bootloader by hand by pressing the BOOT0 button works.
* @note the USART bootloader works fine though
*/
void system_memory(void);
/** start DFU bootloader */
void dfu_bootloader(void);