Files
templates/c/set-protocol/ports/stm32f407-usb-boot/boot_main.c
T

70 lines
3.3 KiB
C

/*
* Старт USB-загрузчика и выбор между обслуживанием обновления и запуском приложения. Здесь
* настраиваются аппаратные часы и цикл обслуживания; код выполняется в окружении конкретного
* MCU.
*/
#include "stm32f4xx_hal.h"
#include "boot_config.h"
#include "usb_cdc.h"
#include "boot_port.h"
#if F407_BOOT_HSE_HZ != HSE_VALUE
#error boot_config.h and HAL HSE_VALUE must describe the same crystal
#endif
#if (F407_BOOT_HSE_HZ % 1000000UL) || F407_BOOT_HSE_HZ < 2000000UL || F407_BOOT_HSE_HZ > 50000000UL
#error HSE must provide a valid integer PLLM divider (2..50 MHz)
#endif
uint32_t SystemCoreClock=16000000;
const uint8_t AHBPrescTable[16]={0,0,0,0,0,0,0,0,1,2,3,4,6,7,8,9};
const uint8_t APBPrescTable[8]={0,0,0,0,1,2,3,4};
static uint8_t usb_clock_ready;
static volatile uint32_t clock_fault;
void SystemInit(void) { SCB->CPACR|=0xFu<<20; SCB->VTOR=0x08000000; }
void SysTick_Handler(void) { HAL_IncTick(); }
static void board_fatal(uint32_t code) { clock_fault=code; for(;;) {} }
static void peripheral_clock(void)
{
RCC_OscInitTypeDef osc={0};
RCC_ClkInitTypeDef clk={0};
/* Разрешаем доступ к PWR и выбираем диапазон питания ядра перед повышением частоты. */
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
osc.OscillatorType=RCC_OSCILLATORTYPE_HSE;
osc.HSEState=RCC_HSE_ON;
/* Готовность HSE проверяется HAL с ограниченным временем ожидания, а не бесконечным циклом. */
if (HAL_RCC_OscConfig(&osc)==HAL_OK) usb_clock_ready=1;
else {
clock_fault=1;
osc.HSEState=RCC_HSE_OFF;
if (HAL_RCC_OscConfig(&osc)!=HAL_OK) board_fatal(3);
}
/* CPU 72 MHz, APB1 36 MHz, USB 48 MHz; USB requires the HSE crystal. */
osc.OscillatorType=RCC_OSCILLATORTYPE_HSI;
osc.HSIState=RCC_HSI_ON;
osc.HSICalibrationValue=RCC_HSICALIBRATION_DEFAULT;
osc.PLL.PLLState=RCC_PLL_ON;
osc.PLL.PLLSource=usb_clock_ready ? RCC_PLLSOURCE_HSE : RCC_PLLSOURCE_HSI;
osc.PLL.PLLM=usb_clock_ready ? F407_BOOT_HSE_HZ/1000000UL : 16;
osc.PLL.PLLN=144; osc.PLL.PLLP=RCC_PLLP_DIV2; osc.PLL.PLLQ=3;
if (HAL_RCC_OscConfig(&osc)!=HAL_OK) board_fatal(3);
clk.ClockType=RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
clk.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;
clk.AHBCLKDivider=RCC_SYSCLK_DIV1;
clk.APB1CLKDivider=RCC_HCLK_DIV2; clk.APB2CLKDivider=RCC_HCLK_DIV1;
/* HAL задаёт два такта ожидания Flash и перестраивает SysTick для новой частоты CPU. */
if (HAL_RCC_ClockConfig(&clk,FLASH_LATENCY_2)!=HAL_OK) board_fatal(3);
}
void boot_protocol_init(void);
void boot_protocol_poll(uint32_t now);
int main(void) {
/* Jump from reset, before initializing USB, DMA, clocks or interrupts. */
bool requested=f407_boot_requested();
if(!requested && f407_app_valid()) f407_jump_app();
if(HAL_Init()!=HAL_OK) board_fatal(3);
peripheral_clock(); boot_protocol_init();
if(usb_clock_ready) usb_cdc_init();
for(;;) { uint32_t now=HAL_GetTick(); usb_cdc_poll(now); boot_protocol_poll(now); }
}