/* * This file is part of the libopencm3 project. * * Copyright (C) 2010 Gareth McMullin * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include "project.h" #define BOOTLOADER_BUTTON GPIO12 #define BOOTLOADER_BUTTON_PORT GPIOE static const clock_scale_t hsi_16mhz_3v3_48 = { /* 48MHz */ .pllm = 16, .plln = 96, .pllp = 2, .pllq = 2, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, .power_save = 1, .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | FLASH_ACR_LATENCY_3WS, .apb1_frequency = 12000000, .apb2_frequency = 24000000, }; static void rcc_clock_setup_hsi_3v3 (const clock_scale_t *clock) { /* Enable internal high-speed oscillator. */ rcc_osc_on (HSI); rcc_wait_for_osc_ready (HSI); /* Select HSI as SYSCLK source. */ rcc_set_sysclk_source (RCC_CFGR_SW_HSI); rcc_wait_for_sysclk_status (HSI); rcc_osc_off (PLL); while (RCC_CR & RCC_CR_PLLRDY); pwr_set_vos_scale (SCALE1); /* * Set prescalers for AHB, ADC, ABP1, ABP2. * Do this before touching the PLL (TODO: why?). */ rcc_set_hpre (clock->hpre); rcc_set_ppre1 (clock->ppre1); rcc_set_ppre2 (clock->ppre2); rcc_set_main_pll_hsi (clock->pllm, clock->plln, clock->pllp, clock->pllq); /* Enable PLL oscillator and wait for it to stabilize. */ rcc_osc_on (PLL); rcc_wait_for_osc_ready (PLL); /* Configure flash settings. */ flash_set_ws (clock->flash_config); /* Select PLL as SYSCLK source. */ rcc_set_sysclk_source (RCC_CFGR_SW_PLL); /* Wait for PLL clock to be selected. */ rcc_wait_for_sysclk_status (PLL); /* Set the peripheral clock frequencies used. */ rcc_apb1_frequency = clock->apb1_frequency; rcc_apb2_frequency = clock->apb2_frequency; } int main (void) { rcc_periph_clock_enable (RCC_GPIOE); rcc_periph_clock_enable (RCC_GPIOB); rcc_periph_clock_enable (RCC_GPIOG); MAP_INPUT_PU (BOOTLOADER_BUTTON); if ((dfu_flag != 0xfee1dead) && (GET (BOOTLOADER_BUTTON))) { /* Boot the application if it's valid. */ if ((* (volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20020000) { max7219 ("boot"); rcc_periph_clock_disable (RCC_GPIOE); rcc_periph_clock_disable (RCC_GPIOB); rcc_periph_clock_disable (RCC_GPIOG); /* Set vector table base address. */ SCB_VTOR = APP_ADDRESS & 0xFFFF; /* Initialise master stack pointer. */ asm volatile ("msr msp, %0\n" "blx %1\n" :: "g" (* (volatile uint32_t *)APP_ADDRESS), "r" (* (uint32_t *) (APP_ADDRESS + 4)) : "memory"); } else max7219 ("nofw dfu"); } else max7219 ("dfu"); dfu_flag = 0; rcc_periph_clock_enable (RCC_SYSCFG); rcc_clock_setup_hsi_3v3 (&hsi_16mhz_3v3_48); RCC_AHB1RSTR |= RCC_AHB1RSTR_ETHMACRST; RCC_AHB2RSTR |= RCC_AHB2RSTR_OTGFSRST; asm ("nop":::"memory"); RCC_AHB2RSTR &= ~RCC_AHB2RSTR_OTGFSRST; RCC_AHB1RSTR &= ~RCC_AHB1RSTR_ETHMACRST; usart_init(); usart2_xmit_str ("\r\nDFU Bootloader\r\n"); delay_ms (100); usart_init(); usart2_xmit_str ("Ready\r\n"); usb(); }