diff --git a/boards.txt b/boards.txt
index 65074d3a9f..928e85bff6 100644
--- a/boards.txt
+++ b/boards.txt
@@ -580,7 +580,7 @@ Disco.name=Discovery
Disco.build.core=arduino
Disco.build.board=Disco
-Disco.build.extra_flags=-D{build.product_line} {build.enable_usb} {build.xSerial}
+Disco.build.extra_flags=-D{build.product_line} {build.enable_usb} {build.xSerial} {build.bootloader_flags}
# DISCO_F030R8 board
Disco.menu.pnum.DISCO_F030R8=STM32F030R8-DISCVL
@@ -596,7 +596,7 @@ Disco.menu.pnum.DISCO_F030R8.build.cmsis_lib_gcc=arm_cortexM0l_math
# DISCO_F072RB board
Disco.menu.pnum.DISCO_F072RB=STM32F072B-DISCOVERY
-Disco.menu.pnum.DISCO_F072RB.node="No_mass_storage_for_this_board_Use_STLink_upload_method"
+Disco.menu.pnum.DISCO_F072RB.node="No_mass_storage_for_this_board_Use_STLink_upload_method_or_softdfu_upload"
Disco.menu.pnum.DISCO_F072RB.upload.maximum_size=131072
Disco.menu.pnum.DISCO_F072RB.upload.maximum_data_size=16384
Disco.menu.pnum.DISCO_F072RB.build.mcu=cortex-m0
@@ -605,6 +605,9 @@ Disco.menu.pnum.DISCO_F072RB.build.series=STM32F0xx
Disco.menu.pnum.DISCO_F072RB.build.product_line=STM32F072xB
Disco.menu.pnum.DISCO_F072RB.build.variant=DISCO_F072RB
Disco.menu.pnum.DISCO_F072RB.build.cmsis_lib_gcc=arm_cortexM0l_math
+Disco.menu.pnum.DISCO_F072RB.build.startup_file=-DCUSTOM_STARTUP_FILE
+Disco.menu.pnum.DISCO_F072RB.build.bootloader_flags=-DVARIANT_SUPPORT_SOFTDFU
+Disco.menu.pnum.DISCO_F072RB.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
#DISCO_F100RB board
Disco.menu.pnum.DISCO_F100RB=STM32F100RB-DISCVL
@@ -729,6 +732,12 @@ Disco.menu.upload_method.dfuMethod.upload.protocol=2
Disco.menu.upload_method.dfuMethod.upload.options=-g
Disco.menu.upload_method.dfuMethod.upload.tool=stm32CubeProg
+Disco.menu.upload_method.dfusMethod=Soft-DFU Upload
+Disco.menu.upload_method.dfusMethod.upload.protocol=softdfu
+Disco.menu.upload_method.dfusMethod.upload.tool=softdfu_upload
+Disco.menu.upload_method.dfusMethod.upload.usbID=0483:df11
+Disco.menu.upload_method.dfusMethod.upload.altID=0
+
################################################################################
# Eval boards
diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c
index c09675f95e..c10b60dd9d 100644
--- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c
+++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c
@@ -55,6 +55,10 @@ __IO uint32_t lineState = 0;
__IO bool receivePended = true;
static uint32_t transmitStart = 0;
+#ifdef VARIANT_SUPPORT_SOFTDFU
+ void variant_soft_dfu_hook(uint8_t *Buf, uint32_t *Len);
+#endif
+
#ifdef DTR_TOGGLING_SEQ
/* DTR toggling sequence management */
extern void dtr_togglingHook(uint8_t *buf, uint32_t *len);
@@ -222,6 +226,9 @@ static int8_t USBD_CDC_Control(uint8_t cmd, uint8_t *pbuf, uint16_t length)
*/
static int8_t USBD_CDC_Receive(uint8_t *Buf, uint32_t *Len)
{
+#ifdef VARIANT_SUPPORT_SOFTDFU
+ variant_soft_dfu_hook(Buf, Len);
+#endif
#ifdef DTR_TOGGLING_SEQ
if (dtr_toggling > 3) {
dtr_togglingHook(Buf, Len);
diff --git a/platform.txt b/platform.txt
index 49dc9a3ea8..30e9e4c793 100644
--- a/platform.txt
+++ b/platform.txt
@@ -208,3 +208,13 @@ tools.remoteproc_gen.script=run_arduino_gen.sh
tools.remoteproc_gen.upload.params.verbose=
tools.remoteproc_gen.upload.params.quiet=
tools.remoteproc_gen.upload.pattern="{busybox}" sh "{path}/{script}" generate "{build.path}/{build.project_name}.elf" "{build.path}/run_arduino_{build.project_name}.sh"
+
+# STM32 built-in DFU upload with Soft-DFU protocol
+tools.softdfu_upload.cmd=softdfu_upload.sh
+tools.softdfu_upload.cmd.windows=softdfu_upload.bat
+tools.softdfu_upload.path={runtime.tools.STM32Tools.path}/tools/win
+tools.softdfu_upload.path.macosx={runtime.tools.STM32Tools.path}/tools/macosx
+tools.softdfu_upload.path.linux={runtime.tools.STM32Tools.path}/tools/linux
+tools.softdfu_upload.upload.params.verbose=
+tools.softdfu_upload.upload.params.quiet=
+tools.softdfu_upload.upload.pattern="{path}/{cmd}" {serial.port.file} {upload.altID} {upload.usbID} "{build.path}/{build.project_name}.bin"
\ No newline at end of file
diff --git a/variants/DISCO_F072RB/startup_stm32f072xb_softdfu.S b/variants/DISCO_F072RB/startup_stm32f072xb_softdfu.S
new file mode 100644
index 0000000000..07c4669407
--- /dev/null
+++ b/variants/DISCO_F072RB/startup_stm32f072xb_softdfu.S
@@ -0,0 +1,296 @@
+/**
+ ******************************************************************************
+ * @file startup_stm32f072xb.s
+ * @author MCD Application Team
+ * @brief STM32F072x8/STM32F072xB devices vector table for GCC toolchain.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M0 processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ * @attention
+ *
+ *
© Copyright (c) 2016 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m0
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr r0, =_estack
+ mov sp, r0 /* set stack pointer */
+
+ bl __initialize_hardware_early /* check for DFU soft boot */
+
+/* Copy the data segment initializers from flash to SRAM */
+ ldr r0, =_sdata
+ ldr r1, =_edata
+ ldr r2, =_sidata
+ movs r3, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r4, [r2, r3]
+ str r4, [r0, r3]
+ adds r3, r3, #4
+
+LoopCopyDataInit:
+ adds r4, r0, r3
+ cmp r4, r1
+ bcc CopyDataInit
+
+/* Zero fill the bss segment. */
+ ldr r2, =_sbss
+ ldr r4, =_ebss
+ movs r3, #0
+ b LoopFillZerobss
+
+FillZerobss:
+ str r3, [r2]
+ adds r2, r2, #4
+
+LoopFillZerobss:
+ cmp r2, r4
+ bcc FillZerobss
+
+/* Call the clock system intitialization function.*/
+ bl SystemInit
+/* Call static constructors */
+ bl __libc_init_array
+/* Call the application's entry point.*/
+ bl main
+
+LoopForever:
+ b LoopForever
+
+
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ *
+ * @param None
+ * @retval : None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M0. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+ .size g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word 0
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word PVD_VDDIO2_IRQHandler /* PVD and VDDIO2 through EXTI Line detect */
+ .word RTC_IRQHandler /* RTC through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_CRS_IRQHandler /* RCC and CRS */
+ .word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */
+ .word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */
+ .word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */
+ .word TSC_IRQHandler /* TSC */
+ .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */
+ .word DMA1_Channel2_3_IRQHandler /* DMA1 Channel 2 and Channel 3 */
+ .word DMA1_Channel4_5_6_7_IRQHandler /* DMA1 Channel 4, Channel 5, Channel 6 and Channel 7*/
+ .word ADC1_COMP_IRQHandler /* ADC1, COMP1 and COMP2 */
+ .word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word TIM2_IRQHandler /* TIM2 */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word TIM6_DAC_IRQHandler /* TIM6 and DAC */
+ .word TIM7_IRQHandler /* TIM7 */
+ .word TIM14_IRQHandler /* TIM14 */
+ .word TIM15_IRQHandler /* TIM15 */
+ .word TIM16_IRQHandler /* TIM16 */
+ .word TIM17_IRQHandler /* TIM17 */
+ .word I2C1_IRQHandler /* I2C1 */
+ .word I2C2_IRQHandler /* I2C2 */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word SPI2_IRQHandler /* SPI2 */
+ .word USART1_IRQHandler /* USART1 */
+ .word USART2_IRQHandler /* USART2 */
+ .word USART3_4_IRQHandler /* USART3 and USART4 */
+ .word CEC_CAN_IRQHandler /* CEC and CAN */
+ .word USB_IRQHandler /* USB */
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak PVD_VDDIO2_IRQHandler
+ .thumb_set PVD_VDDIO2_IRQHandler,Default_Handler
+
+ .weak RTC_IRQHandler
+ .thumb_set RTC_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_CRS_IRQHandler
+ .thumb_set RCC_CRS_IRQHandler,Default_Handler
+
+ .weak EXTI0_1_IRQHandler
+ .thumb_set EXTI0_1_IRQHandler,Default_Handler
+
+ .weak EXTI2_3_IRQHandler
+ .thumb_set EXTI2_3_IRQHandler,Default_Handler
+
+ .weak EXTI4_15_IRQHandler
+ .thumb_set EXTI4_15_IRQHandler,Default_Handler
+
+ .weak TSC_IRQHandler
+ .thumb_set TSC_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel1_IRQHandler
+ .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel2_3_IRQHandler
+ .thumb_set DMA1_Channel2_3_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel4_5_6_7_IRQHandler
+ .thumb_set DMA1_Channel4_5_6_7_IRQHandler,Default_Handler
+
+ .weak ADC1_COMP_IRQHandler
+ .thumb_set ADC1_COMP_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_UP_TRG_COM_IRQHandler
+ .thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM2_IRQHandler
+ .thumb_set TIM2_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM6_DAC_IRQHandler
+ .thumb_set TIM6_DAC_IRQHandler,Default_Handler
+
+ .weak TIM7_IRQHandler
+ .thumb_set TIM7_IRQHandler,Default_Handler
+
+ .weak TIM14_IRQHandler
+ .thumb_set TIM14_IRQHandler,Default_Handler
+
+ .weak TIM15_IRQHandler
+ .thumb_set TIM15_IRQHandler,Default_Handler
+
+ .weak TIM16_IRQHandler
+ .thumb_set TIM16_IRQHandler,Default_Handler
+
+ .weak TIM17_IRQHandler
+ .thumb_set TIM17_IRQHandler,Default_Handler
+
+ .weak I2C1_IRQHandler
+ .thumb_set I2C1_IRQHandler,Default_Handler
+
+ .weak I2C2_IRQHandler
+ .thumb_set I2C2_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak SPI2_IRQHandler
+ .thumb_set SPI2_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+ .weak USART2_IRQHandler
+ .thumb_set USART2_IRQHandler,Default_Handler
+
+ .weak USART3_4_IRQHandler
+ .thumb_set USART3_4_IRQHandler,Default_Handler
+
+ .weak CEC_CAN_IRQHandler
+ .thumb_set CEC_CAN_IRQHandler,Default_Handler
+
+ .weak USB_IRQHandler
+ .thumb_set USB_IRQHandler,Default_Handler
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/variants/DISCO_F072RB/variant.cpp b/variants/DISCO_F072RB/variant.cpp
index 0b5ec54da5..495d4de6fe 100644
--- a/variants/DISCO_F072RB/variant.cpp
+++ b/variants/DISCO_F072RB/variant.cpp
@@ -34,6 +34,12 @@
extern "C" {
#endif
+#define SYSMEM_RESET_VECTOR 0x1FFFC804
+#define RESET_TO_BOOTLOADER_MAGIC_CODE 0xDEADBEEF
+#define BOOTLOADER_STACK_POINTER 0x20002250
+
+uint32_t dfu_reset_to_bootloader_magic;
+
// Pin number
const PinName digitalPin[] = {
//P2 connector Right side (top view)
@@ -121,6 +127,37 @@ const PinName digitalPin[] = {
extern "C" {
#endif
+void __initialize_hardware_early(void)
+{
+ if (dfu_reset_to_bootloader_magic == RESET_TO_BOOTLOADER_MAGIC_CODE) {
+ void (*bootloader)(void) = (void (*)(void))(*((uint32_t *) SYSMEM_RESET_VECTOR));
+ dfu_reset_to_bootloader_magic = 0;
+ __set_MSP(BOOTLOADER_STACK_POINTER);
+ bootloader();
+ while (42);
+ }
+}
+
+void variant_soft_dfu_hook(uint8_t *Buf, uint32_t *Len)
+{
+ uint32_t i;
+ static unsigned char passkey[] = "1EAF";
+ static unsigned char passkey_index = 0;
+
+ for (i = 0; i < *Len; i++) {
+ /* reading buffer for a sequential bytes that form a pass key */
+ if (*(Buf + i) == passkey[passkey_index])
+ passkey_index++;
+ else
+ passkey_index = 0;
+ /* jump to DFU mode when the pass key found */
+ if (passkey_index == 4) {
+ dfu_reset_to_bootloader_magic = RESET_TO_BOOTLOADER_MAGIC_CODE;
+ NVIC_SystemReset();
+ }
+ }
+}
+
/**
* @brief System Clock Configuration
* @param None