#include "main.h" #include "usb_device.h" #include "usbd_dfu_bootloader.h" typedef void (*ApplicationEntry)(void); static void Bootloader_SystemClockConfig(void); static void Bootloader_GPIOInit(void); static uint8_t Bootloader_IsApplicationValid(uint32_t address); static void Bootloader_JumpToApplication(uint32_t address); int main(void) { uint32_t selectedAddress = 0U; HAL_Init(); Bootloader_GPIOInit(); HAL_Delay(20U); /* Holding START during reset always forces USB DFU mode. */ if (HAL_GPIO_ReadPin(Start_GPIO_Port, Start_Pin) != GPIO_PIN_RESET) { GPIO_PinState pa4 = HAL_GPIO_ReadPin(DINPUT_GPIO_Port, DINPUT_Pin); GPIO_PinState pa5 = HAL_GPIO_ReadPin(XINPUT_GPIO_Port, XINPUT_Pin); /* Actual board wiring: PA4 LOW selects XInput, PA5 LOW selects DInput. */ if ((pa4 == GPIO_PIN_RESET) && (pa5 == GPIO_PIN_SET)) { selectedAddress = DFU_APP1_ADDRESS; } else if ((pa4 == GPIO_PIN_SET) && (pa5 == GPIO_PIN_RESET)) { selectedAddress = DFU_APP2_ADDRESS; } } if ((selectedAddress != 0U) && Bootloader_IsApplicationValid(selectedAddress)) { Bootloader_JumpToApplication(selectedAddress); } Bootloader_SystemClockConfig(); MX_USB_DEVICE_Init(); while (1) { } } static void Bootloader_GPIOInit(void) { GPIO_InitTypeDef gpio = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); gpio.Pin = DINPUT_Pin | XINPUT_Pin; gpio.Mode = GPIO_MODE_INPUT; gpio.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &gpio); gpio.Pin = Start_Pin; HAL_GPIO_Init(GPIOC, &gpio); } static uint8_t Bootloader_IsApplicationValid(uint32_t address) { uint32_t stackPointer = *(volatile uint32_t *)address; uint32_t resetHandler = *(volatile uint32_t *)(address + 4U); uint32_t slotEnd = address + DFU_APP_SLOT_SIZE; return ((stackPointer >= SRAM_BASE) && (stackPointer <= (SRAM_BASE + (20U * 1024U))) && ((resetHandler & 1U) != 0U) && ((resetHandler & ~1U) >= address) && ((resetHandler & ~1U) < slotEnd)) ? 1U : 0U; } static void Bootloader_JumpToApplication(uint32_t address) { uint32_t stackPointer = *(volatile uint32_t *)address; uint32_t resetHandler = *(volatile uint32_t *)(address + 4U); __disable_irq(); SysTick->CTRL = 0U; SysTick->LOAD = 0U; SysTick->VAL = 0U; HAL_DeInit(); NVIC->ICER[0] = 0xFFFFFFFFU; NVIC->ICER[1] = 0xFFFFFFFFU; NVIC->ICPR[0] = 0xFFFFFFFFU; NVIC->ICPR[1] = 0xFFFFFFFFU; SCB->VTOR = address; __DSB(); __ISB(); __enable_irq(); __asm volatile ( "msr msp, %0\n" "bx %1\n" : : "r" (stackPointer), "r" (resetHandler) : "memory"); while (1) { } } static void Bootloader_SystemClockConfig(void) { RCC_OscInitTypeDef oscillator = {0}; RCC_ClkInitTypeDef clocks = {0}; RCC_PeriphCLKInitTypeDef peripheral = {0}; oscillator.OscillatorType = RCC_OSCILLATORTYPE_HSE; oscillator.HSEState = RCC_HSE_ON; oscillator.HSEPredivValue = RCC_HSE_PREDIV_DIV1; oscillator.HSIState = RCC_HSI_ON; oscillator.PLL.PLLState = RCC_PLL_ON; oscillator.PLL.PLLSource = RCC_PLLSOURCE_HSE; oscillator.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&oscillator) != HAL_OK) { Error_Handler(); } clocks.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; clocks.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; clocks.AHBCLKDivider = RCC_SYSCLK_DIV1; clocks.APB1CLKDivider = RCC_HCLK_DIV2; clocks.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&clocks, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } peripheral.PeriphClockSelection = RCC_PERIPHCLK_USB; peripheral.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5; if (HAL_RCCEx_PeriphCLKConfig(&peripheral) != HAL_OK) { Error_Handler(); } } void Error_Handler(void) { __disable_irq(); while (1) { } }