Triggering the dfu bootloader works

This commit is contained in:
Sebastian 2024-10-03 22:54:05 +02:00
parent 8cf75ac70d
commit 1c4714381b
9 changed files with 235 additions and 33 deletions

View file

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# TODO(2) replace `$CHIP` with your chip's name (see `probe-run --list-chips` output)
runner = "probe-run --chip STM32F401CCU6"
runner = "probe-rs run --chip STM32F401CCUx"
rustflags = [
"-C", "linker=flip-link",
"-C", "link-arg=-Tlink.x",

View file

@ -0,0 +1,59 @@
use core::ptr::addr_of_mut;
use stm32f4xx_hal::pac;
fn jump_to_bootloader() {
unsafe {
cortex_m::interrupt::disable();
let address: u32 = 0x1FFF0000;
let device = pac::Peripherals::steal();
device.SYSCFG.memrm.modify(|_, w| w.bits(0x01));
let mut p = cortex_m::Peripherals::steal();
p.SCB.invalidate_icache();
p.SCB.vtor.write(address as u32);
cortex_m::interrupt::enable();
cortex_m::asm::bootload(address as *const u32);
}
}
const BOOTLOADER_REQUESTED: u32 = 0xdecafbad;
fn magic_mut_ptr() -> *mut u32 {
extern "C" {
#[link_name = "_dfu_magic"]
static mut magic: u32;
}
unsafe { addr_of_mut!(magic) }
}
fn get_bootloader_flag() -> u32 {
unsafe { magic_mut_ptr().read_volatile() }
}
fn set_bootloader_flag() {
unsafe { magic_mut_ptr().write_volatile(BOOTLOADER_REQUESTED) };
}
fn clear_bootloader_flag() {
unsafe { magic_mut_ptr().write_volatile(BOOTLOADER_REQUESTED) };
}
pub fn init() {
let requested = get_bootloader_flag() == BOOTLOADER_REQUESTED;
if requested {
clear_bootloader_flag();
jump_to_bootloader();
}
}
pub fn reboot_to_bootloader() -> ! {
defmt::info!("Rebooting into the bootloader");
set_bootloader_flag();
cortex_m::peripheral::SCB::sys_reset();
}

View file

@ -6,6 +6,8 @@ use defmt_brtt as _; // global logger
use panic_probe as _;
use stm32f4xx_hal as _;
mod bootloader;
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
#[defmt::panic_handler]
@ -21,7 +23,9 @@ mod app {
use as5048a::AS5048A;
use heapless::Vec;
use core::fmt::Write;
use heapless::{String, Vec};
use num_traits::{Float, FloatConst};
use postcard::{from_bytes_cobs, to_vec_cobs};
use stm32f4xx_hal::{
gpio::{gpioa, gpiob, gpioc, Output, PushPull},
@ -29,20 +33,19 @@ mod app {
otg_fs::{UsbBus, UsbBusType, USB},
pac::{I2C1, SPI1},
prelude::*,
spi,
signature, spi,
};
use usb_device::class_prelude::UsbBusAllocator;
use usb_device::prelude::*;
use usb_device::{class_prelude::UsbBusAllocator, device};
use usbd_serial::SerialPort;
use num_traits::{Float, FloatConst};
use xca9548a::{SlaveAddr, Xca9548a};
use qmc5883l::{self, QMC5883L};
use radomctl_protocol::*;
use crate::bootloader;
use rtic_monotonics::systick::prelude::*;
systick_monotonic!(Mono, 4000);
@ -83,6 +86,8 @@ mod app {
#[init]
fn init(cx: init::Context) -> (Shared, Local) {
bootloader::init();
defmt::info!("init");
let rcc = cx.device.RCC.constrain();
@ -92,11 +97,8 @@ mod app {
let clocks = rcc
.cfgr
.use_hse(25.MHz())
.require_pll48clk()
.sysclk(84.MHz())
.hclk(84.MHz())
.pclk1(42.MHz())
.pclk2(84.MHz())
.require_pll48clk()
.freeze();
Mono::start(cx.core.SYST, clocks.sysclk().to_Hz());
@ -131,16 +133,23 @@ mod app {
let usb_serial = usbd_serial::SerialPort::new(unsafe { USB_BUS.as_ref().unwrap() });
let usb_dev = UsbDeviceBuilder::new(
unsafe { USB_BUS.as_ref().unwrap() },
UsbVidPid(0x16c0, 0x27dd),
)
.device_class(usbd_serial::USB_CLASS_CDC)
.strings(&[StringDescriptors::default()
.manufacturer("Amteurfunk Forschungs Gruppe")
.product("Radom Controler")])
.unwrap()
.build();
let uid = signature::Uid::get();
static mut SERIAL: String<16> = String::new();
unsafe {
write!(SERIAL, "{}{:x}{:x}", uid.lot_num(), uid.x(), uid.y()).unwrap();
}
let usb_dev = unsafe {
UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0x16c0, 0x27dd))
.device_class(usbd_serial::USB_CLASS_CDC)
.strings(&[StringDescriptors::default()
.manufacturer("Amteurfunk Forschungs Gruppe")
.product("Radom Controler")
.serial_number(SERIAL.as_ref())])
.unwrap()
.build()
};
defmt::info!("USB Setup done");
@ -416,9 +425,11 @@ mod app {
to_vec_cobs::<RadomMessage, USB_BUFFER_SIZE>(&device_msg).unwrap();
serial.write(bytes.as_slice()).unwrap();
}
HostMessage::TriggerDFUBootloader => todo!(),
HostMessage::TriggerDFUBootloader => {
bootloader::reboot_to_bootloader();
}
},
Err(err) => defmt::error!("Unable to parse host message: {}", err),
Err(err) => defmt::error!("Unable to parse host message"),
};
*buffer = Vec::<u8, USB_BUFFER_SIZE>::from_slice(rest).unwrap();