2017-04-15 13:51:24 +02:00
/** USB DFU bootloader
2020-06-06 14:35:55 +02:00
* @ file
2017-04-15 13:51:24 +02:00
* @ author King Kévin < kingkevin @ cuvoodoo . info >
2020-06-06 14:35:55 +02:00
* @ copyright SPDX - License - Identifier : GPL - 3.0 - or - later
2020-11-24 16:18:17 +01:00
* @ date 2017 - 2020
2017-04-15 13:51:24 +02:00
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdbool.h> // boolean types
/* STM32 (including CM3) libraries */
# include <libopencm3/cm3/scb.h> // vector table definition
# include <libopencm3/stm32/rcc.h> // clock utilities
# include <libopencm3/stm32/gpio.h> // GPIO utilities
/* own libraries */
# include "global.h" // board definitions
# include "usb_dfu.h" // USB DFU utilities
2020-11-24 16:18:17 +01:00
/** symbol for beginning of the application
* @ note this symbol will be provided by the bootloader linker script
*/
2022-05-10 10:48:05 +02:00
extern uint32_t __application_beginning ;
2020-11-24 16:18:17 +01:00
2017-04-15 13:51:24 +02:00
/** bootloader entry point */
void main ( void ) ;
void main ( void )
{
// check of DFU mode is forced
bool dfu_force = false ; // to remember if DFU mode is forced
2019-12-21 19:48:00 +01:00
// check if DFU magic DFU! has been written to RAM (e.g. by application to indicate we want to start the DFU bootloader)
if ( ' D ' = = __dfu_magic [ 0 ] & & ' F ' = = __dfu_magic [ 1 ] & & ' U ' = = __dfu_magic [ 2 ] & & ' ! ' = = __dfu_magic [ 3 ] ) { // verify if the DFU magic is set
2017-04-15 13:51:24 +02:00
dfu_force = true ;
2019-12-21 19:48:00 +01:00
// clear DFU magic
__dfu_magic [ 0 ] = 0 ;
__dfu_magic [ 1 ] = 0 ;
__dfu_magic [ 2 ] = 0 ;
__dfu_magic [ 3 ] = 0 ;
2018-04-03 16:59:02 +02:00
} else { // check if the force DFU mode input is set
2020-01-03 00:16:59 +01:00
# if (defined(DFU_FORCE_PIN) && defined(DFU_FORCE_VALUE))
2022-05-24 14:11:19 +02:00
rcc_periph_clock_enable ( GPIO_RCC ( DFU_FORCE_PIN ) ) ; // enable clock for button
2019-01-12 16:20:05 +01:00
# if (DFU_FORCE_VALUE == 1)
2020-11-24 16:18:17 +01:00
gpio_mode_setup ( GPIO_PORT ( DFU_FORCE_PIN ) , GPIO_MODE_INPUT , GPIO_PUPD_PULLDOWN , GPIO_PIN ( DFU_FORCE_PIN ) ) ; // set GPIO to input
2019-12-21 20:02:33 +01:00
if ( gpio_get ( GPIO_PORT ( DFU_FORCE_PIN ) , GPIO_PIN ( DFU_FORCE_PIN ) ) ) { // check if output is set to the value to force DFU mode
2018-02-18 15:18:42 +01:00
# else
2020-11-24 16:18:17 +01:00
gpio_mode_setup ( GPIO_PORT ( DFU_FORCE_PIN ) , GPIO_MODE_INPUT , GPIO_PUPD_PULLUP , GPIO_PIN ( DFU_FORCE_PIN ) ) ; // set GPIO to input
2019-12-21 20:02:33 +01:00
if ( 0 = = gpio_get ( GPIO_PORT ( DFU_FORCE_PIN ) , GPIO_PIN ( DFU_FORCE_PIN ) ) ) { // check if output is set to the value to force DFU mode
2020-01-03 00:16:59 +01:00
# endif // DFU_FORCE_VALUE
2017-04-15 13:51:24 +02:00
dfu_force = true ; // DFU mode forced
}
2020-06-14 19:02:37 +02:00
rcc_periph_reset_pulse ( GPIO_RST ( DFU_FORCE_PIN ) ) ; // reset pin GPIO domain
rcc_periph_clock_disable ( GPIO_RCC ( DFU_FORCE_PIN ) ) ; // disable pin GPIO domain
2022-05-24 14:11:19 +02:00
# endif // defined(DFU_FORCE_PIN)
2017-04-15 13:51:24 +02:00
}
// start application if valid
/* the application starts with the vector table
* the first entry in the vector table is the initial stack pointer ( SP ) address
* the stack will be placed in RAM
2020-11-24 16:18:17 +01:00
* on STM32F4 SRAM begins at 0x2000 0000 , and on STM32F4xx there is up to 384 KiB of RAM ( 0x60000 ) .
* since the stack grown " downwards " it should start at the end of the RAM : max 0x2006 0000
2017-04-15 13:51:24 +02:00
* if the SP is not in this range ( e . g . flash has been erased ) there is no valid application
* the second entry in the vector table is the reset address , corresponding to the application start
*/
2018-04-06 19:56:57 +02:00
volatile uint32_t * application = ( uint32_t * ) & __application_beginning ; // get the value of the application address symbol (use a register instead on the stack since the stack pointer will be changed)
2020-11-24 16:18:17 +01:00
if ( ! dfu_force & & ( ( ( * application ) & 0xFFF80000 ) = = 0x20000000 ) ) { // application at address seems valid
2017-04-15 13:51:24 +02:00
SCB_VTOR = ( volatile uint32_t ) ( application ) ; // set vector table to application vector table (store at the beginning of the application)
__asm__ volatile ( " MSR msp,%0 " : : " r " ( * application ) ) ; // set stack pointer to address provided in the beginning of the application (loaded into a register first)
2019-06-12 15:11:10 +02:00
( * ( void ( * * ) ( void ) ) ( ( uint32_t ) application + 4 ) ) ( ) ; // start application (by jumping to the reset function which address is stored as second entry of the vector table)
2017-04-15 13:51:24 +02:00
}
board_setup ( ) ; // setup board to control LED
led_on ( ) ; // indicate bootloader started
usb_dfu_setup ( ) ; // setup USB DFU for firmware upload
usb_dfu_start ( ) ; // run DFU mode
}