From b975570dc0df5ac876e691941d76a20fa0a6c41c Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Fri, 1 Dec 2023 12:28:45 +0100 Subject: [PATCH] Updating DFU reboot mechanism --- memory.x | 5 +- src/hardware/flash.rs | 198 ++------------------------------------- src/hardware/mod.rs | 4 +- src/hardware/platform.rs | 74 +++++++++++++++ src/hardware/setup.rs | 9 +- 5 files changed, 94 insertions(+), 196 deletions(-) create mode 100644 src/hardware/platform.rs diff --git a/memory.x b/memory.x index 02afe9eba..ff76fc918 100644 --- a/memory.x +++ b/memory.x @@ -1,7 +1,7 @@ MEMORY { ITCM (rwx) : ORIGIN = 0x00000000, LENGTH = 64K - RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 127K AXISRAM (rwx) : ORIGIN = 0x24000000, LENGTH = 512K SRAM1 (rwx) : ORIGIN = 0x30000000, LENGTH = 128K SRAM2 (rwx) : ORIGIN = 0x30020000, LENGTH = 128K @@ -10,8 +10,11 @@ MEMORY RAM_B (rwx) : ORIGIN = 0x38800000, LENGTH = 4K FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K FLASH1 (rx) : ORIGIN = 0x08100000, LENGTH = 1024K + BOOTFLAG_RAM: ORIGIN = 0x2001FC00, LENGTH = 1K } +_bootflag = ORIGIN(BOOTFLAG_RAM); + SECTIONS { .axisram (NOLOAD) : ALIGN(8) { *(.axisram .axisram.*); diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs index dff581682..c76bdb2ad 100644 --- a/src/hardware/flash.rs +++ b/src/hardware/flash.rs @@ -1,3 +1,4 @@ +use crate::hardware::platform; use core::fmt::Write; use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use stm32h7xx_hal::flash::LockedFlashBank; @@ -126,198 +127,15 @@ impl serial_settings::Platform for SerialSettingsPlatform { fn cmd(&mut self, cmd: &str) { match cmd { "reboot" => cortex_m::peripheral::SCB::sys_reset(), - - "dfu" => { - // This process is largely adapted from - // https://community.st.com/t5/stm32-mcus/jump-to-bootloader-from-application-on-stm32h7-devices/ta-p/49510 - cortex_m::interrupt::disable(); - - // Disable the SysTick peripheral. - let systick = unsafe { &*cortex_m::peripheral::SYST::PTR }; - unsafe { - systick.csr.write(0); - systick.rvr.write(0); - systick.cvr.write(0); - } - - // Disable the USB peripheral. - let usb_otg = - unsafe { &*stm32h7xx_hal::stm32::OTG2_HS_GLOBAL::ptr() }; - usb_otg.gccfg.write(|w| unsafe { w.bits(0) }); - - // Reset the RCC configuration. - let rcc = unsafe { &*stm32h7xx_hal::stm32::RCC::ptr() }; - - // Enable the HSI - we will be switching back to it shortly for the DFU bootloader. - rcc.cr.modify(|_, w| w.hsion().set_bit()); - - // Wait for the HSI to enable - while !rcc.cr.read().hsirdy().is_ready() {} - - // Reset the CFGR and begin using the HSI for the system bus. - rcc.cfgr.reset(); - - // Wait for the HSI to become the active clock. - while !rcc.cfgr.read().sws().is_hsi() {} - - // Reset the configuration register. - rcc.cr.reset(); - - // Wait for the HSE to disable - while rcc.cr.read().hserdy().is_ready() {} - - // Wait for the PLLs to disable - while rcc.cr.read().pll1rdy().is_ready() {} - while rcc.cr.read().pll2rdy().is_ready() {} - while rcc.cr.read().pll3rdy().is_ready() {} - - rcc.d1cfgr.reset(); - rcc.d2cfgr.reset(); - rcc.d3cfgr.reset(); - - // Reset the PLL configuration now that PLLs are unused. - rcc.pllckselr.reset(); - rcc.pllcfgr.reset(); - rcc.pll1divr.reset(); - rcc.pll1fracr.reset(); - rcc.pll2divr.reset(); - rcc.pll2fracr.reset(); - rcc.pll3divr.reset(); - rcc.pll3fracr.reset(); - - // Disable all RCC interrupts. - rcc.cier.reset(); - - // Clear all RCC interrupt flags - unsafe { rcc.cicr.write(|w| w.bits(u32::MAX)) }; - - rcc.rsr.write(|w| w.rmvf().set_bit()); - - // Reset peripherals using the RCC. - rcc.ahb1rstr.write(|w| w.usb2otgrst().set_bit()); - rcc.apb1lrstr.write(|w| { - w.i2c2rst() - .set_bit() - .i2c1rst() - .set_bit() - .spi2rst() - .set_bit() - .spi3rst() - .set_bit() - }); - rcc.apb2rstr.write(|w| { - w.spi1rst() - .set_bit() - .spi4rst() - .set_bit() - .spi5rst() - .set_bit() - }); - rcc.apb4rstr.write(|w| w.spi6rst().set_bit()); - - // Reset DMA and ETH - rcc.ahb1rstr.write(|w| { - w.dma1rst() - .set_bit() - .dma2rst() - .set_bit() - .eth1macrst() - .set_bit() - }); - - // Reset GPIO peripherals - rcc.ahb4rstr.write(|w| { - w.gpioarst() - .set_bit() - .gpiobrst() - .set_bit() - .gpiocrst() - .set_bit() - .gpiodrst() - .set_bit() - .gpioerst() - .set_bit() - .gpiofrst() - .set_bit() - .gpiogrst() - .set_bit() - }); - - // Reset TIM2, TIM3, and TIM5 - rcc.apb1lrstr.write(|w| { - w.tim2rst() - .set_bit() - .tim3rst() - .set_bit() - .tim5rst() - .set_bit() - }); - - // Reset clocking registers - rcc.d2ccip1r.reset(); - rcc.d1ccipr.reset(); - rcc.d3ccipr.reset(); - - rcc.ahb1enr.reset(); - rcc.ahb2enr.reset(); - rcc.ahb3enr.reset(); - rcc.ahb4enr.reset(); - - rcc.apb1lenr.reset(); - rcc.apb1henr.reset(); - rcc.apb2enr.reset(); - rcc.apb3enr.reset(); - rcc.apb4enr.reset(); - rcc.ahb1lpenr.reset(); - rcc.ahb2lpenr.reset(); - rcc.ahb3lpenr.reset(); - rcc.ahb4lpenr.reset(); - - rcc.apb1llpenr.reset(); - rcc.apb1hlpenr.reset(); - rcc.apb2lpenr.reset(); - rcc.apb3lpenr.reset(); - rcc.apb4lpenr.reset(); - - // Reset the PWR register. - let pwr = unsafe { &*stm32h7xx_hal::stm32::PWR::ptr() }; - pwr.cr1.reset(); - pwr.cr2.reset(); - pwr.cr3.reset(); - pwr.d3cr.reset(); - pwr.cpucr.reset(); - - // Clear NVIC interrupt flags and enables. - let nvic = unsafe { &*cortex_m::peripheral::NVIC::PTR }; - for reg in nvic.icer.iter() { - unsafe { - reg.write(u32::MAX); - } - } - - for reg in nvic.icpr.iter() { - unsafe { - reg.write(u32::MAX); - } - } - - unsafe { cortex_m::interrupt::enable() }; - - // The chip does not provide a means to modify the BOOT pins during - // run-time. Jump to the bootloader in system memory instead. - unsafe { - let system_memory_address: *const u32 = - 0x1FF0_9800 as *const u32; - log::info!("Jumping to DFU"); - cortex_m::asm::bootload(system_memory_address); - } + "dfu" => platform::start_dfu_reboot(), + _ => { + writeln!( + self.interface_mut(), + "Invalid platform command `{cmd}`" + ) + .ok(); } - _ => writeln!( - self.interface_mut(), - "Invalid platform command `{cmd}`" - ), } - .ok(); } fn settings(&self) -> &Self::Settings { diff --git a/src/hardware/mod.rs b/src/hardware/mod.rs index bc51a9fef..a9683f249 100644 --- a/src/hardware/mod.rs +++ b/src/hardware/mod.rs @@ -9,16 +9,16 @@ pub mod cpu_temp_sensor; pub mod dac; pub mod delay; pub mod design_parameters; +mod eeprom; pub mod flash; pub mod input_stamper; +pub mod platform; pub mod pounder; pub mod setup; pub mod shared_adc; pub mod signal_generator; pub mod timers; -mod eeprom; - // Type alias for the analog front-end (AFE) for ADC0. pub type AFE0 = afe::ProgrammableGainAmplifier< hal::gpio::gpiof::PF2>, diff --git a/src/hardware/platform.rs b/src/hardware/platform.rs new file mode 100644 index 000000000..8a6580b61 --- /dev/null +++ b/src/hardware/platform.rs @@ -0,0 +1,74 @@ +/// Indicate a reboot to DFU is requested. +pub fn start_dfu_reboot() { + extern "C" { + static mut _bootflag: u8; + } + + unsafe { + let start_ptr = &mut _bootflag as *mut u8; + core::ptr::write_unaligned(start_ptr.cast::(), 0xDEAD_BEEF); + } + + cortex_m::peripheral::SCB::sys_reset(); +} + +/// Check if the DFU reboot flag is set, indicating a reboot to DFU is requested. +pub fn dfu_bootflag() -> bool { + // Obtain panic region start and end from linker symbol _panic_dump_start and _panic_dump_end + extern "C" { + static mut _bootflag: u8; + } + + unsafe { + let start_ptr = &mut _bootflag as *mut u8; + let set = + 0xDEAD_BEEF == core::ptr::read_unaligned(start_ptr.cast::()); + + // Clear the boot flag after checking it to ensure it doesn't stick between reboots. + core::ptr::write_unaligned(start_ptr.cast::(), 0); + set + } +} + +/// Execute the DFU bootloader stored in system memory. +/// +/// # Note +/// This function must be called before any system configuration is performed, as the DFU +/// bootloader expects the system in an uninitialized state. +pub fn execute_system_bootloader() { + // This process is largely adapted from + // https://community.st.com/t5/stm32-mcus/jump-to-bootloader-from-application-on-stm32h7-devices/ta-p/49510 + cortex_m::interrupt::disable(); + + // Disable the SysTick peripheral. + let systick = unsafe { &*cortex_m::peripheral::SYST::PTR }; + unsafe { + systick.csr.write(0); + systick.rvr.write(0); + systick.cvr.write(0); + } + + // Clear NVIC interrupt flags and enables. + let nvic = unsafe { &*cortex_m::peripheral::NVIC::PTR }; + for reg in nvic.icer.iter() { + unsafe { + reg.write(u32::MAX); + } + } + + for reg in nvic.icpr.iter() { + unsafe { + reg.write(u32::MAX); + } + } + + unsafe { cortex_m::interrupt::enable() }; + + // The chip does not provide a means to modify the BOOT pins during + // run-time. Jump to the bootloader in system memory instead. + unsafe { + let system_memory_address: *const u32 = 0x1FF0_9800 as *const u32; + log::info!("Jumping to DFU"); + cortex_m::asm::bootload(system_memory_address); + } +} diff --git a/src/hardware/setup.rs b/src/hardware/setup.rs index 0ec174515..f10fa7226 100644 --- a/src/hardware/setup.rs +++ b/src/hardware/setup.rs @@ -14,7 +14,7 @@ use smoltcp_nal::smoltcp; use super::{ adc, afe, cpu_temp_sensor::CpuTempSensor, dac, delay, design_parameters, - eeprom, input_stamper::InputStamper, pounder, + eeprom, input_stamper::InputStamper, platform, pounder, pounder::dds_output::DdsOutput, shared_adc::SharedAdc, timers, DigitalInput0, DigitalInput1, EemDigitalInput0, EemDigitalInput1, EemDigitalOutput0, EemDigitalOutput1, EthernetPhy, NetworkStack, @@ -247,8 +247,11 @@ pub fn setup( .unwrap(); log::info!("Starting"); } - const DFU_VER: *const u8 = 0x1FF1E7FE as _; - unsafe { log::info!("DFU version: {:x}", *DFU_VER) }; + + // Check for a reboot to DFU before doing any system configuration. + if platform::dfu_bootflag() { + platform::execute_system_bootloader(); + } let pwr = device.PWR.constrain(); let vos = pwr.freeze();