stabilizer/hardware/
platform.rs

1/// Flag used to indicate that a reboot to DFU is requested.
2const DFU_REBOOT_FLAG: u32 = 0xDEAD_BEEF;
3
4extern "C" {
5    static mut _bootflag: u8;
6}
7
8/// Indicate a reboot to DFU is requested.
9pub fn start_dfu_reboot() {
10    unsafe {
11        core::ptr::write_unaligned(
12            core::ptr::addr_of_mut!(_bootflag).cast(),
13            DFU_REBOOT_FLAG,
14        );
15    }
16
17    cortex_m::peripheral::SCB::sys_reset();
18}
19
20/// Check if the DFU reboot flag is set, indicating a reboot to DFU is requested.
21pub fn dfu_bootflag() -> bool {
22    unsafe {
23        let start_ptr = core::ptr::addr_of_mut!(_bootflag).cast();
24        let set = DFU_REBOOT_FLAG == core::ptr::read_unaligned(start_ptr);
25
26        // Clear the boot flag after checking it to ensure it doesn't stick between reboots.
27        core::ptr::write_unaligned(start_ptr, 0);
28        set
29    }
30}
31
32/// Execute the DFU bootloader stored in system memory.
33///
34/// # Note
35/// This function must be called before any system configuration is performed, as the DFU
36/// bootloader expects the system in an uninitialized state.
37pub fn execute_system_bootloader() {
38    // This process is largely adapted from
39    // https://community.st.com/t5/stm32-mcus/jump-to-bootloader-from-application-on-stm32h7-devices/ta-p/49510
40    cortex_m::interrupt::disable();
41
42    // Disable the SysTick peripheral.
43    let systick = unsafe { &*cortex_m::peripheral::SYST::PTR };
44    unsafe {
45        systick.csr.write(0);
46        systick.rvr.write(0);
47        systick.cvr.write(0);
48    }
49
50    // Clear NVIC interrupt flags and enables.
51    let nvic = unsafe { &*cortex_m::peripheral::NVIC::PTR };
52    for reg in nvic.icer.iter() {
53        unsafe {
54            reg.write(u32::MAX);
55        }
56    }
57
58    for reg in nvic.icpr.iter() {
59        unsafe {
60            reg.write(u32::MAX);
61        }
62    }
63
64    unsafe { cortex_m::interrupt::enable() };
65
66    // The chip does not provide a means to modify the BOOT pins during
67    // run-time. Jump to the bootloader in system memory instead.
68    unsafe {
69        let system_memory_address: *const u32 = 0x1FF0_9800 as *const u32;
70        log::info!("Jumping to DFU");
71        cortex_m::asm::bootload(system_memory_address);
72    }
73}