Add dual-bank STM32 bootloader support, given GPIO toggle on BOOT0 to charge RC circuit. (#8778)
This commit is contained in:
		
							parent
							
								
									d0abad27ab
								
							
						
					
					
						commit
						93e7a8f74c
					
				
					 3 changed files with 86 additions and 20 deletions
				
			
		| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue