#include "bl.h"
/* Simple function pointer type to call user program */
typedef void (*func_ptr)();
static void delay(uint32_t timeout) {
do __NOP(); while (--timeout);
}
static void USB_Renum() {
BB_BIT(GPIOA->CRH,16) = 1; // PA12: Open Drain Output
BB_BIT(GPIOA->ODR,12) = 0; // PA12 nach Low ziehen
delay(0x10000);
BB_BIT(GPIOA->ODR,12) = 1; // PA12 nach High freilassen
BB_BIT(GPIOA->CRH,16) = 0; // PA12: Eingang
}
#define SRAM_SIZE (20*1024) // 20 KiByte SRAM size
static bool check_user_code() {
uint32_t sp = *reinterpret_cast<uint32_t*>(USER_PROGRAM)-SRAM_BASE;
/* Check if the stack pointer in the vector table points somewhere in SRAM */
return sp <= SRAM_SIZE;
}
static uint16_t get_and_clear_magic_word() {
/* Enable the power and backup interface clocks by setting the
* PWREN and BKPEN bits in the RCC_APB1ENR register */
uint32_t save = RCC->APB1ENR;
RCC->APB1ENR = save | RCC_APB1ENR_BKPEN|RCC_APB1ENR_PWREN;
uint16_t value = BKP->DR4;
if (value) { /* Enable write access to the backup registers and the RTC. */
BB_BIT(PWR->CR,8) = 1;
BKP->DR4 = 0;
BB_BIT(PWR->CR,8) = 0;
}
RCC->APB1ENR = save;
return value;
}
void set_sysclock() { // hier: 48 MHz (24 MHz geht nicht)
BB_BIT(RCC->CR,16) = 1; // Enable High-Speed External Oscillator
while (!BB_BIT(RCC->CR,17)); // Wait until HSE is ready
BB_BIT(FLASH->ACR,0) = 1; // Enable Prefetch Buffer & set Flash access to 1 wait state
/* SYSCLK = PCLK2 = HCLK */
/* PCLK1 = HCLK / 2 */
/* PLLCLK = HSE * 6 = 48 MHz */
RCC->CFGR = 1<<22 | RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV2 |
RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6 | 0x80;
BB_BIT(RCC->CR,24) = 1; // Enable PLL
while (!BB_BIT(RCC->CR,25)) ; // Wait until PLL is ready
BB_BIT(RCC->CFGR,1) = 1; // Select PLL as system clock source
while (!BB_BIT(RCC->CFGR,3)) ; // Wait until PLL is used as system clock source
}
void revert_sysclock() {
BB_BIT(RCC->CFGR,1) = 0;
BB_BIT(RCC->CR,24) = 0;
RCC->CFGR = 0;
BB_BIT(FLASH->ACR,0) = 0;
BB_BIT(RCC->CR,16) = 0;
}
// Keep in mind that .bss is not zeroed out!
// Blöd (210917): Nach dem Flashen mit stm32flash.exe ist der Bootloader
// nicht bereit für hid-flash.exe. Nach Reset geht's aber. Nicht schlimm.
static void Reset_Handler() __attribute__((naked,noreturn));
static void Reset_Handler() {
uint32_t csr = RCC->CSR; // früh Reset-Ursache erfassen
RCC->CSR = 1<<24; // und Bits löschen
if (get_and_clear_magic_word() == 0x424C
|| csr & 1<<26 && !(csr & 1<<27)// Reset vom Taster: Bootloader aktivieren!
|| !check_user_code()) {
uint32_t cyclecounter = 0;
RCC->APB2ENR = 0x3C;
// set_sysclock();
LED_INIT;
UploadState = 0;
USB_Renum();
usb::init();
while (!(UploadState&4)) {
usb::poll(); // polling instead of interrupt
if (!UploadState&1) LED = ++cyclecounter>>13&1;
}
usb::shutdown(); /* Reset the USB */
// revert_sysclock();
RCC->APB2ENR = 0;
}
SCB->VTOR = USER_PROGRAM; // Setup the vector table to the user-defined one in Flash memory
asm volatile(
" msr msp,%0 \n" // setup stack pointer to the user-defined one
::"r"(*(uint32_t*)(USER_PROGRAM)));
asm volatile(
" mov r0,%0 \n" // pass reset reason in r0
" bx %1 \n" // jump to user code, LSB dictates ARM(0) or THUMB(1) mode
::"r"(csr),"r"(*(uint32_t*)(USER_PROGRAM+4)));
} // BUGBUG: Luckily, %1 is not r0, but I don't know how to restrict this.
/* Minimal Flash-based vector table */
func_ptr vectors[] __attribute__((section(".vectors"))) = {
reinterpret_cast<func_ptr>(SRAM_BASE+SRAM_SIZE), // Initial stack pointer (MSP)
Reset_Handler, // Initial program counter (PC): Reset handler
};
Detected encoding: UTF-8 | 0
|