123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- /*
- * STM32F1 board support for the bootloader.
- *
- */
- #include "hw_config.h"
- #include <stdlib.h>
- #include <libopencm3/stm32/rcc.h>
- #include <libopencm3/stm32/f1/bkp.h>
- #include <libopencm3/stm32/gpio.h>
- #include <libopencm3/stm32/flash.h>
- #include <libopencm3/stm32/usart.h>
- #include <libopencm3/stm32/pwr.h>
- #include <libopencm3/cm3/systick.h>
- #include "bl.h"
- #define UDID_START 0x1FFFF7E8
- // address of MCU IDCODE
- #define DBGMCU_IDCODE 0xE0042000
- #ifdef INTERFACE_USART
- # define BOARD_INTERFACE_CONFIG (void *)BOARD_USART
- #else
- # define BOARD_INTERFACE_CONFIG NULL
- #endif
- /* board definition */
- struct boardinfo board_info = {
- .board_type = BOARD_TYPE,
- .board_rev = 0,
- .fw_size = APP_SIZE_MAX,
- .systick_mhz = OSC_FREQ,
- };
- static void board_init(void);
- uint32_t
- board_get_devices(void)
- {
- return BOOT_DEVICES_SELECTION;
- }
- static void
- board_init(void)
- {
- /* initialise LEDs */
- rcc_peripheral_enable_clock(&BOARD_CLOCK_LEDS_REGISTER, BOARD_CLOCK_LEDS);
- gpio_set_mode(BOARD_PORT_LEDS,
- GPIO_MODE_OUTPUT_50_MHZ,
- GPIO_CNF_OUTPUT_PUSHPULL,
- BOARD_PIN_LED_BOOTLOADER | BOARD_PIN_LED_ACTIVITY);
- BOARD_LED_ON(
- BOARD_PORT_LEDS,
- BOARD_PIN_LED_BOOTLOADER | BOARD_PIN_LED_ACTIVITY);
- /* if we have one, enable the force-bootloader pin */
- #ifdef BOARD_FORCE_BL_PIN
- rcc_peripheral_enable_clock(&BOARD_FORCE_BL_CLOCK_REGISTER, BOARD_FORCE_BL_CLOCK_BIT);
- gpio_set(BOARD_FORCE_BL_PORT, BOARD_FORCE_BL_PIN);
- gpio_set_mode(BOARD_FORCE_BL_PORT,
- GPIO_MODE_INPUT,
- BOARD_FORCE_BL_PULL,
- BOARD_FORCE_BL_PIN);
- #endif
- /* enable the backup registers */
- rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN);
- #ifdef INTERFACE_USART
- /* configure usart pins */
- rcc_peripheral_enable_clock(&BOARD_USART_PIN_CLOCK_REGISTER, BOARD_USART_PIN_CLOCK_BIT);
- gpio_set_mode(BOARD_PORT_USART,
- GPIO_MODE_OUTPUT_50_MHZ,
- GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
- BOARD_PIN_TX);
- /* configure USART clock */
- rcc_peripheral_enable_clock(&BOARD_USART_CLOCK_REGISTER, BOARD_USART_CLOCK_BIT);
- #endif
- #ifdef INTERFACE_I2C
- # error I2C GPIO config not handled yet
- #endif
- }
- void
- board_deinit(void)
- {
- /* deinitialise LEDs */
- gpio_set_mode(BOARD_PORT_LEDS,
- GPIO_MODE_INPUT,
- GPIO_CNF_INPUT_FLOAT,
- BOARD_PIN_LED_BOOTLOADER | BOARD_PIN_LED_ACTIVITY);
- /* if we have one, disable the force-bootloader pin */
- #ifdef BOARD_FORCE_BL_PIN
- gpio_set_mode(BOARD_FORCE_BL_PORT,
- GPIO_MODE_INPUT,
- GPIO_CNF_INPUT_FLOAT,
- BOARD_FORCE_BL_PIN);
- gpio_clear(BOARD_FORCE_BL_PORT, BOARD_FORCE_BL_PIN);
- #endif
- /* disable the backup registers */
- rcc_peripheral_disable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN);
- #ifdef INTERFACE_USART
- /* configure usart pins */
- gpio_set_mode(BOARD_PORT_USART,
- GPIO_MODE_INPUT,
- GPIO_CNF_INPUT_FLOAT,
- BOARD_PIN_TX);
- /* disable USART peripheral clock */
- rcc_peripheral_disable_clock(&BOARD_USART_CLOCK_REGISTER, BOARD_USART_CLOCK_BIT);
- #endif
- #ifdef INTERFACE_I2C
- # error I2C GPIO config not handled yet
- #endif
- /* reset the APB2 peripheral clocks */
- RCC_APB2ENR = 0x00000000; // XXX Magic reset number from STM32F1x reference manual
- }
- /**
- * @brief Initializes the RCC clock configuration.
- *
- * @param clock_setup : The clock configuration to set
- */
- static inline void
- clock_init(void)
- {
- #if defined(INTERFACE_USB)
- rcc_clock_setup_in_hsi_out_48mhz();
- #else
- rcc_clock_setup_in_hsi_out_24mhz();
- #endif
- }
- /**
- * @brief Resets the RCC clock configuration to the default reset state.
- * @note The default reset state of the clock configuration is given below:
- * - HSI ON and used as system clock source
- * - HSE, PLL and PLLI2S OFF
- * - AHB, APB1 and APB2 prescaler set to 1.
- * - CSS, MCO1 and MCO2 OFF
- * - All interrupts disabled
- * @note This function doesn't modify the configuration of the
- * - Peripheral clocks
- * - LSI, LSE and RTC clocks
- */
- void
- clock_deinit(void)
- {
- /* Enable internal high-speed oscillator. */
- rcc_osc_on(RCC_HSI);
- rcc_wait_for_osc_ready(RCC_HSI);
- /* Reset the RCC_CFGR register */
- RCC_CFGR = 0x000000;
- /* Stop the HSE, CSS, PLL, PLLI2S, PLLSAI */
- rcc_osc_off(RCC_HSE);
- rcc_osc_off(RCC_PLL);
- rcc_css_disable();
- /* Reset the HSEBYP bit */
- rcc_osc_bypass_disable(RCC_HSE);
- /* Reset the CIR register */
- RCC_CIR = 0x000000;
- }
- uint32_t
- flash_func_sector_size(unsigned sector)
- {
- if (sector < BOARD_FLASH_SECTORS) {
- return FLASH_SECTOR_SIZE;
- }
- return 0;
- }
- void
- flash_func_erase_sector(unsigned sector)
- {
- if (sector < BOARD_FLASH_SECTORS) {
- flash_erase_page(APP_LOAD_ADDRESS + (sector * FLASH_SECTOR_SIZE));
- }
- }
- void
- flash_func_write_word(uint32_t address, uint32_t word)
- {
- flash_program_word(address + APP_LOAD_ADDRESS, word);
- }
- uint32_t
- flash_func_read_word(uint32_t address)
- {
- return *(uint32_t *)(address + APP_LOAD_ADDRESS);
- }
- uint32_t
- flash_func_read_otp(uint32_t address)
- {
- return 0;
- }
- uint32_t get_mcu_id(void)
- {
- return *(uint32_t *)DBGMCU_IDCODE;
- }
- // See F4 version for future enhancement for full decoding
- int get_mcu_desc(int max, uint8_t *revstr)
- {
- const char none[] = "STM32F1xxx,?";
- int i;
- for (i = 0; none[i] && i < max - 1; i++) {
- revstr[i] = none[i];
- }
- return i;
- }
- int check_silicon(void)
- {
- return 0;
- }
- uint32_t
- flash_func_read_sn(uint32_t address)
- {
- // read a byte out from unique chip ID area
- // it's 12 bytes, or 3 words.
- return *(uint32_t *)(address + UDID_START);
- }
- void
- led_on(unsigned led)
- {
- switch (led) {
- case LED_ACTIVITY:
- BOARD_LED_ON(BOARD_PORT_LEDS, BOARD_PIN_LED_ACTIVITY);
- break;
- case LED_BOOTLOADER:
- BOARD_LED_ON(BOARD_PORT_LEDS, BOARD_PIN_LED_BOOTLOADER);
- break;
- }
- }
- void
- led_off(unsigned led)
- {
- switch (led) {
- case LED_ACTIVITY:
- BOARD_LED_OFF(BOARD_PORT_LEDS, BOARD_PIN_LED_ACTIVITY);
- break;
- case LED_BOOTLOADER:
- BOARD_LED_OFF(BOARD_PORT_LEDS, BOARD_PIN_LED_BOOTLOADER);
- break;
- }
- }
- void
- led_toggle(unsigned led)
- {
- switch (led) {
- case LED_ACTIVITY:
- gpio_toggle(BOARD_PORT_LEDS, BOARD_PIN_LED_ACTIVITY);
- break;
- case LED_BOOTLOADER:
- gpio_toggle(BOARD_PORT_LEDS, BOARD_PIN_LED_BOOTLOADER);
- break;
- }
- }
- static bool
- should_wait(void)
- {
- bool result = false;
- PWR_CR |= PWR_CR_DBP;
- if (BKP_DR1 == BL_WAIT_MAGIC) {
- result = true;
- BKP_DR1 = 0;
- }
- PWR_CR &= ~PWR_CR_DBP;
- return result;
- }
- int
- main(void)
- {
- unsigned timeout = 0;
- /* do board-specific initialisation */
- board_init();
- #if defined(INTERFACE_USART) || defined (INTERFACE_USB)
- /* XXX sniff for a USART connection to decide whether to wait in the bootloader? */
- timeout = BOOTLOADER_DELAY;
- #endif
- #ifdef INTERFACE_I2C
- # error I2C bootloader detection logic not implemented
- #endif
- /* if the app left a cookie saying we should wait, then wait */
- if (should_wait()) {
- timeout = BOOTLOADER_DELAY;
- }
- #ifdef BOARD_FORCE_BL_PIN
- /* if the force-BL pin state matches the state of the pin, wait in the bootloader forever */
- if (BOARD_FORCE_BL_VALUE == gpio_get(BOARD_FORCE_BL_PORT, BOARD_FORCE_BL_PIN)) {
- timeout = 0xffffffff;
- }
- #endif
- /* look for the magic wait-in-bootloader value in backup register zero */
- /* if we aren't expected to wait in the bootloader, try to boot immediately */
- if (timeout == 0) {
- /* try to boot immediately */
- jump_to_app();
- /* if we returned, there is no app; go to the bootloader and stay there */
- timeout = 0;
- }
- /* configure the clock for bootloader activity */
- clock_init();
- /* start the interface */
- cinit(BOARD_INTERFACE_CONFIG, USART);
- while (1) {
- /* run the bootloader, possibly coming back after the timeout */
- bootloader(timeout);
- /* look to see if we can boot the app */
- jump_to_app();
- /* boot failed; stay in the bootloader forever next time */
- timeout = 0;
- }
- }
|