add command to reboot into DFU

Co-Authored-By: topquark12 <aw@m-labs.hk>
Co-Committed-By: topquark12 <aw@m-labs.hk>
This commit is contained in:
topquark12 2021-01-13 11:59:06 +08:00 committed by sb10q
parent 9e4d06fdbc
commit f6802635a4
5 changed files with 68 additions and 3 deletions

View File

@ -124,6 +124,7 @@ formatted as line-delimited JSON.
| `load [0/1]` | Restore configuration for channel all/0/1 from flash |
| `save [0/1]` | Save configuration for channel all/0/1 to flash |
| `reset` | Reset the device |
| `dfu` | Reset device and enters USB device firmware update (DFU) mode |
| `ipv4 <X.X.X.X/L> [Y.Y.Y.Y]` | Configure IPv4 address, netmask length, and optional default gateway |

View File

@ -3,10 +3,13 @@ MEMORY
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
/* reserved for config data */
CONFIG (rx) : ORIGIN = 0x8100000, LENGTH = 16K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 112K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 112K - 4
/* reserved for DFU trigger message */
DFU_MSG (wrx) : ORIGIN = 0x2001BFFC, LENGTH = 4
RAM2 (xrw) : ORIGIN = 0x2001C000, LENGTH = 16K
RAM3 (xrw) : ORIGIN = 0x20020000, LENGTH = 64K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
_stack_start = ORIGIN(CCMRAM) + LENGTH(CCMRAM);
_dfu_msg = ORIGIN(DFU_MSG);

View File

@ -179,6 +179,7 @@ pub enum Command {
channel: usize,
rate: Option<f32>,
},
Dfu,
}
fn end(input: &[u8]) -> IResult<&[u8], ()> {
@ -535,6 +536,7 @@ fn command(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
pid,
steinhart_hart,
postfilter,
value(Ok(Command::Dfu), tag("dfu")),
))(input)
}

49
src/dfu.rs Normal file
View File

@ -0,0 +1,49 @@
use cortex_m_rt::{pre_init};
const DFU_TRIG_MSG: u32 = 0xDECAFBAD;
extern "C" {
// This symbol comes from memory.x
static mut _dfu_msg: u32;
}
pub unsafe fn set_dfu_trigger() {
_dfu_msg = DFU_TRIG_MSG;
}
/// Called by reset handler in lib.rs immediately after reset.
/// This function should not be called outside of reset handler as
/// bootloader expects MCU to be in reset state when called.
#[pre_init]
unsafe fn __pre_init() {
if _dfu_msg == DFU_TRIG_MSG {
_dfu_msg = 0x00000000;
// Enable system config controller clock
const RCC_APB2ENR: *mut u32 = 0xE000_ED88 as *mut u32;
const RCC_APB2ENR_ENABLE_SYSCFG_CLOCK: u32 = 0x00004000;
core::ptr::write_volatile(
RCC_APB2ENR,
*RCC_APB2ENR | RCC_APB2ENR_ENABLE_SYSCFG_CLOCK,
);
// Bypass BOOT pins and remap bootloader to 0x00000000
const SYSCFG_MEMRMP: *mut u32 = 0x40013800 as *mut u32;
const SYSCFG_MEMRMP_MAP_ROM: u32 = 0x00000001;
core::ptr::write_volatile(
SYSCFG_MEMRMP,
*SYSCFG_MEMRMP | SYSCFG_MEMRMP_MAP_ROM,
);
asm!(
// Set stack pointer to bootloader location
"LDR R0, =0x1FFF0000",
"LDR SP,[R0, #0]",
// Jump to bootloader
"LDR R0,[R0, #4]",
"BX R0",
);
}
}

View File

@ -1,6 +1,6 @@
#![cfg_attr(not(test), no_std)]
#![cfg_attr(not(test), no_main)]
#![feature(maybe_uninit_extra, maybe_uninit_ref)]
#![feature(maybe_uninit_extra, maybe_uninit_ref, asm)]
#![cfg_attr(test, allow(unused))]
// TODO: #![deny(warnings, unused)]
@ -66,6 +66,7 @@ mod channel_state;
mod config;
use config::ChannelConfig;
mod flash_store;
mod dfu;
const HSE: MegaHertz = MegaHertz(8);
#[cfg(not(feature = "semihosting"))]
@ -77,7 +78,6 @@ const CHANNEL_CONFIG_KEY: [&str; 2] = ["ch0", "ch1"];
const TCP_PORT: u16 = 23;
fn send_line(socket: &mut TcpSocket, data: &[u8]) -> bool {
let send_free = socket.send_capacity() - socket.send_queue();
if data.len() > send_free + 1 {
@ -422,6 +422,16 @@ fn main() -> ! {
channels.power_down(i);
}
SCB::sys_reset();
}
Command::Dfu => {
for i in 0..CHANNELS {
channels.power_down(i);
}
unsafe {
dfu::set_dfu_trigger();
}
SCB::sys_reset();
}
}