From 0819f0eb3949601e16c58c318d858602a60e1de5 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Fri, 22 May 2020 21:35:53 +0200 Subject: [PATCH 1/2] cpu/stm32: implement reset to bootloader The STM32 line of microcontrollers comes with a bootloader in the ROM. It provides the option to flash the device firmware in DFU mode (USB) or via UART or SPI. To enter the bootloader we have to jump to a specific address in memory, but before reset the CPU to make sure the system is in a known state. This enables us to use the usb_board_reset module on all STM32 platforms. --- cpu/stm32/Makefile | 2 +- cpu/stm32/Makefile.dep | 4 ++ cpu/stm32/Makefile.features | 1 + cpu/stm32/bootloader/Makefile | 3 + cpu/stm32/bootloader/reset.c | 77 ++++++++++++++++++++++++ cpu/stm32/include/periph/f0/periph_cpu.h | 17 ++++++ cpu/stm32/include/periph/f1/periph_cpu.h | 12 ++++ cpu/stm32/include/periph/f2/periph_cpu.h | 7 +++ cpu/stm32/include/periph/f3/periph_cpu.h | 41 +++++++++++++ cpu/stm32/include/periph/f4/periph_cpu.h | 11 ++++ cpu/stm32/include/periph/f7/periph_cpu.h | 42 +++++++++++++ cpu/stm32/include/periph/l0/periph_cpu.h | 7 +++ cpu/stm32/include/periph/l1/periph_cpu.h | 7 +++ cpu/stm32/include/periph/l4/periph_cpu.h | 7 +++ cpu/stm32/include/periph/wb/periph_cpu.h | 42 +++++++++++++ cpu/stm32/include/periph_cpu.h | 14 +++++ 16 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 cpu/stm32/bootloader/Makefile create mode 100644 cpu/stm32/bootloader/reset.c create mode 100644 cpu/stm32/include/periph/f3/periph_cpu.h create mode 100644 cpu/stm32/include/periph/f7/periph_cpu.h create mode 100644 cpu/stm32/include/periph/wb/periph_cpu.h diff --git a/cpu/stm32/Makefile b/cpu/stm32/Makefile index 3c379f1ec9..7cfdddf258 100644 --- a/cpu/stm32/Makefile +++ b/cpu/stm32/Makefile @@ -1,5 +1,5 @@ MODULE = cpu -DIRS = $(RIOTCPU)/cortexm_common periph stmclk vectors +DIRS = $(RIOTCPU)/cortexm_common periph stmclk vectors bootloader include $(RIOTBASE)/Makefile.base diff --git a/cpu/stm32/Makefile.dep b/cpu/stm32/Makefile.dep index 737767266e..07adf57c7f 100644 --- a/cpu/stm32/Makefile.dep +++ b/cpu/stm32/Makefile.dep @@ -8,4 +8,8 @@ ifneq (,$(filter periph_usbdev,$(FEATURES_USED))) USEMODULE += xtimer endif +ifneq (,$(filter bootloader_stm32,$(FEATURES_USED))) + USEMODULE += bootloader_stm32 +endif + include $(RIOTCPU)/cortexm_common/Makefile.dep diff --git a/cpu/stm32/Makefile.features b/cpu/stm32/Makefile.features index 88853e93c3..ebf0c8aa1e 100644 --- a/cpu/stm32/Makefile.features +++ b/cpu/stm32/Makefile.features @@ -1,5 +1,6 @@ include $(RIOTCPU)/stm32/stm32_info.mk +FEATURES_PROVIDED += bootloader_stm32 FEATURES_PROVIDED += cpu_stm32$(CPU_FAM) FEATURES_PROVIDED += periph_cpuid FEATURES_PROVIDED += periph_gpio periph_gpio_irq diff --git a/cpu/stm32/bootloader/Makefile b/cpu/stm32/bootloader/Makefile new file mode 100644 index 0000000000..ee7308dcfb --- /dev/null +++ b/cpu/stm32/bootloader/Makefile @@ -0,0 +1,3 @@ +MODULE = bootloader_stm32 + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/stm32/bootloader/reset.c b/cpu/stm32/bootloader/reset.c new file mode 100644 index 0000000000..0a8e10c58f --- /dev/null +++ b/cpu/stm32/bootloader/reset.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020 Benjamin Valentin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup cpu_stm32 + * @{ + * + * @file + * @brief Trigger reset to the bootloader stored in the internal boot ROM + * memory. + * + * This will start the DFU/UART/SPI bootloader. + * See application note AN2606 for which options are available on + * your individual MCU. + * + * @author Benjamin Valentin + * @author Marian Buschsieweke + * + * @} + */ + +#include "cpu.h" +#include "periph_cpu.h" +#include "sched.h" + +/* repurpose the sched_context_switch_request variable to signal + * jump to bootloader after reset */ +#define MAGIC sched_context_switch_request +#define BOOTLOADER_MAGIC 0xB007AFFE + +/* called by reset_handler_default() before memory is initialized */ +void pre_startup(void) +{ + if (MAGIC != BOOTLOADER_MAGIC) { + return; + } + + /* clear magic */ + MAGIC = 0; + + /* enable SYSCFG clock */ +#if defined(RCC_APB2ENR_SYSCFGEN) + RCC->APB2ENR = RCC_APB2ENR_SYSCFGEN; +#elif defined(RCC_APB2ENR_SYSCFGCOMPEN) + RCC->APB2ENR = RCC_APB2ENR_SYSCFGCOMPEN +#endif + + /* remap ROM at zero */ +#if defined(SYSCFG_MEMRMP_MEM_MODE_0) + SYSCFG->MEMRMP = SYSCFG_MEMRMP_MEM_MODE_0; +#elif defined(SYSCFG_CFGR1_MEM_MODE_0) + SYSCFG->CFGR1 = SYSCFG_CFGR1_MEM_MODE_0; +#endif + + /* jump to the bootloader */ + __asm__ volatile( + "ldr r0, [%[btldr]] \n" + "mov sp, r0 \n" + "ldr r0, [%[btldr], #4] \n" + "mov pc, r0 \n" + : /* no outputs */ + : [btldr] "r" ((uintptr_t)STM32_BOOTLOADER_ADDR) + : "r0", "memory" + ); +} + +void __attribute__((weak)) usb_board_reset_in_bootloader(void) +{ + irq_disable(); + MAGIC = BOOTLOADER_MAGIC; + NVIC_SystemReset(); +} diff --git a/cpu/stm32/include/periph/f0/periph_cpu.h b/cpu/stm32/include/periph/f0/periph_cpu.h index c710966e8f..11d8f7b389 100644 --- a/cpu/stm32/include/periph/f0/periph_cpu.h +++ b/cpu/stm32/include/periph/f0/periph_cpu.h @@ -24,6 +24,23 @@ extern "C" { #endif #ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#if defined(CPU_LINE_STM32F030x4) || defined(CPU_LINE_STM32F030x6) || \ + defined(CPU_LINE_STM32F030x8) || defined(CPU_LINE_STM32F031x6) || \ + defined(CPU_LINE_STM32F051x8) +#define STM32_BOOTLOADER_ADDR (0x1FFFEC00) +#elif defined(CPU_LINE_STM32F072xB) || defined(CPU_LINE_STM32F070xB) +#define STM32_BOOTLOADER_ADDR (0x1FFFC800) +#elif defined(CPU_LINE_STM32F030xC) || defined(CPU_LINE_STM32F091xC) +#define STM32_BOOTLOADER_ADDR (0x1FFFD800) +#elif defined(CPU_LINE_STM32F042x6) +#define STM32_BOOTLOADER_ADDR (0x1FFFC400) +#endif + /** * @brief Override ADC resolution values * @{ diff --git a/cpu/stm32/include/periph/f1/periph_cpu.h b/cpu/stm32/include/periph/f1/periph_cpu.h index 8ef83e2abf..184d33834a 100644 --- a/cpu/stm32/include/periph/f1/periph_cpu.h +++ b/cpu/stm32/include/periph/f1/periph_cpu.h @@ -23,6 +23,18 @@ extern "C" { #endif +#ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#if defined(CPU_LINE_STM32F103xB) || defined(CPU_LINE_STM32F103xE) +#define STM32_BOOTLOADER_ADDR (0x1FFFF000) +#endif + +#endif /* ndef DOXYGEN */ + /** * @name Real time counter configuration * @{ diff --git a/cpu/stm32/include/periph/f2/periph_cpu.h b/cpu/stm32/include/periph/f2/periph_cpu.h index ac8cc0d065..656704f662 100644 --- a/cpu/stm32/include/periph/f2/periph_cpu.h +++ b/cpu/stm32/include/periph/f2/periph_cpu.h @@ -31,6 +31,13 @@ extern "C" { #define ADC_DEVS (2U) #ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#define STM32_BOOTLOADER_ADDR (0x1FFF0000) + /** * @brief Override the ADC resolution configuration * @{ diff --git a/cpu/stm32/include/periph/f3/periph_cpu.h b/cpu/stm32/include/periph/f3/periph_cpu.h new file mode 100644 index 0000000000..d27950e935 --- /dev/null +++ b/cpu/stm32/include/periph/f3/periph_cpu.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015-2016 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_stm32 + * @{ + * + * @file + * @brief STM32F3 CPU specific definitions for internal peripheral handling + * + * @author Hauke Petersen + */ + +#ifndef PERIPH_F3_PERIPH_CPU_H +#define PERIPH_F3_PERIPH_CPU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#define STM32_BOOTLOADER_ADDR (0x1FFFD800) + +#endif /* ndef DOXYGEN */ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_F3_PERIPH_CPU_H */ +/** @} */ diff --git a/cpu/stm32/include/periph/f4/periph_cpu.h b/cpu/stm32/include/periph/f4/periph_cpu.h index 03cb4a1494..886c9e6178 100644 --- a/cpu/stm32/include/periph/f4/periph_cpu.h +++ b/cpu/stm32/include/periph/f4/periph_cpu.h @@ -37,6 +37,17 @@ extern "C" { #endif #ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#if defined(CPU_LINE_STM32F423xx) +#define STM32_BOOTLOADER_ADDR (0x1FF00000) +#else +#define STM32_BOOTLOADER_ADDR (0x1FFF0000) +#endif + /** * @brief Override the ADC resolution configuration * @{ diff --git a/cpu/stm32/include/periph/f7/periph_cpu.h b/cpu/stm32/include/periph/f7/periph_cpu.h new file mode 100644 index 0000000000..401b6e2de0 --- /dev/null +++ b/cpu/stm32/include/periph/f7/periph_cpu.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_stm32 + * @{ + * + * @file + * @brief STM32F7 CPU specific definitions for internal peripheral handling + * + * @author Hauke Petersen + * + */ + +#ifndef PERIPH_F7_PERIPH_CPU_H +#define PERIPH_F7_PERIPH_CPU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#define STM32_BOOTLOADER_ADDR (0x1FF00000) + +#endif /* ndef DOXYGEN */ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_F7_PERIPH_CPU_H */ +/** @} */ diff --git a/cpu/stm32/include/periph/l0/periph_cpu.h b/cpu/stm32/include/periph/l0/periph_cpu.h index 058b9a2593..589e1f650a 100644 --- a/cpu/stm32/include/periph/l0/periph_cpu.h +++ b/cpu/stm32/include/periph/l0/periph_cpu.h @@ -27,6 +27,13 @@ extern "C" { #endif #ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#define STM32_BOOTLOADER_ADDR (0x1FF00000) + /** * @brief Override ADC resolution values * @{ diff --git a/cpu/stm32/include/periph/l1/periph_cpu.h b/cpu/stm32/include/periph/l1/periph_cpu.h index cced46363b..b2b1734d31 100644 --- a/cpu/stm32/include/periph/l1/periph_cpu.h +++ b/cpu/stm32/include/periph/l1/periph_cpu.h @@ -26,6 +26,13 @@ extern "C" { #endif #ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#define STM32_BOOTLOADER_ADDR (0x1FF00000) + /** * @brief Override the ADC resolution configuration * @{ diff --git a/cpu/stm32/include/periph/l4/periph_cpu.h b/cpu/stm32/include/periph/l4/periph_cpu.h index 21fdf15889..78075b11b0 100644 --- a/cpu/stm32/include/periph/l4/periph_cpu.h +++ b/cpu/stm32/include/periph/l4/periph_cpu.h @@ -42,6 +42,13 @@ extern "C" { #endif #ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#define STM32_BOOTLOADER_ADDR (0x1FFF0000) + /** * @brief Override ADC resolution values * @{ diff --git a/cpu/stm32/include/periph/wb/periph_cpu.h b/cpu/stm32/include/periph/wb/periph_cpu.h new file mode 100644 index 0000000000..0928df59e3 --- /dev/null +++ b/cpu/stm32/include/periph/wb/periph_cpu.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_stm32 + * @{ + * + * @file + * @brief STM32WB CPU specific definitions for internal peripheral handling + * + * @author Francisco Molina + * + */ + +#ifndef PERIPH_WB_PERIPH_CPU_H +#define PERIPH_WB_PERIPH_CPU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#define STM32_BOOTLOADER_ADDR (0x1FFF0000) + +#endif /* ndef DOXYGEN */ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_WB_PERIPH_CPU_H */ +/** @} */ diff --git a/cpu/stm32/include/periph_cpu.h b/cpu/stm32/include/periph_cpu.h index 00e6ca3107..5ceced1675 100644 --- a/cpu/stm32/include/periph_cpu.h +++ b/cpu/stm32/include/periph_cpu.h @@ -29,14 +29,20 @@ #include "periph/f1/periph_cpu.h" #elif defined(CPU_FAM_STM32F2) #include "periph/f2/periph_cpu.h" +#elif defined(CPU_FAM_STM32F3) +#include "periph/f3/periph_cpu.h" #elif defined(CPU_FAM_STM32F4) #include "periph/f4/periph_cpu.h" +#elif defined(CPU_FAM_STM32F7) +#include "periph/f7/periph_cpu.h" #elif defined(CPU_FAM_STM32L0) #include "periph/l0/periph_cpu.h" #elif defined(CPU_FAM_STM32L1) #include "periph/l1/periph_cpu.h" #elif defined(CPU_FAM_STM32L4) #include "periph/l4/periph_cpu.h" +#elif defined(CPU_FAM_STM32WB) +#include "periph/wb/periph_cpu.h" #endif #ifdef __cplusplus @@ -59,6 +65,14 @@ extern "C" { #error "error: LSI clock speed not defined for your target CPU" #endif +#ifdef Doxygen +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#define STM32_BOOTLOADER_ADDR +#endif + /** * @brief Length of the CPU_ID in octets * From 43585804b76074ab46d00985cdbdcf7aa0f417b6 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sat, 23 May 2020 16:04:30 +0200 Subject: [PATCH 2/2] tests/stm32_bootloader: add test for STM32 bootloader mode --- tests/stm32_bootloader/Makefile | 10 +++++++++ tests/stm32_bootloader/main.c | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/stm32_bootloader/Makefile create mode 100644 tests/stm32_bootloader/main.c diff --git a/tests/stm32_bootloader/Makefile b/tests/stm32_bootloader/Makefile new file mode 100644 index 0000000000..ea9ef31f44 --- /dev/null +++ b/tests/stm32_bootloader/Makefile @@ -0,0 +1,10 @@ +BOARD ?= nucleo-f411re +include ../Makefile.tests_common + +FEATURES_REQUIRED = bootloader_stm32 + +USEMODULE += shell +USEMODULE += shell_commands +USEMODULE += usb_board_reset + +include $(RIOTBASE)/Makefile.include diff --git a/tests/stm32_bootloader/main.c b/tests/stm32_bootloader/main.c new file mode 100644 index 0000000000..f61f9fc6b5 --- /dev/null +++ b/tests/stm32_bootloader/main.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 Benjamin Valentin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application to activate the STM32 bootloader mode. + * + * @author Benjamin Valentin + * + * @} + */ + +#include +#include + +#include "shell.h" +#include "shell_commands.h" + +int main(void) +{ + char line_buf[SHELL_DEFAULT_BUFSIZE]; + + puts("STM32 bootloader test application."); + + /* bootloader command is provided by default */ + shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +}