Skip to content

Commit

Permalink
Merge pull request #820 from quartiq/feature/dfu-support
Browse files Browse the repository at this point in the history
Adding support for rebooting to DFU
  • Loading branch information
jordens authored Dec 1, 2023
2 parents 09c1d61 + 7e390dd commit 4b08d56
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 20 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased](https://github.com/quartiq/stabilizer/compare/v0.9.0...main)

### Added
* Serial terminal is available on USB for settings configurations
* Reboot to DFU support added via the serial terminal for remote bootloading

### Changed
* Broker is no longer configured at compile time, but is maintained in device memory

## [0.9.0](https://github.com/quartiq/stabilizer/compare/v0.8.1...v0.9.0)

### Fixed
Expand Down
30 changes: 19 additions & 11 deletions book/src/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,10 @@ docker run -p 1883:1883 --name mosquitto -v ${pwd}/mosquitto.conf:/mosquitto/con

Firmware can be loaded onto stabilizer using **one** of the three following methods.

> **Note:** All methods require access to the circuit board. Pulling the device from a
> crate always requires power removal as there are sensitive leads and components on
> both sides of the board that may come into contact with adjacent front panels.
> Every access to the board also requires proper ESD precautions. Never
> hot-plug the device or the probe.
> **Note:** Most methods below require access to the circuit board. Pulling the device from a crate
> always requires power removal as there are sensitive leads and components on both sides of the
> board that may come into contact with adjacent front panels. Every access to the board also
> requires proper ESD precautions. Never hot-plug the device or the probe.

### ST-Link virtual mass storage

Expand All @@ -124,15 +123,24 @@ and applying power again.

### DFU Upload

If an SWD/JTAG probe is not available,
you can flash firmware using only a micro USB cable
plugged in to the front of Stabilizer, a DFU utility, and a jumper to activate
the bootloader.
If an SWD/JTAG probe is not available, you can flash firmware using only a micro USB cable plugged
in to the front of Stabilizer, and a DFU utility.

> **Note:** If there is already newer firmware running on Stabilizer that supports the USB serial
> interface, there is no need to remove Stabilizer from the crate or disconnect any existing
> connectors/power supplies or to jumper the BOOT0 pin. Instead, open the serial port on Stabilizer
> and request it to enter DFU mode:
> ```bash
> python -m serial <serial-port>
> > platform dfu
> ```
>
> After the device is in DFU mode, use the `dfu-util` command specified in the instructions below,
> and the DFU firmware update will be complete.

1. Install the DFU USB tool [`dfu-util`](http://dfu-util.sourceforge.net)
1. Remove power
1. Then carefully remove the module from the crate to gain
access to the board
1. Then carefully remove the module from the crate to gain acccess to the board
1. Short JC2/BOOT with the jumper
1. Connect your computer to the Micro USB connector below/left of the RJ45
connector on the front panel
Expand Down
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
14 changes: 9 additions & 5 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,12 +127,15 @@ impl serial_settings::Platform for SerialSettingsPlatform {
fn cmd(&mut self, cmd: &str) {
match cmd {
"reboot" => cortex_m::peripheral::SCB::sys_reset(),
_ => writeln!(
self.interface_mut(),
"Invalid platform command `{cmd}`"
),
"dfu" => platform::start_dfu_reboot(),
_ => {
writeln!(
self.interface_mut(),
"Invalid platform command: `{cmd}` not in [`dfu`, `reboot`]"
)
.ok();
}
}
.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
77 changes: 77 additions & 0 deletions src/hardware/platform.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/// Flag used to indicate that a reboot to DFU is requested.
const DFU_REBOOT_FLAG: u32 = 0xDEAD_BEEF;

/// 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>(), DFU_REBOOT_FLAG);
}

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 = DFU_REBOOT_FLAG
== 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);
}
}
7 changes: 6 additions & 1 deletion 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 @@ -248,6 +248,11 @@ pub fn setup(
log::info!("Starting");
}

// 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 4b08d56

Please sign in to comment.