CuVoodoo STM32F1 firmware template
bootloader.c
Go to the documentation of this file.
1 /* This program is free software: you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation, either version 3 of the License, or
4  * (at your option) any later version.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program. If not, see <http://www.gnu.org/licenses/>.
13  *
14  */
20 /* standard libraries */
21 #include <stdint.h> // standard integer types
22 #include <stdbool.h> // boolean types
23 
24 /* STM32 (including CM3) libraries */
25 #include <libopencm3/cm3/scb.h> // vector table definition
26 #include <libopencm3/stm32/rcc.h> // clock utilities
27 #include <libopencm3/stm32/gpio.h> // GPIO utilities
28 
29 /* own libraries */
30 #include "global.h" // board definitions
31 #include "usb_dfu.h" // USB DFU utilities
32 
34 void main(void);
35 void main(void)
36 {
37  // check of DFU mode is forced
38  bool dfu_force = false; // to remember if DFU mode is forced
39  // check if a soft boot has been used
40  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, very probably to start the DFU mode
41  dfu_force = true;
42  } else { // check if the force DFU mode input is set
43  // disable SWJ pin to use as GPIO
44 #if (GPIO(B)==GPIO(DFU_FORCE_PORT)) && (GPIO(4)==GPIO(DFU_FORCE_PIN))
45  // JNTRST pin is used as DFU pin
46  rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternate function domain
47  gpio_primary_remap(AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_JNTRST, 0); // keep SWJ enable bit don't use JNTRST
48 #elif ((GPIO(B)==GPIO(DFU_FORCE_PORT)) && (GPIO(3)==GPIO(DFU_FORCE_PIN))) || ((GPIO(A)==GPIO(DFU_FORCE_PORT)) && (GPIO(15)==GPIO(DFU_FORCE_PIN)))
49  // JTAG but not SWD pin used as DFU pin
50  rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternate function domain
51  gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0); // disable JTAG but keep SWD
52 #elif ((GPIO(A)==GPIO(DFU_FORCE_PORT)) && (GPIO(14)==GPIO(DFU_FORCE_PIN))) || ((GPIO(A)==GPIO(DFU_FORCE_PORT)) && (GPIO(13)==GPIO(DFU_FORCE_PIN)))
53  // JTAG and SWD pin used as DFU pin
54  rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternate function domain
55  gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_OFF, 0); // disable JTAG and SWD
56 #endif
57  rcc_periph_clock_enable(RCC_GPIO(DFU_FORCE_PORT)); // enable clock for GPIO domain
58  gpio_set_mode(GPIO(DFU_FORCE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO(DFU_FORCE_PIN)); // set GPIO to input
59  // pull on the opposite of the expected value
60 #if (DFU_FORCE_VALUE==1)
61  gpio_clear(GPIO(DFU_FORCE_PORT), GPIO(DFU_FORCE_PIN)); // pull down to be able to detect when tied to high
62  if (gpio_get(GPIO(DFU_FORCE_PORT), GPIO(DFU_FORCE_PIN))) { // check if output is set to the value to force DFU mode
63 #else
64  gpio_set(GPIO(DFU_FORCE_PORT), GPIO(DFU_FORCE_PIN)); // pull up to be able to detect when tied to low
65  if (0==gpio_get(GPIO(DFU_FORCE_PORT), GPIO(DFU_FORCE_PIN))) { // check if output is set to the value to force DFU mode
66 #endif
67  dfu_force = true; // DFU mode forced
68  }
69  }
70 
71  // start application if valid
72  /* the application starts with the vector table
73  * the first entry in the vector table is the initial stack pointer (SP) address
74  * the stack will be placed in RAM
75  * on STM32F1xx SRAM begins at 0x2000 0000, and on STM32F103xx there is up to 96 KB of RAM (0x18000).
76  * since the stack grown "downwards" it should start at the end of the RAM: max 0x2001 8000
77  * if the SP is not in this range (e.g. flash has been erased) there is no valid application
78  * the second entry in the vector table is the reset address, corresponding to the application start
79  */
80  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)
81  if (!dfu_force && (((*application)&0xFFFE0000)==0x20000000)) { // application at address seems valid
82  SCB_VTOR = (volatile uint32_t)(application); // set vector table to application vector table (store at the beginning of the application)
83  __asm__ volatile ("MSR msp,%0" : :"r"(*application)); // set stack pointer to address provided in the beginning of the application (loaded into a register first)
84  (*(void(**)(void))(application + 1))(); // start application (by jumping to the reset function which address is stored as second entry of the vector table)
85  }
86 
87  rcc_clock_setup_in_hse_8mhz_out_72mhz(); // start main clock
88  board_setup(); // setup board to control LED
89  led_on(); // indicate bootloader started
90 #if defined(BUSVOODOO)
91  led_toggle(); // switch from blue to red LED
92 #endif
93  usb_dfu_setup(); // setup USB DFU for firmware upload
94  usb_dfu_start(); // run DFU mode
95 }
void board_setup(void)
setup board peripherals
Definition: global.c:169
void main(void)
bootloader entry point
Definition: bootloader.c:35
#define RCC_GPIO(x)
get RCC for GPIO based on GPIO identifier
Definition: global.h:105
char __application_beginning
symbol for beginning of the application
#define DFU_FORCE_PORT
JNTRST port (needs to be remapped to become PB4)
Definition: global.h:423
global definitions and methods (API)
#define GPIO(x)
get GPIO based on GPIO identifier
Definition: global.h:103
void usb_dfu_start(void)
start USB DFU handling
Definition: usb_dfu.c:297
void usb_dfu_setup(void)
setup USB DFU peripheral
Definition: usb_dfu.c:286
#define DFU_FORCE_PIN
JNTRST pin (needs to be remapped to become PB4)
Definition: global.h:424
library for USB DFU to write on internal flash (API)
void led_toggle(void)
toggle board LED
Definition: global.c:94
void led_on(void)
switch on board LED
Definition: global.c:67