2017-04-15 13:51:24 +02:00
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
*/
/** USB DFU bootloader
* @ file bootloader . c
* @ author King Kévin < kingkevin @ cuvoodoo . info >
2019-06-12 15:11:10 +02:00
* @ date 2017 - 2019
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
/** 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 ;
2020-01-02 13:00:49 +01:00
} else if ( 0 = = ( RCC_CSR & 0xfc000000 ) ) { // no reset flag present -> this was a soft reset using scb_reset_core() after clearing the flags using RCC_CSR_RMVF, this was the legacy way to start the DFU mode
dfu_force = true ;
2018-04-03 16:59:02 +02:00
} else { // check if the force DFU mode input is set
2017-04-15 13:51:24 +02:00
// disable SWJ pin to use as GPIO
2020-01-03 00:16:59 +01:00
# if (defined(DFU_FORCE_PIN) && defined(DFU_FORCE_VALUE))
# if ((GPIO(B) == GPIO_PORT(DFU_FORCE_PIN)) && (GPIO(4) == GPIO_PIN(DFU_FORCE_PIN)))
2018-04-03 17:54:59 +02:00
// JNTRST pin is used as DFU pin
rcc_periph_clock_enable ( RCC_AFIO ) ; // enable clock for alternate function domain
gpio_primary_remap ( AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_JNTRST , 0 ) ; // keep SWJ enable bit don't use JNTRST
2019-12-21 20:02:33 +01:00
# elif ((GPIO(B) == GPIO_PORT(DFU_FORCE_PIN)) && (GPIO(3) == GPIO_PIN(DFU_FORCE_PIN))) || ((GPIO(A) == GPIO_PORT(DFU_FORCE_PIN)) && (GPIO(15) == GPIO_PIN(DFU_FORCE_PIN)))
2018-04-03 17:54:59 +02:00
// JTAG but not SWD pin used as DFU pin
rcc_periph_clock_enable ( RCC_AFIO ) ; // enable clock for alternate function domain
gpio_primary_remap ( AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON , 0 ) ; // disable JTAG but keep SWD
2019-12-21 20:02:33 +01:00
# elif ((GPIO(A) == GPIO_PORT(DFU_FORCE_PIN)) && (GPIO(14) == GPIO_PIN(DFU_FORCE_PIN))) || ((GPIO(A) == GPIO_PORT(DFU_FORCE_PIN)) && (GPIO(13) == GPIO_PIN(DFU_FORCE_PIN)))
2018-04-03 17:54:59 +02:00
// JTAG and SWD pin used as DFU pin
rcc_periph_clock_enable ( RCC_AFIO ) ; // enable clock for alternate function domain
gpio_primary_remap ( AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_OFF , 0 ) ; // disable JTAG and SWD
2020-01-03 00:16:59 +01:00
# endif // DFU_FORCE_PIN
2019-12-21 20:02:33 +01:00
rcc_periph_clock_enable ( GPIO_RCC ( DFU_FORCE_PIN ) ) ; // enable clock for GPIO domain
gpio_set_mode ( GPIO_PORT ( DFU_FORCE_PIN ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_PULL_UPDOWN , GPIO_PIN ( DFU_FORCE_PIN ) ) ; // set GPIO to input
2017-04-15 13:51:24 +02:00
// pull on the opposite of the expected value
2019-01-12 16:20:05 +01:00
# if (DFU_FORCE_VALUE == 1)
2019-12-21 20:02:33 +01:00
gpio_clear ( GPIO_PORT ( DFU_FORCE_PIN ) , GPIO_PIN ( DFU_FORCE_PIN ) ) ; // pull down to be able to detect when tied to high
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
2019-12-21 20:02:33 +01:00
gpio_set ( GPIO_PORT ( DFU_FORCE_PIN ) , GPIO_PIN ( DFU_FORCE_PIN ) ) ; // pull up to be able to detect when tied to low
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-01-03 00:16:59 +01:00
# endif // defined(DFU_FORCE_PIN)
2019-11-18 11:17:55 +01:00
gpio_primary_remap ( AFIO_MAPR_SWJ_CFG_FULL_SWJ , 0 ) ; // re-enable full SWJ
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
2018-04-07 11:13:08 +02:00
* on STM32F1xx SRAM begins at 0x2000 0000 , and on STM32F103xx there is up to 96 KB of RAM ( 0x18000 ) .
* since the stack grown " downwards " it should start at the end of the RAM : max 0x2001 8000
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)
2019-01-12 16:20:05 +01:00
if ( ! dfu_force & & ( ( ( * application ) & 0xFFFE0000 ) = = 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
}
rcc_clock_setup_in_hse_8mhz_out_72mhz ( ) ; // start main clock
board_setup ( ) ; // setup board to control LED
led_on ( ) ; // indicate bootloader started
2018-05-03 12:54:55 +02:00
# if defined(BUSVOODOO)
led_toggle ( ) ; // switch from blue to red LED
2018-04-03 16:59:02 +02:00
# endif
2017-04-15 13:51:24 +02:00
usb_dfu_setup ( ) ; // setup USB DFU for firmware upload
usb_dfu_start ( ) ; // run DFU mode
}