qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

stm32_dfu.c (4878B)


      1 /* Copyright 2021-2023 QMK
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15  */
     16 
     17 #include "bootloader.h"
     18 #include "util.h"
     19 
     20 #include <ch.h>
     21 #include <hal.h>
     22 #include "wait.h"
     23 
     24 #ifndef STM32_BOOTLOADER_RAM_SYMBOL
     25 #    define STM32_BOOTLOADER_RAM_SYMBOL __ram0_end__
     26 #endif
     27 
     28 extern uint32_t STM32_BOOTLOADER_RAM_SYMBOL;
     29 
     30 #ifndef STM32_BOOTLOADER_DUAL_BANK
     31 #    define STM32_BOOTLOADER_DUAL_BANK FALSE
     32 #endif
     33 
     34 #if STM32_BOOTLOADER_DUAL_BANK
     35 #    include "gpio.h"
     36 
     37 #    ifndef STM32_BOOTLOADER_DUAL_BANK_GPIO
     38 #        error "No STM32_BOOTLOADER_DUAL_BANK_GPIO defined, don't know which pin to toggle"
     39 #    endif
     40 
     41 #    ifndef STM32_BOOTLOADER_DUAL_BANK_POLARITY
     42 #        define STM32_BOOTLOADER_DUAL_BANK_POLARITY 0
     43 #    endif
     44 
     45 #    ifndef STM32_BOOTLOADER_DUAL_BANK_DELAY
     46 #        define STM32_BOOTLOADER_DUAL_BANK_DELAY 100
     47 #    endif
     48 
     49 __attribute__((weak)) void bootloader_jump(void) {
     50     // For STM32 MCUs with dual-bank flash, and we're incapable of jumping to the bootloader. The first valid flash
     51     // bank is executed unconditionally after a reset, so it doesn't enter DFU unless BOOT0 is high. Instead, we do
     52     // it with hardware...in this case, we pull a GPIO high/low depending on the configuration, connects 3.3V to
     53     // BOOT0's RC charging circuit, lets it charge the capacitor, and issue a system reset. See the QMK discord
     54     // #hardware channel pins for an example circuit.
     55     palSetPadMode(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_MODE_OUTPUT_PUSHPULL);
     56 #    if STM32_BOOTLOADER_DUAL_BANK_POLARITY
     57     palSetPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
     58 #    else
     59     palClearPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
     60 #    endif
     61 
     62     // Wait for a while for the capacitor to charge
     63     wait_ms(STM32_BOOTLOADER_DUAL_BANK_DELAY);
     64 
     65     // Issue a system reset to get the ROM bootloader to execute, with BOOT0 high
     66     NVIC_SystemReset();
     67 }
     68 
     69 __attribute__((weak)) void mcu_reset(void) {
     70     NVIC_SystemReset();
     71 }
     72 // not needed at all, but if anybody attempts to invoke it....
     73 void enter_bootloader_mode_if_requested(void) {}
     74 
     75 #else
     76 
     77 /* This code should be checked whether it runs correctly on platforms */
     78 #    define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
     79 #    define BOOTLOADER_MAGIC 0xDEADBEEF
     80 #    define MAGIC_ADDR (unsigned long *)(SYMVAL(STM32_BOOTLOADER_RAM_SYMBOL) - 4)
     81 
     82 __attribute__((weak)) void bootloader_marker_enable(void) {
     83     uint32_t *marker = (uint32_t *)MAGIC_ADDR;
     84     *marker          = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
     85 }
     86 
     87 __attribute__((weak)) bool bootloader_marker_active(void) {
     88     const uint32_t *marker = (const uint32_t *)MAGIC_ADDR;
     89     return (*marker == BOOTLOADER_MAGIC) ? true : false;
     90 }
     91 
     92 __attribute__((weak)) void bootloader_marker_disable(void) {
     93     uint32_t *marker = (uint32_t *)MAGIC_ADDR;
     94     *marker          = 0;
     95 }
     96 
     97 __attribute__((weak)) void bootloader_jump(void) {
     98     bootloader_marker_enable();
     99     NVIC_SystemReset();
    100 }
    101 
    102 __attribute__((weak)) void mcu_reset(void) {
    103     NVIC_SystemReset();
    104 }
    105 
    106 void enter_bootloader_mode_if_requested(void) {
    107     if (bootloader_marker_active()) {
    108         bootloader_marker_disable();
    109 
    110         struct system_memory_vector_t {
    111             uint32_t stack_top;
    112             void (*entrypoint)(void);
    113         };
    114         const struct system_memory_vector_t *bootloader = (const struct system_memory_vector_t *)(STM32_BOOTLOADER_ADDRESS);
    115 
    116         __disable_irq();
    117 
    118 #    if defined(QMK_MCU_ARCH_CORTEX_M7)
    119         SCB_DisableDCache();
    120         SCB_DisableICache();
    121 #    endif
    122 
    123 #    if defined(__MPU_PRESENT) && (__MPU_PRESENT == 1U)
    124         ARM_MPU_Disable();
    125 #    endif
    126 
    127         SysTick->CTRL = 0;
    128         SysTick->VAL  = 0;
    129         SysTick->LOAD = 0;
    130 
    131         // Clear interrupt enable and interrupt pending registers
    132         for (int i = 0; i < ARRAY_SIZE(NVIC->ICER); i++) {
    133             NVIC->ICER[i] = 0xFFFFFFFF;
    134             NVIC->ICPR[i] = 0xFFFFFFFF;
    135         }
    136 
    137         __set_CONTROL(0);
    138         __set_MSP(bootloader->stack_top);
    139         __enable_irq();
    140 
    141         // Jump to bootloader
    142         bootloader->entrypoint();
    143         while (true) {
    144         }
    145     }
    146 }
    147 #endif