From 59a0936dc7d6e616cb45ca8bac6c9b1561bd1dcd Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Wed, 16 Oct 2019 14:45:35 +0200 Subject: [PATCH 01/15] Clean declaration Signed-off-by: Frederic Pillon --- cores/arduino/stm32/bootloader.h | 7 +++++++ cores/arduino/stm32/usb/cdc/usbd_cdc_if.c | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cores/arduino/stm32/bootloader.h b/cores/arduino/stm32/bootloader.h index 118bc7b860..aa9e243da4 100644 --- a/cores/arduino/stm32/bootloader.h +++ b/cores/arduino/stm32/bootloader.h @@ -1,6 +1,8 @@ #ifndef _BOOTLOADER_H_ #define _BOOTLOADER_H_ +#include + /* Ensure DTR_TOGGLING_SEQ enabled */ #if defined(BL_LEGACY_LEAF) || defined(BL_HID) #ifndef DTR_TOGGLING_SEQ @@ -12,6 +14,11 @@ extern "C" { #endif /* __cplusplus */ +#ifdef DTR_TOGGLING_SEQ +/* DTR toggling sequence management */ +void dtr_togglingHook(uint8_t *buf, uint32_t *len); +#endif + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c index c09675f95e..c97ea4d04b 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c @@ -56,8 +56,7 @@ __IO bool receivePended = true; static uint32_t transmitStart = 0; #ifdef DTR_TOGGLING_SEQ - /* DTR toggling sequence management */ - extern void dtr_togglingHook(uint8_t *buf, uint32_t *len); + uint8_t dtr_toggling = 0; #endif From 13945e3b1178c6828fe599c87a3461a8c6c8aa97 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Wed, 16 Oct 2019 14:48:40 +0200 Subject: [PATCH 02/15] Jump to system memory boot from user application Fixes #706 Signed-off-by: Frederic Pillon --- cores/arduino/stm32/backup.h | 9 ++ cores/arduino/stm32/bootloader.h | 6 + cores/arduino/stm32/usb/cdc/usbd_cdc_if.c | 3 + libraries/SrcWrapper/src/stm32/bootloader.c | 143 ++++++++++++++++++++ libraries/SrcWrapper/src/stm32/hw_config.c | 8 +- 5 files changed, 167 insertions(+), 2 deletions(-) diff --git a/cores/arduino/stm32/backup.h b/cores/arduino/stm32/backup.h index 7940c35ce7..5a99cc76c0 100644 --- a/cores/arduino/stm32/backup.h +++ b/cores/arduino/stm32/backup.h @@ -59,6 +59,15 @@ extern "C" { #endif /* HID_MAGIC_NUMBER_BKP_VALUE */ #endif /* BL_HID */ +#if !defined(SYSBL_MAGIC_NUMBER_BKP_INDEX) && defined(ENABLE_BACKUP_SUPPORT) +#define SYSBL_MAGIC_NUMBER_BKP_INDEX LL_RTC_BKP_DR2 +#else +#define SYSBL_MAGIC_NUMBER_BKP_INDEX 0 +#endif /* SYSBL_MAGIC_NUMBER_BKP_INDEX */ +#ifndef SYSBL_MAGIC_NUMBER_BKP_VALUE +#define SYSBL_MAGIC_NUMBER_BKP_VALUE 0x515B +#endif /* SYSBL_MAGIC_NUMBER_BKP_VALUE */ + /* Exported functions ------------------------------------------------------- */ static inline void resetBackupDomain(void) { diff --git a/cores/arduino/stm32/bootloader.h b/cores/arduino/stm32/bootloader.h index aa9e243da4..01ec2d1253 100644 --- a/cores/arduino/stm32/bootloader.h +++ b/cores/arduino/stm32/bootloader.h @@ -14,6 +14,12 @@ extern "C" { #endif /* __cplusplus */ +/* Request to jump to system memory boot */ +void jumpToBootloaderRequested(void); + +/* Jump to system memory boot from user application */ +void jumpToBootloader(void); + #ifdef DTR_TOGGLING_SEQ /* DTR toggling sequence management */ void dtr_togglingHook(uint8_t *buf, uint32_t *len); diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c index c97ea4d04b..9d52899193 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c @@ -169,6 +169,9 @@ static int8_t USBD_CDC_Control(uint8_t cmd, uint8_t *pbuf, uint16_t length) linecoding.format = pbuf[4]; linecoding.paritytype = pbuf[5]; linecoding.datatype = pbuf[6]; + if (linecoding.bitrate == 1200) { + jumpToBootloaderRequested(); + } break; case CDC_GET_LINE_CODING: diff --git a/libraries/SrcWrapper/src/stm32/bootloader.c b/libraries/SrcWrapper/src/stm32/bootloader.c index d7d86e968e..b95da6e7df 100644 --- a/libraries/SrcWrapper/src/stm32/bootloader.c +++ b/libraries/SrcWrapper/src/stm32/bootloader.c @@ -2,7 +2,147 @@ #include "stm32_def.h" #include "backup.h" +#include "stm32yyxx_ll_system.h" +#include "usbd_if.h" +/* + * STM32 built-in bootloader in system memory support + */ +/* Private definitions to manage system memory address */ +#define SYSMEM_ADDR_COMMON 0xFFF + +typedef struct { + uint32_t devID; + uint32_t sysMemAddr; +} devSysMemAddr_str; + +devSysMemAddr_str devSysMemAddr[] = { +#ifdef STM32F0xx + {0x440, 0x1FFFEC00}, + {0x444, 0x1FFFEC00}, + {0x442, 0x1FFFD800}, + {0x445, 0x1FFFC400}, + {0x448, 0x1FFFC800}, +#elif STM32F1xx + {0x412, 0x1FFFF000}, + {0x410, 0x1FFFF000}, + {0x414, 0x1FFFF000}, + {0x420, 0x1FFFF000}, + {0x428, 0x1FFFF000}, + {0x418, 0x1FFFB000}, + {0x430, 0x1FFFE000}, +#elif STM32F2xx + {0x411, 0x1FFF0000}, +#elif STM32F3xx + {SYSMEM_ADDR_COMMON, 0x1FFFD800}, +#elif STM32F4xx + {SYSMEM_ADDR_COMMON, 0x1FFF0000}, +#elif STM32F7xx + {SYSMEM_ADDR_COMMON, 0x1FF00000}, +#elif STM32G0xx + {SYSMEM_ADDR_COMMON, 0x1FFF0000}, +#elif STM32G4xx + {SYSMEM_ADDR_COMMON, 0x1FFF0000}, +#elif STM32H7xx + {0x450, 0x1FF00000}, +#elif STM32L0xx + {SYSMEM_ADDR_COMMON, 0x1FF00000}, +#elif STM32L1xx + {SYSMEM_ADDR_COMMON, 0x1FF00000}, +#elif STM32L4xx + {SYSMEM_ADDR_COMMON, 0x1FFF0000}, +#elif STM32WBxx + {SYSMEM_ADDR_COMMON, 0x1FFF0000}, +#else +#warning "No system memory address for this serie!" +#endif + {0x0000, 0x00000000} +}; + +uint32_t getSysMemAddr(void) +{ + uint32_t sysMemAddr = 0; + if (devSysMemAddr[0].devID == SYSMEM_ADDR_COMMON) { + sysMemAddr = devSysMemAddr[0].sysMemAddr; + } else { + uint32_t devId = LL_DBGMCU_GetDeviceID(); + for (uint32_t id = 0; devSysMemAddr[id].devID != 0; id++) { + if (devSysMemAddr[id].devID == devId) { + sysMemAddr = devSysMemAddr[id].sysMemAddr; + break; + } + } + } + return sysMemAddr; +} + +/* Request to jump to system memory boot */ +WEAK void jumpToBootloaderRequested(void) +{ + enableBackupDomain(); + setBackupRegister(SYSBL_MAGIC_NUMBER_BKP_INDEX, SYSBL_MAGIC_NUMBER_BKP_VALUE); + NVIC_SystemReset(); +} + +/* Jump to system memory boot from user application */ +WEAK void jumpToBootloader(void) +{ + enableBackupDomain(); + if (getBackupRegister(SYSBL_MAGIC_NUMBER_BKP_INDEX) == SYSBL_MAGIC_NUMBER_BKP_VALUE) { + setBackupRegister(SYSBL_MAGIC_NUMBER_BKP_INDEX, 0); + +#ifdef USBCON + USBD_reenumerate(); +#endif + void (*sysMemBootJump)(void); + + /** + * Get system memory address + * + * Available in AN2606 document: + * Table xxx Bootloader device-dependent parameters + */ + volatile uint32_t sysMem_addr = getSysMemAddr(); + /* + * If the system address is not not referenced in 'devSysMemAddr' array, + * does not do anything + */ + if (sysMem_addr != 0) { +#ifdef __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH + /* Remap system Flash memory at address 0x00000000 */ + __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); +#endif + + /** + * Set jump memory location for system memory + * Use address with 4 bytes offset which specifies jump location + * where program starts + */ + sysMemBootJump = (void (*)(void))(*((uint32_t *)(sysMem_addr + 4))); + + /** + * Set main stack pointer. + * This step must be done last otherwise local variables in this function + * don't have proper value since stack pointer is located on different position + * + * Set direct address location which specifies stack pointer in SRAM location + */ + __set_MSP(*(uint32_t *)sysMem_addr); + + /** + * Jump to set location + * This will start system memory execution + */ + sysMemBootJump(); + + while (1); + } + } +} + +/* + * Legacy maple bootloader support + */ #ifdef BL_LEGACY_LEAF void dtr_togglingHook(uint8_t *buf, uint32_t *len) { @@ -17,6 +157,9 @@ void dtr_togglingHook(uint8_t *buf, uint32_t *len) } #endif /* BL_LEGACY_LEAF */ +/* + * HID bootloader support + */ #ifdef BL_HID void dtr_togglingHook(uint8_t *buf, uint32_t *len) { diff --git a/libraries/SrcWrapper/src/stm32/hw_config.c b/libraries/SrcWrapper/src/stm32/hw_config.c index 3434d6da96..aaccab5510 100644 --- a/libraries/SrcWrapper/src/stm32/hw_config.c +++ b/libraries/SrcWrapper/src/stm32/hw_config.c @@ -35,10 +35,11 @@ * ****************************************************************************** */ -#include "stm32_def.h" +#include "bootloader.h" +#include "dwt.h" #include "hw_config.h" #include "usbd_if.h" -#include "dwt.h" +#include "stm32_def.h" #ifdef __cplusplus extern "C" { @@ -59,6 +60,9 @@ void hw_config_init(void) /* Initialize the HAL */ HAL_Init(); + /* Check if a jump to system memory boot requested */ + jumpToBootloader(); + /* Configure the system clock */ SystemClock_Config(); From 6c081f4fb30b47027dcc3840b6a80827933b4aad Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 5 Nov 2019 08:24:03 +0100 Subject: [PATCH 03/15] Add upload.use_1200bps_touch=true The upload.use_1200bps_touch key tells the IDE to open the user-selected serial port at 1200 baud, and then close it, before attempting an upload. This allow to jump in BL mode. Signed-off-by: Frederic Pillon --- boards.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/boards.txt b/boards.txt index 65074d3a9f..b82635c93a 100644 --- a/boards.txt +++ b/boards.txt @@ -181,6 +181,7 @@ Nucleo_144.menu.upload_method.serialMethod.upload.tool=stm32CubeProg Nucleo_144.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) Nucleo_144.menu.upload_method.dfuMethod.upload.protocol=2 Nucleo_144.menu.upload_method.dfuMethod.upload.options=-g +Nucleo_144.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true Nucleo_144.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg ################################################################################ @@ -466,6 +467,7 @@ Nucleo_64.menu.upload_method.serialMethod.upload.tool=stm32CubeProg Nucleo_64.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) Nucleo_64.menu.upload_method.dfuMethod.upload.protocol=2 Nucleo_64.menu.upload_method.dfuMethod.upload.options=-g +Nucleo_64.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true Nucleo_64.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg ################################################################################ @@ -571,6 +573,7 @@ Nucleo_32.menu.upload_method.serialMethod.upload.tool=stm32CubeProg Nucleo_32.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) Nucleo_32.menu.upload_method.dfuMethod.upload.protocol=2 Nucleo_32.menu.upload_method.dfuMethod.upload.options=-g +Nucleo_32.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true Nucleo_32.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg ################################################################################ @@ -727,6 +730,7 @@ Disco.menu.upload_method.serialMethod.upload.tool=stm32CubeProg Disco.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) Disco.menu.upload_method.dfuMethod.upload.protocol=2 Disco.menu.upload_method.dfuMethod.upload.options=-g +Disco.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true Disco.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg ################################################################################ @@ -759,6 +763,7 @@ Eval.menu.upload_method.swdMethod.upload.tool=stm32CubeProg Eval.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) Eval.menu.upload_method.dfuMethod.upload.protocol=2 Eval.menu.upload_method.dfuMethod.upload.options=-g +Eval.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true Eval.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg ################################################################################ @@ -847,6 +852,7 @@ GenF0.menu.upload_method.serialMethod.upload.tool=stm32CubeProg GenF0.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) GenF0.menu.upload_method.dfuMethod.upload.protocol=2 GenF0.menu.upload_method.dfuMethod.upload.options=-g +GenF0.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true GenF0.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg ################################################################################ @@ -1152,6 +1158,7 @@ GenF1.menu.upload_method.serialMethod.upload.tool=stm32CubeProg GenF1.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) GenF1.menu.upload_method.dfuMethod.upload.protocol=2 GenF1.menu.upload_method.dfuMethod.upload.options=-g +GenF1.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true GenF1.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg GenF1.menu.upload_method.bmpMethod=BMP (Black Magic Probe) @@ -1215,6 +1222,7 @@ GenF3.menu.upload_method.serialMethod.upload.tool=stm32CubeProg GenF3.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) GenF3.menu.upload_method.dfuMethod.upload.protocol=2 GenF3.menu.upload_method.dfuMethod.upload.options=-g +GenF3.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true GenF3.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg GenF3.menu.upload_method.bmpMethod=BMP (Black Magic Probe) @@ -1623,6 +1631,7 @@ GenF4.menu.upload_method.serialMethod.upload.tool=stm32CubeProg GenF4.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) GenF4.menu.upload_method.dfuMethod.upload.protocol=2 GenF4.menu.upload_method.dfuMethod.upload.options=-g +GenF4.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true GenF4.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg GenF4.menu.upload_method.bmpMethod=BMP (Black Magic Probe) @@ -1712,6 +1721,7 @@ GenL0.menu.upload_method.serialMethod.upload.tool=stm32CubeProg GenL0.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) GenL0.menu.upload_method.dfuMethod.upload.protocol=2 GenL0.menu.upload_method.dfuMethod.upload.options=-g +GenL0.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true GenL0.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg GenL0.menu.upload_method.bmpMethod=BMP (Black Magic Probe) @@ -1752,6 +1762,7 @@ ESC_board.menu.upload_method.serialMethod.upload.tool=stm32CubeProg ESC_board.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) ESC_board.menu.upload_method.dfuMethod.upload.protocol=2 ESC_board.menu.upload_method.dfuMethod.upload.options=-g +ESC_board.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true ESC_board.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg ################################################################################ @@ -1834,6 +1845,7 @@ LoRa.menu.upload_method.serialMethod.upload.tool=stm32CubeProg LoRa.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) LoRa.menu.upload_method.dfuMethod.upload.protocol=2 LoRa.menu.upload_method.dfuMethod.upload.options=-g +LoRa.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true LoRa.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg ############################### @@ -2010,6 +2022,7 @@ LoRa.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg 3dprinter.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) 3dprinter.menu.upload_method.dfuMethod.upload.protocol=2 3dprinter.menu.upload_method.dfuMethod.upload.options=-g +3dprinter.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true 3dprinter.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg @@ -2069,6 +2082,7 @@ Genericflight.menu.upload_method.serialMethod.upload.tool=stm32CubeProg Genericflight.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) Genericflight.menu.upload_method.dfuMethod.upload.protocol=2 Genericflight.menu.upload_method.dfuMethod.upload.options=-g +Genericflight.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true Genericflight.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg Genericflight.menu.upload_method.bmpMethod=BMP (Black Magic Probe) @@ -2199,6 +2213,7 @@ Midatronics.menu.upload_method.serialMethod.upload.tool=stm32CubeProg Midatronics.menu.upload_method.dfuMethod=STM32CubeProgrammer (DFU) Midatronics.menu.upload_method.dfuMethod.upload.protocol=2 Midatronics.menu.upload_method.dfuMethod.upload.options=-g +Midatronics.menu.upload_method.dfuMethod.upload.use_1200bps_touch=true Midatronics.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg ################################################################################ From b32a37aa4ffd9a171696b6bbe6fffcecf89ada9a Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 4 Mar 2020 17:40:38 +0100 Subject: [PATCH 04/15] Do not use the RTC to track a bootloader request Instead, use a .noinit variable, which survives across reboots. Note: This file uses the bool type, so needs to include stdbool.h. It seems that for the F4, this was indirectly included elsewhere, but for e.g. F0, this did not seem to be the case, causing the build to fail. --- cores/arduino/stm32/backup.h | 9 --------- libraries/SrcWrapper/src/stm32/bootloader.c | 21 ++++++++++++++++----- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/cores/arduino/stm32/backup.h b/cores/arduino/stm32/backup.h index 5a99cc76c0..7940c35ce7 100644 --- a/cores/arduino/stm32/backup.h +++ b/cores/arduino/stm32/backup.h @@ -59,15 +59,6 @@ extern "C" { #endif /* HID_MAGIC_NUMBER_BKP_VALUE */ #endif /* BL_HID */ -#if !defined(SYSBL_MAGIC_NUMBER_BKP_INDEX) && defined(ENABLE_BACKUP_SUPPORT) -#define SYSBL_MAGIC_NUMBER_BKP_INDEX LL_RTC_BKP_DR2 -#else -#define SYSBL_MAGIC_NUMBER_BKP_INDEX 0 -#endif /* SYSBL_MAGIC_NUMBER_BKP_INDEX */ -#ifndef SYSBL_MAGIC_NUMBER_BKP_VALUE -#define SYSBL_MAGIC_NUMBER_BKP_VALUE 0x515B -#endif /* SYSBL_MAGIC_NUMBER_BKP_VALUE */ - /* Exported functions ------------------------------------------------------- */ static inline void resetBackupDomain(void) { diff --git a/libraries/SrcWrapper/src/stm32/bootloader.c b/libraries/SrcWrapper/src/stm32/bootloader.c index b95da6e7df..ef324eafd8 100644 --- a/libraries/SrcWrapper/src/stm32/bootloader.c +++ b/libraries/SrcWrapper/src/stm32/bootloader.c @@ -1,3 +1,5 @@ +#include + #include "bootloader.h" #include "stm32_def.h" @@ -11,6 +13,8 @@ /* Private definitions to manage system memory address */ #define SYSMEM_ADDR_COMMON 0xFFF +static bool BootIntoBootloaderAfterReset __attribute__((__section__(".noinit"))); + typedef struct { uint32_t devID; uint32_t sysMemAddr; @@ -79,18 +83,25 @@ uint32_t getSysMemAddr(void) /* Request to jump to system memory boot */ WEAK void jumpToBootloaderRequested(void) { - enableBackupDomain(); - setBackupRegister(SYSBL_MAGIC_NUMBER_BKP_INDEX, SYSBL_MAGIC_NUMBER_BKP_VALUE); + BootIntoBootloaderAfterReset = true; NVIC_SystemReset(); } /* Jump to system memory boot from user application */ WEAK void jumpToBootloader(void) { - enableBackupDomain(); - if (getBackupRegister(SYSBL_MAGIC_NUMBER_BKP_INDEX) == SYSBL_MAGIC_NUMBER_BKP_VALUE) { - setBackupRegister(SYSBL_MAGIC_NUMBER_BKP_INDEX, 0); + // Boot into bootloader if BootIntoBootloaderAfterReset is set. + // Note that BootIntoBootloaderAfterReset is a noinit variable, so it + // s not automatically initialized on startup (so it can keep its + // value across resets). At initial poweron, its value can be + // *anything*, so only consider its value after a software reset. In + // all cases, clear its value (this both takes care of giving it an + // initial value after power-up, and prevents booting into the + // bootloader more than once for a single request). + bool doBootloader = __HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST) && BootIntoBootloaderAfterReset; + BootIntoBootloaderAfterReset = false; + if (doBootloader) { #ifdef USBCON USBD_reenumerate(); #endif From c40cfdd767fccde689cdcb2cd9e7396eebce5ec1 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 11 Mar 2020 15:53:51 +0100 Subject: [PATCH 05/15] Override Reset_Handler to jump to bootloader --- cores/arduino/stm32/startup_stm32yyxx.S | 5 +++++ libraries/SrcWrapper/src/stm32/bootloader.c | 14 +++++++++++++- libraries/SrcWrapper/src/stm32/hw_config.c | 3 --- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/cores/arduino/stm32/startup_stm32yyxx.S b/cores/arduino/stm32/startup_stm32yyxx.S index 8572083cdd..088f6ccabc 100644 --- a/cores/arduino/stm32/startup_stm32yyxx.S +++ b/cores/arduino/stm32/startup_stm32yyxx.S @@ -3,3 +3,8 @@ #if defined(CMSIS_STARTUP_FILE) #include CMSIS_STARTUP_FILE #endif + +# Expose Reset_Handler under a different name, to allow overriding it +# with a strong symbol and then calling the original. +.global Original_Reset_Handler +.thumb_set Original_Reset_Handler,Reset_Handler diff --git a/libraries/SrcWrapper/src/stm32/bootloader.c b/libraries/SrcWrapper/src/stm32/bootloader.c index ef324eafd8..9b6d52df64 100644 --- a/libraries/SrcWrapper/src/stm32/bootloader.c +++ b/libraries/SrcWrapper/src/stm32/bootloader.c @@ -13,7 +13,7 @@ /* Private definitions to manage system memory address */ #define SYSMEM_ADDR_COMMON 0xFFF -static bool BootIntoBootloaderAfterReset __attribute__((__section__(".noinit"))); +static bool BootIntoBootloaderAfterReset; typedef struct { uint32_t devID; @@ -87,6 +87,18 @@ WEAK void jumpToBootloaderRequested(void) NVIC_SystemReset(); } +// This overrides the Reset_Handler that is run on reset before +// *anything* else (including memory initialization). Only the stack +// pointer is set up by this time. +void Reset_Handler() +{ + // Jump to the bootloader if needed. + jumpToBootloader(); + + // Continue with regular startup by calling the original reset handler + Original_Reset_Handler(); +} + /* Jump to system memory boot from user application */ WEAK void jumpToBootloader(void) { diff --git a/libraries/SrcWrapper/src/stm32/hw_config.c b/libraries/SrcWrapper/src/stm32/hw_config.c index aaccab5510..20013b2aa5 100644 --- a/libraries/SrcWrapper/src/stm32/hw_config.c +++ b/libraries/SrcWrapper/src/stm32/hw_config.c @@ -60,9 +60,6 @@ void hw_config_init(void) /* Initialize the HAL */ HAL_Init(); - /* Check if a jump to system memory boot requested */ - jumpToBootloader(); - /* Configure the system clock */ SystemClock_Config(); From c0ef636001dd604e87d7bbca30a0536dbd649477 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 18 Mar 2020 20:12:19 +0100 Subject: [PATCH 06/15] Use handcoded delay in USBD_reenumerate This now runs in early startup, so the normal delay will not work (systick is not running yet). Note: Seems that on F0, inline assembler is compiled using the classic rather than unified syntax (which *is* used on F4 it seems). This explicitly selects the unified syntax in the inline assembly block, to fix building for F0. TODO: There is a variant which also overrides the enumeration. --- cores/arduino/stm32/usb/usbd_if.c | 54 +++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/cores/arduino/stm32/usb/usbd_if.c b/cores/arduino/stm32/usb/usbd_if.c index e579140f72..6651273530 100644 --- a/cores/arduino/stm32/usb/usbd_if.c +++ b/cores/arduino/stm32/usb/usbd_if.c @@ -115,6 +115,56 @@ #define USBD_DP_TRICK #endif +/** + * @brief USBD_early_startup_delay + * @param us - number of us to delay + * @retval None + * + * This is a minimal delay which is usable in very early startup, when + * nothing has been initialized yet (no clocks, no memory, no systick + * timer). It works by counting CPU cycles, and assumes the system is + * still running from the HSI. + * + * If the systick timer is already enabled, this assumes everything is + * intialized and instead used the normal delayMicroseconds function. + * + * Max delay depends on HSI, but is around 268 sec with 16Mhz HSI. + */ +void USBD_early_startup_delay_us(uint32_t us) +{ + if (SysTick->CTRL & SysTick_CTRL_ENABLE_Msk) { + delayMicroseconds(us); + return; + } + +#if !HSI_VALUE +#error "Missing HSI_VALUE" +#endif + +#if HSI_VALUE % 4000000 != 0 +#warning "HSI not multiple of 4MHz, early startup delay will be inaccurate!" +#endif + + // To simplify this calculation, this assumes the HSI runs at a + // multiple of 4Mhz (1Mhz to scale to us, times 4 to account for 4 + // cycles per loop). + const uint32_t loops_per_us = (HSI_VALUE / 1000000) / 4; + const uint32_t loop_count = us * loops_per_us; + + // Assembly loop, designed to run at exactly 4 cycles per loop. + asm volatile( + // Use the unified ARM/Thumb syntax, which seems to be more + // universally used and corresponds to what avr-objdump outputs + // See https://sourceware.org/binutils/docs/as/ARM_002dInstruction_002dSet.html + ".syntax unified\n\t" + "1:\n\t" + "nop /* 1 cycle */\n\t" + "subs %[loop], %[loop], #1 /* 1 cycle */\n\t" + "bne 1b /* 2 if taken, 1 otherwise */\n\t" + : : [loop] "l"(loop_count) + ); +} + /** * @brief Force to re-enumerate USB. * @@ -134,7 +184,7 @@ WEAK void USBD_reenumerate(void) digitalWriteFast(USBD_PULLUP_CONTROL_PINNAME, USBD_DETACH_LEVEL); /* Wait */ - delay(USBD_ENUM_DELAY); + USBD_early_startup_delay_us(USBD_ENUM_DELAY * 1000); /* Attach */ #if defined(USBD_DP_TRICK) @@ -145,7 +195,7 @@ WEAK void USBD_reenumerate(void) #endif /* defined(USBD_PULLUP_CONTROL_FLOATING) */ #elif defined(USBD_HAVE_INTERNAL_PULLUPS) USB_DevDisconnect(USBD_USB_INSTANCE); - delay(USBD_ENUM_DELAY); + USBD_early_startup_delay_us(USBD_ENUM_DELAY * 1000); USB_DevConnect(USBD_USB_INSTANCE); #else #warning "No USB attach/detach method, USB might not be reliable through system resets" From 93de06d47ccdddf83020e9577236fd1130cbc1a2 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 18 Mar 2020 20:14:03 +0100 Subject: [PATCH 07/15] Clear reset flags before starting bootloader Since the bootloader does not touch these flags, but can start the sketch if instructed by the programmer (without a reset), clearing is needed to prevent a start from the bootloader looking like a software-reset. Otherwise, the startup code would be looking at the BootIntoBootloaderAfterReset variable to decide whether to jump to the bootloader. This variable should have been cleared before jumping to the bootloader the last time, but the bootloader might have overwritten it (or a sketch was uploaded with a different address for that variable). Additionally, clearing the reset flags allows a sketch to see that the they are started through the bootloader, when all reset flags are cleared. --- libraries/SrcWrapper/src/stm32/bootloader.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/SrcWrapper/src/stm32/bootloader.c b/libraries/SrcWrapper/src/stm32/bootloader.c index 9b6d52df64..38ac5c4323 100644 --- a/libraries/SrcWrapper/src/stm32/bootloader.c +++ b/libraries/SrcWrapper/src/stm32/bootloader.c @@ -119,6 +119,8 @@ WEAK void jumpToBootloader(void) #endif void (*sysMemBootJump)(void); + __HAL_RCC_CLEAR_RESET_FLAGS(); + /** * Get system memory address * From c6edf2bdd04cfde0ea00c3da7f98217ff81ed133 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 18 Mar 2020 22:12:27 +0100 Subject: [PATCH 08/15] Simplify system flash address detection On most CPUs, detecting the system flash address is not needed, since they can remap the system flash onto adress 0x0 and the bootloader reset vector can be read from there. This approach also more closely mimics a bootloader start using the BOOTx pins. For CPUs that cannot remap flash, this hardcodes the address of system flash and jumps there instead. For H7 and F7, this is also how it works when using the BOOT pins. For F1, remapping can be done using the BOOT pins, but not from software, resulting in a difference with a BOOT-activated bootloader. This puts the code that figures out where the bootloader lives back in a separate function. This makes the code easier to read, and makes it easier to jump to custom bootloaders (e.g. in normal flash instead of in system flash). TODO: Check value for H7, AN2606 and reference manual disagree --- cores/arduino/stm32/bootloader.h | 2 +- libraries/SrcWrapper/src/stm32/bootloader.c | 169 ++++++++------------ 2 files changed, 64 insertions(+), 107 deletions(-) diff --git a/cores/arduino/stm32/bootloader.h b/cores/arduino/stm32/bootloader.h index 01ec2d1253..16abbecec0 100644 --- a/cores/arduino/stm32/bootloader.h +++ b/cores/arduino/stm32/bootloader.h @@ -18,7 +18,7 @@ extern "C" { void jumpToBootloaderRequested(void); /* Jump to system memory boot from user application */ -void jumpToBootloader(void); +void jumpToBootloaderIfRequested(void); #ifdef DTR_TOGGLING_SEQ /* DTR toggling sequence management */ diff --git a/libraries/SrcWrapper/src/stm32/bootloader.c b/libraries/SrcWrapper/src/stm32/bootloader.c index 38ac5c4323..e64275782c 100644 --- a/libraries/SrcWrapper/src/stm32/bootloader.c +++ b/libraries/SrcWrapper/src/stm32/bootloader.c @@ -10,76 +10,9 @@ /* * STM32 built-in bootloader in system memory support */ -/* Private definitions to manage system memory address */ -#define SYSMEM_ADDR_COMMON 0xFFF static bool BootIntoBootloaderAfterReset; -typedef struct { - uint32_t devID; - uint32_t sysMemAddr; -} devSysMemAddr_str; - -devSysMemAddr_str devSysMemAddr[] = { -#ifdef STM32F0xx - {0x440, 0x1FFFEC00}, - {0x444, 0x1FFFEC00}, - {0x442, 0x1FFFD800}, - {0x445, 0x1FFFC400}, - {0x448, 0x1FFFC800}, -#elif STM32F1xx - {0x412, 0x1FFFF000}, - {0x410, 0x1FFFF000}, - {0x414, 0x1FFFF000}, - {0x420, 0x1FFFF000}, - {0x428, 0x1FFFF000}, - {0x418, 0x1FFFB000}, - {0x430, 0x1FFFE000}, -#elif STM32F2xx - {0x411, 0x1FFF0000}, -#elif STM32F3xx - {SYSMEM_ADDR_COMMON, 0x1FFFD800}, -#elif STM32F4xx - {SYSMEM_ADDR_COMMON, 0x1FFF0000}, -#elif STM32F7xx - {SYSMEM_ADDR_COMMON, 0x1FF00000}, -#elif STM32G0xx - {SYSMEM_ADDR_COMMON, 0x1FFF0000}, -#elif STM32G4xx - {SYSMEM_ADDR_COMMON, 0x1FFF0000}, -#elif STM32H7xx - {0x450, 0x1FF00000}, -#elif STM32L0xx - {SYSMEM_ADDR_COMMON, 0x1FF00000}, -#elif STM32L1xx - {SYSMEM_ADDR_COMMON, 0x1FF00000}, -#elif STM32L4xx - {SYSMEM_ADDR_COMMON, 0x1FFF0000}, -#elif STM32WBxx - {SYSMEM_ADDR_COMMON, 0x1FFF0000}, -#else -#warning "No system memory address for this serie!" -#endif - {0x0000, 0x00000000} -}; - -uint32_t getSysMemAddr(void) -{ - uint32_t sysMemAddr = 0; - if (devSysMemAddr[0].devID == SYSMEM_ADDR_COMMON) { - sysMemAddr = devSysMemAddr[0].sysMemAddr; - } else { - uint32_t devId = LL_DBGMCU_GetDeviceID(); - for (uint32_t id = 0; devSysMemAddr[id].devID != 0; id++) { - if (devSysMemAddr[id].devID == devId) { - sysMemAddr = devSysMemAddr[id].sysMemAddr; - break; - } - } - } - return sysMemAddr; -} - /* Request to jump to system memory boot */ WEAK void jumpToBootloaderRequested(void) { @@ -93,14 +26,54 @@ WEAK void jumpToBootloaderRequested(void) void Reset_Handler() { // Jump to the bootloader if needed. - jumpToBootloader(); + jumpToBootloaderIfRequested(); // Continue with regular startup by calling the original reset handler Original_Reset_Handler(); } +/* Figure out where the bootloader lives, remapping memory if needed, + * and return its address. The returned address should point to the + * bootloader's interrupt vector table, so to a SP to load followed by + * an address to jump to. + */ +WEAK uint32_t bootloaderAddress() +{ +#ifdef __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH + /* Remap system Flash memory at address 0x00000000 */ + __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); + // Make the variable volatile to prevent the compiler from seeing a + // null-pointer dereference (which is undefined in C) and generating + // an UDF (undefined) instruction instead of just loading address 0. + return 0; +#elif defined(STM32F1xx) && (defined (STM32F101xG) || defined (STM32F103xG)) + // From AN2606, table 136 "Bootloader device-dependent parameters" + // STM32F10xxx XL-density, aka 768K-1M flash, aka F and G flash size codes + return 0x1FFFE000; +#elif defined(STM32F1xx) && defined (STM32F105xC) || defined (STM32F107xC) + // STM32F105xx/107xx from AN2606, table 136 "Bootloader device-dependent parameters" + return 0x1FFFB000; +#elif defined (STM32F100xB) || defined (STM32F100xE) || defined (STM32F101x6) || \ + defined (STM32F101xB) || defined (STM32F101xE) || defined (STM32F102x6) || \ + defined (STM32F102xB) || defined (STM32F103x6) || defined (STM32F103xB) || \ + defined (STM32F103xE) + // STM32F10xxx from AN2606, table 136 "Bootloader device-dependent parameters" + // This does not check for STM32F1xx, to prevent catching + // STM32F105xx/STM32F107xx or XL-density chips that are introduced later. + // Defines from system/Drivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f1xx.h + return 0x1FFFF000; +#elif defined(STM32F7xx) || defined(STM32H7xx) + // From AN2606, table 136 "Bootloader device-dependent parameters" + // TODO: Reference manual for has a different value... + return 0x1FF00000; +#else +#error "System flash address unknown for this CPU" +#endif +} + + /* Jump to system memory boot from user application */ -WEAK void jumpToBootloader(void) +WEAK void jumpToBootloaderIfRequested(void) { // Boot into bootloader if BootIntoBootloaderAfterReset is set. // Note that BootIntoBootloaderAfterReset is a noinit variable, so it @@ -114,54 +87,38 @@ WEAK void jumpToBootloader(void) BootIntoBootloaderAfterReset = false; if (doBootloader) { + __HAL_RCC_CLEAR_RESET_FLAGS(); + #ifdef USBCON USBD_reenumerate(); #endif void (*sysMemBootJump)(void); - __HAL_RCC_CLEAR_RESET_FLAGS(); + uint32_t sys = bootloaderAddress(); + + /** + * Set jump memory location for system memory + * Use address with 4 bytes offset which specifies jump location + * where program starts + */ + sysMemBootJump = (void (*)(void))(*((uint32_t *)(sysMem_addr + 4))); /** - * Get system memory address + * Set main stack pointer. + * This step must be done last otherwise local variables in this function + * don't have proper value since stack pointer is located on different position * - * Available in AN2606 document: - * Table xxx Bootloader device-dependent parameters + * Set direct address location which specifies stack pointer in SRAM location */ - volatile uint32_t sysMem_addr = getSysMemAddr(); - /* - * If the system address is not not referenced in 'devSysMemAddr' array, - * does not do anything + __set_MSP(*(uint32_t *)sysMem_addr); + + /** + * Jump to set location + * This will start system memory execution */ - if (sysMem_addr != 0) { -#ifdef __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH - /* Remap system Flash memory at address 0x00000000 */ - __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); -#endif + sysMemBootJump(); - /** - * Set jump memory location for system memory - * Use address with 4 bytes offset which specifies jump location - * where program starts - */ - sysMemBootJump = (void (*)(void))(*((uint32_t *)(sysMem_addr + 4))); - - /** - * Set main stack pointer. - * This step must be done last otherwise local variables in this function - * don't have proper value since stack pointer is located on different position - * - * Set direct address location which specifies stack pointer in SRAM location - */ - __set_MSP(*(uint32_t *)sysMem_addr); - - /** - * Jump to set location - * This will start system memory execution - */ - sysMemBootJump(); - - while (1); - } + while (1); } } From 0871fee8bbad07ec3e9b2e785ee0fdfde7c50977 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 19 Mar 2020 12:52:31 +0100 Subject: [PATCH 09/15] Forward declare Original_Reset_handler --- libraries/SrcWrapper/src/stm32/bootloader.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/SrcWrapper/src/stm32/bootloader.c b/libraries/SrcWrapper/src/stm32/bootloader.c index e64275782c..92137b408e 100644 --- a/libraries/SrcWrapper/src/stm32/bootloader.c +++ b/libraries/SrcWrapper/src/stm32/bootloader.c @@ -20,6 +20,9 @@ WEAK void jumpToBootloaderRequested(void) NVIC_SystemReset(); } +// Defined in startup assembly code +void Original_Reset_Handler(); + // This overrides the Reset_Handler that is run on reset before // *anything* else (including memory initialization). Only the stack // pointer is set up by this time. From 617981000c2ea1298d95411a4510074d80d3673d Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 19 Mar 2020 12:52:44 +0100 Subject: [PATCH 10/15] Jump to bootloader from asm block This ensures that the SP is not modified after loading it and ensures a jump instruction is used. The assembly code was based on micropython and another STM32 core: https://github.com/micropython/micropython/blob/f6375ac3ebac28656a0a757952d32c265b1ba7aa/ports/stm32/powerctrl.c#L71-L78 https://github.com/GrumpyOldPizza/arduino-STM32L4/blob/bacc184288a4644b2ee6a97672334983f3e788ab/system/STM32L4xx/Source/boot_stm32l4xx.c#L159-L166 --- libraries/SrcWrapper/src/stm32/bootloader.c | 39 ++++++++------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/libraries/SrcWrapper/src/stm32/bootloader.c b/libraries/SrcWrapper/src/stm32/bootloader.c index 92137b408e..8e341a517a 100644 --- a/libraries/SrcWrapper/src/stm32/bootloader.c +++ b/libraries/SrcWrapper/src/stm32/bootloader.c @@ -95,33 +95,24 @@ WEAK void jumpToBootloaderIfRequested(void) #ifdef USBCON USBD_reenumerate(); #endif - void (*sysMemBootJump)(void); uint32_t sys = bootloaderAddress(); - /** - * Set jump memory location for system memory - * Use address with 4 bytes offset which specifies jump location - * where program starts - */ - sysMemBootJump = (void (*)(void))(*((uint32_t *)(sysMem_addr + 4))); - - /** - * Set main stack pointer. - * This step must be done last otherwise local variables in this function - * don't have proper value since stack pointer is located on different position - * - * Set direct address location which specifies stack pointer in SRAM location - */ - __set_MSP(*(uint32_t *)sysMem_addr); - - /** - * Jump to set location - * This will start system memory execution - */ - sysMemBootJump(); - - while (1); + // This is assembly to prevent modifying the stack pointer after + // loading it, and to ensure a jump (not call) to the bootloader. + // Not sure if the barriers are really needed, they were taken from + // https://github.com/GrumpyOldPizza/arduino-STM32L4/blob/ac659033eadd50cfe001ba1590a1362b2d87bb76/system/STM32L4xx/Source/boot_stm32l4xx.c#L159-L165 + asm volatile( + "ldr r0, [%[sys], #0] \n\t" // get address of stack pointer + "msr msp, r0 \n\t" // set stack pointer + "ldr r0, [%[sys], #4] \n\t" // get address of reset handler + "dsb \n\t" // data sync barrier + "isb \n\t" // instruction sync barrier + "bx r0 \n\t" // branch to bootloader + : : [sys] "l"(sys) : "r0" + ); + + __builtin_unreachable(); } } From 8e5ad31175e48ca76886283a0c232869ff26e9ef Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 24 Mar 2020 17:46:48 +0100 Subject: [PATCH 11/15] Delay autoreset to bootloader This waits for 250ms, just like the Arduino SAM and SAMD cores do (AVR waits only 120ms), to allow the USB host and application a bit more time to close the port and clean up. --- cores/arduino/stm32/bootloader.h | 4 +++ cores/arduino/stm32/usb/cdc/usbd_cdc_if.c | 19 +++++++++++--- libraries/SrcWrapper/src/stm32/bootloader.c | 29 +++++++++++++++++++++ libraries/SrcWrapper/src/stm32/clock.c | 2 ++ 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/cores/arduino/stm32/bootloader.h b/cores/arduino/stm32/bootloader.h index 16abbecec0..cb077a624a 100644 --- a/cores/arduino/stm32/bootloader.h +++ b/cores/arduino/stm32/bootloader.h @@ -14,6 +14,10 @@ extern "C" { #endif /* __cplusplus */ +void scheduleBootloaderReset(); +void cancelBootloaderReset(); +void bootloaderSystickHandler(); + /* Request to jump to system memory boot */ void jumpToBootloaderRequested(void); diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c index 9d52899193..b340a6b553 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c @@ -33,6 +33,9 @@ #define CDC_MAX_PACKET_SIZE USB_MAX_EP0_SIZE #endif +// TODO: Put this elsewhere +#define BOOTLOADER_RESET_1200_BAUD + /* * The value USB_CDC_TRANSMIT_TIMEOUT is defined in terms of HAL_GetTick() units. * Typically it is 1ms value. The timeout determines when we would consider the @@ -169,9 +172,6 @@ static int8_t USBD_CDC_Control(uint8_t cmd, uint8_t *pbuf, uint16_t length) linecoding.format = pbuf[4]; linecoding.paritytype = pbuf[5]; linecoding.datatype = pbuf[6]; - if (linecoding.bitrate == 1200) { - jumpToBootloaderRequested(); - } break; case CDC_GET_LINE_CODING: @@ -203,6 +203,19 @@ static int8_t USBD_CDC_Control(uint8_t cmd, uint8_t *pbuf, uint16_t length) break; } +#ifdef BOOTLOADER_RESET_1200_BAUD + if (cmd == CDC_SET_LINE_CODING || cmd == CDC_SET_CONTROL_LINE_STATE) { + // Auto-reset into the bootloader is triggered when the port, already + // open at 1200 bps, is closed. Cancel the reset when the port is + // opened again. + if (linecoding.bitrate == 1200 && !lineState) { + scheduleBootloaderReset(); + } else { + cancelBootloaderReset(); + } + } +#endif /* BOOTLOADER_RESET_1200_BAUD */ + return ((int8_t)USBD_OK); } diff --git a/libraries/SrcWrapper/src/stm32/bootloader.c b/libraries/SrcWrapper/src/stm32/bootloader.c index 8e341a517a..811b527543 100644 --- a/libraries/SrcWrapper/src/stm32/bootloader.c +++ b/libraries/SrcWrapper/src/stm32/bootloader.c @@ -11,7 +11,10 @@ * STM32 built-in bootloader in system memory support */ +static const uint32_t BOOTLOADER_DELAY_MS = 250; static bool BootIntoBootloaderAfterReset; +static uint32_t countdown = 0; + /* Request to jump to system memory boot */ WEAK void jumpToBootloaderRequested(void) @@ -116,6 +119,32 @@ WEAK void jumpToBootloaderIfRequested(void) } } +/** + * Scheduler a reset into the bootloader after a delay. + */ +void scheduleBootloaderReset() +{ + countdown = BOOTLOADER_DELAY_MS; +} + +/** + * Cancel a previously scheduled bootloader reset. + */ +void cancelBootloaderReset() +{ + countdown = 0; +} + +/** + * Bootloader systick handler, should be called every ms + */ +void bootloaderSystickHandler() +{ + if (countdown && --countdown == 0) { + jumpToBootloaderRequested(); + } +} + /* * Legacy maple bootloader support */ diff --git a/libraries/SrcWrapper/src/stm32/clock.c b/libraries/SrcWrapper/src/stm32/clock.c index bea7adcdbc..4c65c98826 100644 --- a/libraries/SrcWrapper/src/stm32/clock.c +++ b/libraries/SrcWrapper/src/stm32/clock.c @@ -37,6 +37,7 @@ */ #include "backup.h" #include "clock.h" +#include "bootloader.h" #include "stm32yyxx_ll_cortex.h" #ifdef __cplusplus @@ -88,6 +89,7 @@ void SysTick_Handler(void) HAL_IncTick(); HAL_SYSTICK_IRQHandler(); osSystickHandler(); + bootloaderSystickHandler(); } /** From 63c49b0adcec04bcb803f5ad70650c38a5674f60 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 3 Sep 2020 17:23:42 +0200 Subject: [PATCH 12/15] HACK: Do not use USB_DevDisconnect in early startup This function calls HAL_Delay, which relies on the systick timer to be running, so this results in an infinite loop. This should probably be fixed in HAL_Delay, but for now just remove the calls to USB_DevDisconnect and USB_DevConnect and replace it with the bit twiddles needed for some chip families (e.g. the F4), breaking compilation and/or functionality for others. --- cores/arduino/stm32/usb/usbd_if.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cores/arduino/stm32/usb/usbd_if.c b/cores/arduino/stm32/usb/usbd_if.c index 6651273530..08f920c616 100644 --- a/cores/arduino/stm32/usb/usbd_if.c +++ b/cores/arduino/stm32/usb/usbd_if.c @@ -194,9 +194,12 @@ WEAK void USBD_reenumerate(void) digitalWriteFast(USBD_PULLUP_CONTROL_PINNAME, USBD_ATTACH_LEVEL); #endif /* defined(USBD_PULLUP_CONTROL_FLOATING) */ #elif defined(USBD_HAVE_INTERNAL_PULLUPS) - USB_DevDisconnect(USBD_USB_INSTANCE); + uint32_t USBx_BASE = (uint32_t)USBD_USB_INSTANCE; + USBx_DEVICE->DCTL |= USB_OTG_DCTL_SDIS; + //USB_DevDisconnect(USBD_USB_INSTANCE); USBD_early_startup_delay_us(USBD_ENUM_DELAY * 1000); - USB_DevConnect(USBD_USB_INSTANCE); + //USB_DevConnect(USBD_USB_INSTANCE); + USBx_DEVICE->DCTL &= ~USB_OTG_DCTL_SDIS; #else #warning "No USB attach/detach method, USB might not be reliable through system resets" #endif From 2f148bfb69959df6e996a509b510a019a64a7d85 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 16 Sep 2020 10:27:19 +0200 Subject: [PATCH 13/15] HACK: Extend HACK to boards with DPPU-based pullup control (e.g. F0) --- cores/arduino/stm32/usb/usbd_if.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cores/arduino/stm32/usb/usbd_if.c b/cores/arduino/stm32/usb/usbd_if.c index 08f920c616..8a8c60301a 100644 --- a/cores/arduino/stm32/usb/usbd_if.c +++ b/cores/arduino/stm32/usb/usbd_if.c @@ -194,12 +194,18 @@ WEAK void USBD_reenumerate(void) digitalWriteFast(USBD_PULLUP_CONTROL_PINNAME, USBD_ATTACH_LEVEL); #endif /* defined(USBD_PULLUP_CONTROL_FLOATING) */ #elif defined(USBD_HAVE_INTERNAL_PULLUPS) +#ifdef USB_OTG_DCTL_SDIS uint32_t USBx_BASE = (uint32_t)USBD_USB_INSTANCE; USBx_DEVICE->DCTL |= USB_OTG_DCTL_SDIS; //USB_DevDisconnect(USBD_USB_INSTANCE); USBD_early_startup_delay_us(USBD_ENUM_DELAY * 1000); //USB_DevConnect(USBD_USB_INSTANCE); USBx_DEVICE->DCTL &= ~USB_OTG_DCTL_SDIS; +#else + USBD_USB_INSTANCE->BCDR &= (uint16_t)(~(USB_BCDR_DPPU)); + USBD_early_startup_delay_us(USBD_ENUM_DELAY * 1000); + USBD_USB_INSTANCE->BCDR |= (uint16_t)(USB_BCDR_DPPU); +#endif #else #warning "No USB attach/detach method, USB might not be reliable through system resets" #endif From 3da8f2d8228edc710105b7935a020df10fc64fb4 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 22 Jan 2020 14:38:58 +0100 Subject: [PATCH 14/15] [USB] Support DFU runtime protocol along CDC This adds support for the DFU runtime protocol, which allows resetting into the bootloader using a DFU command. This allows e.g. dfu-util to handle the complete firmware upload, including the needed reset. This consists of a number of changes: - An extra interface is added to the USB configuration descriptor. This descriptor has two parts (interface descriptor and functional descriptor) which together indicate to a host that this device supports DFU. - Control packets to this new interface are detected by the CDC code an forwarded to a new USBD_DFU_Runtime_Control() function. - This new function handles the DFU GET_STATE, GET_STATUS and DFU_DETACH commands. The former are optional, but simple enough, the latter is mandatory and handles resetting into the bootloader. - The CDC device descriptor is changed to become a composite device (CDC and DFU). This allows operating systems (in particular Windows, Linux did not really need this) to identify two different subdevices, and install different drivers for each (on Windows, this is serusb for the CDC part and WinUSB/libusb for the DFU part). Without this, dfu-util on Windows could not access the DFU commands when the serial driver was loaded. Because the CDC functionality already exposes two interfaces (which together form a single serial port), an IAD (Interface Association Descriptor) is inserted before these interfaces to group them together in a single subdevice. No IAD is needed for the DFU interface, since it is just a single interface. To become a composite device, the device class must be changed from CDC to a composite device class. This was originally class 0/0/0, but together with the IAD, a new EF/2/1 deviceclass was also introduced, which is used now. Note that this only adds descriptors and a command handler on the default control endpoint, so no extra (scarce) endpoints are used by this, just a bit of memory. This commit is still a bit rough, because: - The DFU descriptors and code are now pulled in directly by the CDC code (and HID is not supported yet). Ideally, there should be some kind of pluggable USB library where different interfaces can be registered independent of each other (see also https://github.com/stm32duino/Arduino_Core_STM32/issues/687). - The interface number is hardcoded in the DFU descriptor. - The reset to bootloader happens immediately, while it might be better to wait a short while to allow the current USB transaction to complete. - DFU support is unconditionally advertised, while not all boards might support DFU. --- cores/arduino/stm32/usb/cdc/usbd_cdc.c | 81 +++++++++++-- cores/arduino/stm32/usb/cdc/usbd_cdc.h | 3 +- cores/arduino/stm32/usb/dfu_runtime.h | 151 +++++++++++++++++++++++++ cores/arduino/stm32/usb/usbd_conf.h | 2 +- cores/arduino/stm32/usb/usbd_desc.c | 6 +- 5 files changed, 231 insertions(+), 12 deletions(-) create mode 100644 cores/arduino/stm32/usb/dfu_runtime.h diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc.c b/cores/arduino/stm32/usb/cdc/usbd_cdc.c index 9ee0d7885a..86185360d6 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc.c @@ -158,13 +158,26 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_CfgHSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */ 0x00, - 0x02, /* bNumInterfaces: 2 interface */ + 0x03, /* bNumInterfaces: 3 interface */ 0x01, /* bConfigurationValue: Configuration value */ 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ 0xC0, /* bmAttributes: self powered */ 0x32, /* MaxPower 0 mA */ + /*---------------------------------------------------------------------------*/ + /*Interface Association Descriptor*/ + 0x08, /* bLength: Descriptor length */ + 0x0B, /* bDescriptorType: IAD */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass (class of subdevice, should match first interface) */ + 0x02, /* bFunctionSubclass (subclass of subdevice, should match first interface) */ + 0x00, /* bFunctionProtocol (protocol of subdevice, should match first interface) */ + /* TODO: Put a meaningful string here, which shows up in the Windows */ + /* device manager when no driver is installed yet. */ + 0x00, /* iFunction */ + /*---------------------------------------------------------------------------*/ /* Interface Descriptor */ 0x09, /* bLength: Interface Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ @@ -233,7 +246,9 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_CfgHSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN 0x02, /* bmAttributes: Bulk */ LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), - 0x00 /* bInterval: ignore for Bulk transfer */ + 0x00, /* bInterval: ignore for Bulk transfer */ + + DFU_RT_IFACE_DESC, }; @@ -244,11 +259,25 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_CfgFSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */ 0x00, - 0x02, /* bNumInterfaces: 2 interface */ + 0x03, /* bNumInterfaces: 3 interface */ 0x01, /* bConfigurationValue: Configuration value */ 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ 0xC0, /* bmAttributes: self powered */ 0x32, /* MaxPower 0 mA */ + + /*---------------------------------------------------------------------------*/ + /*Interface Association Descriptor*/ + 0x08, /* bLength: Descriptor length */ + 0x0B, /* bDescriptorType: IAD */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass (class of subdevice, should match first interface) */ + 0x02, /* bFunctionSubclass (subclass of subdevice, should match first interface) */ + 0x00, /* bFunctionProtocol (protocol of subdevice, should match first interface) */ + /* TODO: Put a meaningful string here, which shows up in the Windows */ + /* device manager when no driver is installed yet. */ + 0x00, /* iFunction */ + /*---------------------------------------------------------------------------*/ /* Interface Descriptor */ 0x09, /* bLength: Interface Descriptor size */ @@ -318,7 +347,9 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_CfgFSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN 0x02, /* bmAttributes: Bulk */ LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), - 0x00 /* bInterval: ignore for Bulk transfer */ + 0x00, /* bInterval: ignore for Bulk transfer */ + + DFU_RT_IFACE_DESC, }; __ALIGN_BEGIN static uint8_t USBD_CDC_OtherSpeedCfgDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = { @@ -326,11 +357,26 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_OtherSpeedCfgDesc[USB_CDC_CONFIG_DESC_SIZ] USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION, USB_CDC_CONFIG_DESC_SIZ, 0x00, - 0x02, /* bNumInterfaces: 2 interfaces */ + 0x03, /* bNumInterfaces: 3 interfaces */ 0x01, /* bConfigurationValue: */ 0x04, /* iConfiguration: */ 0xC0, /* bmAttributes: */ 0x32, /* MaxPower 100 mA */ + + /*---------------------------------------------------------------------------*/ + /*Interface Association Descriptor*/ + 0x08, /* bLength: Descriptor length */ + 0x0B, /* bDescriptorType: IAD */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass (class of subdevice, should match first interface) */ + 0x02, /* bFunctionSubclass (subclass of subdevice, should match first interface) */ + 0x00, /* bFunctionProtocol (protocol of subdevice, should match first interface) */ + /* TODO: Put a meaningful string here, which shows up in the Windows */ + /* device manager when no driver is installed yet. */ + 0x00, /* iFunction */ + + /*---------------------------------------------------------------------------*/ /*Interface Descriptor */ 0x09, /* bLength: Interface Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ @@ -399,7 +445,9 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_OtherSpeedCfgDesc[USB_CDC_CONFIG_DESC_SIZ] 0x02, /* bmAttributes: Bulk */ 0x40, /* wMaxPacketSize: */ 0x00, - 0x00 /* bInterval */ + 0x00, /* bInterval */ + + DFU_RT_IFACE_DESC, }; /** @@ -539,7 +587,26 @@ static uint8_t USBD_CDC_Setup(USBD_HandleTypeDef *pdev, switch (req->bmRequest & USB_REQ_TYPE_MASK) { case USB_REQ_TYPE_CLASS: - if (req->wLength != 0U) { + if ((req->bmRequest & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_INTERFACE + && req->wIndex == DFU_RT_IFACE_NUM) { + // Handle requests to the DFU interface separately + int device_to_host = (req->bmRequest & 0x80U); + + if (!device_to_host && req->wLength > 0) { + // When data is sent, return an error, since the data receiving + // machinery will forget the target interface and handle as a CDC + // request instead. + ret = USBD_FAIL; + } else { + ret = USBD_DFU_Runtime_Control(req->bRequest, req->wValue, (uint8_t *)(void *)hcdc->data, req->wLength); + } + + if (ret == USBD_FAIL) { + USBD_CtlError(pdev, req); + } else if (device_to_host && req->wLength > 0) { + USBD_CtlSendData(pdev, (uint8_t *)(void *)hcdc->data, req->wLength); + } + } else if (req->wLength != 0U) { if ((req->bmRequest & 0x80U) != 0U) { ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(req->bRequest, (uint8_t *)hcdc->data, diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc.h b/cores/arduino/stm32/usb/cdc/usbd_cdc.h index 5395708c06..fd4a8022ae 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc.h +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc.h @@ -28,6 +28,7 @@ extern "C" { /* Includes ------------------------------------------------------------------*/ #include "usbd_ioreq.h" #include "usbd_ep_conf.h" +#include "dfu_runtime.h" /** @addtogroup STM32_USB_DEVICE_LIBRARY * @{ @@ -51,7 +52,7 @@ extern "C" { /* CDC Endpoints parameters */ -#define USB_CDC_CONFIG_DESC_SIZ 67U +#define USB_CDC_CONFIG_DESC_SIZ 67U + /* IAD */ 8 + DFU_RT_IFACE_DESC_SIZE #define CDC_DATA_HS_IN_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE #define CDC_DATA_HS_OUT_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE diff --git a/cores/arduino/stm32/usb/dfu_runtime.h b/cores/arduino/stm32/usb/dfu_runtime.h new file mode 100644 index 0000000000..052d65e5ae --- /dev/null +++ b/cores/arduino/stm32/usb/dfu_runtime.h @@ -0,0 +1,151 @@ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_DFU_RUNTIME_H +#define __USB_DFU_RUNTIME_H + +#include + +/**************************************************/ +/* DFU Requests DFU states */ +/**************************************************/ +#define APP_STATE_IDLE 0U +#define APP_STATE_DETACH 1U +#define DFU_STATE_IDLE 2U +#define DFU_STATE_DNLOAD_SYNC 3U +#define DFU_STATE_DNLOAD_BUSY 4U +#define DFU_STATE_DNLOAD_IDLE 5U +#define DFU_STATE_MANIFEST_SYNC 6U +#define DFU_STATE_MANIFEST 7U +#define DFU_STATE_MANIFEST_WAIT_RESET 8U +#define DFU_STATE_UPLOAD_IDLE 9U +#define DFU_STATE_ERROR 10U + +/**************************************************/ +/* DFU errors */ +/**************************************************/ +#define DFU_ERROR_NONE 0x00U +#define DFU_ERROR_TARGET 0x01U +#define DFU_ERROR_FILE 0x02U +#define DFU_ERROR_WRITE 0x03U +#define DFU_ERROR_ERASE 0x04U +#define DFU_ERROR_CHECK_ERASED 0x05U +#define DFU_ERROR_PROG 0x06U +#define DFU_ERROR_VERIFY 0x07U +#define DFU_ERROR_ADDRESS 0x08U +#define DFU_ERROR_NOTDONE 0x09U +#define DFU_ERROR_FIRMWARE 0x0AU +#define DFU_ERROR_VENDOR 0x0BU +#define DFU_ERROR_USB 0x0CU +#define DFU_ERROR_POR 0x0DU +#define DFU_ERROR_UNKNOWN 0x0EU +#define DFU_ERROR_STALLEDPKT 0x0FU + +typedef enum { + DFU_DETACH = 0U, + DFU_DNLOAD, + DFU_UPLOAD, + DFU_GETSTATUS, + DFU_CLRSTATUS, + DFU_GETSTATE, + DFU_ABORT +} DFU_RequestTypeDef; + +#define DFU_DESCRIPTOR_TYPE 0x21U + +// Device will detach by itself (alternative is that the host sends a +// USB reset within DETACH_TIMEOUT). +#define DFU_RT_ATTR_WILL_DETACH 0x08U +// Device is still accessible on USB after flashing (manifestation). +// Probably not so relevant in runtime mode +#define DFU_RT_ATTR_MANIFESTATION_TOLERANT 0x04U +#define DFU_RT_ATTR_CAN_UPLOAD 0x02U +#define DFU_RT_ATTR_CAN_DNLOAD 0x01U + +// Of these, only WILL_DETACH is relevant at runtime, but specify +// CAN_UPLOAD and CAN_DNLOAD too, just in case there is a tool that +// somehow checks these before resetting. +#define DFU_RT_ATTRS DFU_RT_ATTR_WILL_DETACH \ + | DFU_RT_ATTR_CAN_UPLOAD | DFU_RT_ATTR_CAN_DNLOAD + +// Detach timeout is only relevant when ATTR_WILL_DETACH is unset +#define DFU_RT_DETACH_TIMEOUT 0 +// This should be only relevant for actual firmware uploads (the actual +// value is read from the bootloader after reset), but specify a +// conservative value here in case any tool fails to reread the value +// after reset. +// The max packet size for EP0 control transfers is specified in the +// device descriptor. +#define DFU_RT_TRANSFER_SIZE 64 +#define DFU_RT_DFU_VERSION 0x0101 // DFU 1.1 + +#define DFU_RT_IFACE_NUM 2 // XXX: Hardcoded + +#define DFU_RT_IFACE_DESC_SIZE 18U +#define DFU_RT_IFACE_DESC \ + /*DFU Runtime interface descriptor*/ \ + 0x09, /* bLength: Endpoint Descriptor size */ \ + USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */ \ + DFU_RT_IFACE_NUM, /* bInterfaceNumber: Number of Interface */ \ + 0x00, /* bAlternateSetting: Alternate setting */ \ + 0x00, /* bNumEndpoints: no endpoints used (only control endpoint) */ \ + 0xFE, /* bInterfaceClass: Application Specific */ \ + 0x01, /* bInterfaceSubClass: Device Firmware Upgrade Code*/ \ + 0x01, /* bInterfaceProtocol: Runtime Protocol*/ \ + /* TODO: Put a meaningful string here, which shows up in the Windows * */ \ + /* device manager when no driver is installed yet. */ \ + 0x00, /* iInterface: */ \ + \ + /*DFU Runtime Functional Descriptor*/ \ + 0x09, /* bFunctionLength */ \ + DFU_DESCRIPTOR_TYPE, /* bDescriptorType: DFU Functional */ \ + DFU_RT_ATTRS, /* bmAttributes: DFU Attributes */ \ + LOBYTE(DFU_RT_DETACH_TIMEOUT), /* wDetachTimeout */ \ + HIBYTE(DFU_RT_DETACH_TIMEOUT), \ + LOBYTE(DFU_RT_TRANSFER_SIZE), /* wTransferSize */ \ + HIBYTE(DFU_RT_TRANSFER_SIZE), \ + LOBYTE(DFU_RT_DFU_VERSION), /* bcdDFUVersion */ \ + HIBYTE(DFU_RT_DFU_VERSION) + +/** + * @brief USBD_DFU_Runtime_Control + * Manage the DFU interface control requests + * @param bRequest: Command code from request + * @param wValue: Value from request + * @param data: Buffer for result + * @param length: Number of data to be sent (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t USBD_DFU_Runtime_Control(uint8_t bRequest, uint16_t wValue, uint8_t *data, uint16_t len) +{ + UNUSED(wValue); + switch (bRequest) { + case DFU_GETSTATUS: + if (len != 6) { + return (USBD_FAIL); + } + + data[0] = DFU_ERROR_NONE; + // Minimum delay until next GET_STATUS + data[1] = data[2] = data[3] = 0; + data[4] = APP_STATE_IDLE; + // State string descriptor + data[5] = 0; + + return (USBD_OK); + + case DFU_DETACH: + scheduleBootloaderReset(); + return (USBD_OK); + + case DFU_GETSTATE: + if (len != 1) { + return (USBD_FAIL); + } + data[0] = APP_STATE_IDLE; + return (USBD_OK); + + default: + return (USBD_FAIL); + } +} + +#endif // __USB_DFU_RUNTIME_H diff --git a/cores/arduino/stm32/usb/usbd_conf.h b/cores/arduino/stm32/usb/usbd_conf.h index c1a4808380..d0c9a7c8f5 100644 --- a/cores/arduino/stm32/usb/usbd_conf.h +++ b/cores/arduino/stm32/usb/usbd_conf.h @@ -70,7 +70,7 @@ extern "C" { #endif #ifndef USBD_MAX_NUM_INTERFACES -#define USBD_MAX_NUM_INTERFACES 2U +#define USBD_MAX_NUM_INTERFACES 3U #endif /* USBD_MAX_NUM_INTERFACES */ #ifndef USBD_MAX_NUM_CONFIGURATION diff --git a/cores/arduino/stm32/usb/usbd_desc.c b/cores/arduino/stm32/usb/usbd_desc.c index 229112ea5f..6c92dc256c 100644 --- a/cores/arduino/stm32/usb/usbd_desc.c +++ b/cores/arduino/stm32/usb/usbd_desc.c @@ -170,9 +170,9 @@ __ALIGN_BEGIN uint8_t USBD_Class_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = { 0x00, /* bcdUSB */ #endif 0x02, - 0x02, /* bDeviceClass */ - 0x02, /* bDeviceSubClass */ - 0x00, /* bDeviceProtocol */ + 0xEF, /* bDeviceClass (Miscellaneous) */ + 0x02, /* bDeviceSubClass (Common Class) */ + 0x01, /* bDeviceProtocol (Interface Association Descriptor) */ USB_MAX_EP0_SIZE, /* bMaxPacketSize */ LOBYTE(USBD_VID), /* idVendor */ HIBYTE(USBD_VID), /* idVendor */ From a37e8226df64ee7515d5cbb7161db04652f70637 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Fri, 18 Sep 2020 17:27:45 +0200 Subject: [PATCH 15/15] Do not build for STM32MP1xx Bootloader management is not applicable for this serie. Signed-off-by: Frederic Pillon --- libraries/SrcWrapper/src/stm32/bootloader.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/SrcWrapper/src/stm32/bootloader.c b/libraries/SrcWrapper/src/stm32/bootloader.c index 811b527543..f75503f4bf 100644 --- a/libraries/SrcWrapper/src/stm32/bootloader.c +++ b/libraries/SrcWrapper/src/stm32/bootloader.c @@ -10,7 +10,7 @@ /* * STM32 built-in bootloader in system memory support */ - +#if !defined(STM32MP1xx) static const uint32_t BOOTLOADER_DELAY_MS = 250; static bool BootIntoBootloaderAfterReset; static uint32_t countdown = 0; @@ -134,15 +134,18 @@ void cancelBootloaderReset() { countdown = 0; } +#endif /* !STM32MP1xx */ /** * Bootloader systick handler, should be called every ms */ void bootloaderSystickHandler() { +#ifndef STM32MP1xx if (countdown && --countdown == 0) { jumpToBootloaderRequested(); } +#endif /* !STM32MP1xx */ } /*