forked from M-Labs/thermostat
49 lines
1.3 KiB
Rust
49 lines
1.3 KiB
Rust
|
use cortex_m_rt::{pre_init};
|
||
|
|
||
|
const DFU_TRIG_MSG: u32 = 0xDECAFBAD;
|
||
|
|
||
|
extern "C" {
|
||
|
// This symbol comes from memory.x
|
||
|
static mut _dfu_msg: u32;
|
||
|
}
|
||
|
|
||
|
pub unsafe fn set_dfu_trigger() {
|
||
|
_dfu_msg = DFU_TRIG_MSG;
|
||
|
}
|
||
|
|
||
|
/// Called by reset handler in lib.rs immediately after reset.
|
||
|
/// This function should not be called outside of reset handler as
|
||
|
/// bootloader expects MCU to be in reset state when called.
|
||
|
#[pre_init]
|
||
|
unsafe fn __pre_init() {
|
||
|
if _dfu_msg == DFU_TRIG_MSG {
|
||
|
_dfu_msg = 0x00000000;
|
||
|
|
||
|
// Enable system config controller clock
|
||
|
const RCC_APB2ENR: *mut u32 = 0xE000_ED88 as *mut u32;
|
||
|
const RCC_APB2ENR_ENABLE_SYSCFG_CLOCK: u32 = 0x00004000;
|
||
|
|
||
|
core::ptr::write_volatile(
|
||
|
RCC_APB2ENR,
|
||
|
*RCC_APB2ENR | RCC_APB2ENR_ENABLE_SYSCFG_CLOCK,
|
||
|
);
|
||
|
|
||
|
// Bypass BOOT pins and remap bootloader to 0x00000000
|
||
|
const SYSCFG_MEMRMP: *mut u32 = 0x40013800 as *mut u32;
|
||
|
const SYSCFG_MEMRMP_MAP_ROM: u32 = 0x00000001;
|
||
|
|
||
|
core::ptr::write_volatile(
|
||
|
SYSCFG_MEMRMP,
|
||
|
*SYSCFG_MEMRMP | SYSCFG_MEMRMP_MAP_ROM,
|
||
|
);
|
||
|
|
||
|
asm!(
|
||
|
// Set stack pointer to bootloader location
|
||
|
"LDR R0, =0x1FFF0000",
|
||
|
"LDR SP,[R0, #0]",
|
||
|
// Jump to bootloader
|
||
|
"LDR R0,[R0, #4]",
|
||
|
"BX R0",
|
||
|
);
|
||
|
}
|
||
|
}
|