Add dual-bank STM32 bootloader support, given GPIO toggle on BOOT0 to charge RC circuit. (#8778)

This commit is contained in:
Nick Brassel 2020-07-16 16:58:14 +10:00 committed by James Young
parent d0abad27ab
commit 93e7a8f74c
3 changed files with 86 additions and 20 deletions

View file

@ -3,28 +3,82 @@
#include "ch.h"
#include "hal.h"
#ifdef STM32_BOOTLOADER_ADDRESS
/* STM32 */
/* This code should be checked whether it runs correctly on platforms */
# define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
extern uint32_t __ram0_end__;
# define BOOTLOADER_MAGIC 0xDEADBEEF
# define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4)
#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
#define BOOTLOADER_MAGIC 0xDEADBEEF
#define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4)
#ifndef STM32_BOOTLOADER_DUAL_BANK
# define STM32_BOOTLOADER_DUAL_BANK FALSE
#endif
#if STM32_BOOTLOADER_DUAL_BANK
// Need pin definitions
# include "config_common.h"
# ifndef STM32_BOOTLOADER_DUAL_BANK_GPIO
# error "No STM32_BOOTLOADER_DUAL_BANK_GPIO defined, don't know which pin to toggle"
# endif
# ifndef STM32_BOOTLOADER_DUAL_BANK_POLARITY
# define STM32_BOOTLOADER_DUAL_BANK_POLARITY 0
# endif
# ifndef STM32_BOOTLOADER_DUAL_BANK_DELAY
# define STM32_BOOTLOADER_DUAL_BANK_DELAY 100000
# endif
extern uint32_t __ram0_end__;
# define bootdelay(loopcount) \
do { \
for (int i = 0; i < loopcount; ++i) { \
__asm__ volatile("nop\n\t" \
"nop\n\t" \
"nop\n\t"); \
} \
} while (0)
void bootloader_jump(void) {
*MAGIC_ADDR = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
NVIC_SystemReset();
}
void enter_bootloader_mode_if_requested(void) {
unsigned long *check = MAGIC_ADDR;
if (*check == BOOTLOADER_MAGIC) {
*check = 0;
// For STM32 MCUs with dual-bank flash, and we're incapable of jumping to the bootloader. The first valid flash
// bank is executed unconditionally after a reset, so it doesn't enter DFU unless BOOT0 is high. Instead, we do
// it with hardware...in this case, we pull a GPIO high/low depending on the configuration, connects 3.3V to
// BOOT0's RC charging circuit, lets it charge the capacitor, and issue a system reset. See the QMK discord
// #hardware channel pins for an example circuit.
palSetPadMode(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_MODE_OUTPUT_PUSHPULL);
# if STM32_BOOTLOADER_DUAL_BANK_POLARITY
palSetPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
# else
palClearPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
# endif
// Wait for a while for the capacitor to charge
bootdelay(STM32_BOOTLOADER_DUAL_BANK_DELAY);
// Issue a system reset to get the ROM bootloader to execute, with BOOT0 high
NVIC_SystemReset();
}
}
#elif defined(STM32_BOOTLOADER_ADDRESS) // STM32_BOOTLOADER_DUAL_BANK
extern uint32_t __ram0_end__;
/** \brief Jump to the bootloader
*
* FIXME: needs doc
*/
void bootloader_jump(void) {
*MAGIC_ADDR = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
NVIC_SystemReset();
}
/** \brief Enter bootloader mode if requested
*
* FIXME: needs doc
*/
void enter_bootloader_mode_if_requested(void) {
unsigned long *check = MAGIC_ADDR;
if (*check == BOOTLOADER_MAGIC) {
@ -41,7 +95,7 @@ void enter_bootloader_mode_if_requested(void) {
}
}
#elif defined(KL2x) || defined(K20x) /* STM32_BOOTLOADER_ADDRESS */
#elif defined(KL2x) || defined(K20x) // STM32_BOOTLOADER_DUAL_BANK // STM32_BOOTLOADER_ADDRESS
/* Kinetis */
# if defined(KIIBOHD_BOOTLOADER)