Skip to content

Commit

Permalink
Updating DFU reboot mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
ryan-summers committed Dec 1, 2023
1 parent 20faaad commit b975570
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 196 deletions.
5 changes: 4 additions & 1 deletion memory.x
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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.*);
Expand Down
198 changes: 8 additions & 190 deletions src/hardware/flash.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::hardware::platform;
use core::fmt::Write;
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
use stm32h7xx_hal::flash::LockedFlashBank;
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/hardware/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<hal::gpio::Output<hal::gpio::PushPull>>,
Expand Down
74 changes: 74 additions & 0 deletions src/hardware/platform.rs
Original file line number Diff line number Diff line change
@@ -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::<u32>(), 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::<u32>());

// Clear the boot flag after checking it to ensure it doesn't stick between reboots.
core::ptr::write_unaligned(start_ptr.cast::<u32>(), 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);
}
}
9 changes: 6 additions & 3 deletions src/hardware/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit b975570

Please sign in to comment.