Skip to content

Commit 2704ad6

Browse files
committed
implement undocumented system erase and write
1 parent 887c5d3 commit 2704ad6

4 files changed

Lines changed: 89 additions & 11 deletions

File tree

algos/v3/src/bin/sys.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ algorithm!(Algo, {
1818
program_time_out: PROGRAM_TIMEOUT_MS,
1919
erase_time_out: ERASE_TIMEOUT_MS,
2020
sectors: [{
21-
size: SYS_PAGE_SIZE,
21+
size: SYS_ERASE_SIZE,
2222
address: SYS_BASE,
2323
}]
2424
});
@@ -34,12 +34,12 @@ impl FlashAlgorithm for Algo {
3434
}
3535

3636
fn erase_sector(&mut self, addr: u32) -> Result<(), ErrorCode> {
37-
fast_page_erase(addr, SYS_PAGE_SIZE);
37+
boot_page_erase(addr);
3838
Ok(())
3939
}
4040

4141
fn program_page(&mut self, addr: u32, data: &[u8]) -> Result<(), ErrorCode> {
42-
fast_page_program(addr, data, SYS_PAGE_SIZE, SYS_LOAD);
42+
boot_page_program(addr, data, SYS_LOAD);
4343
Ok(())
4444
}
4545
}

algos/v3/src/lib.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub const SYS_BASE: u32 = region("SYS_1").address;
1111
const SYS_FAST: (u32, u32) = fast(region("SYS_1"));
1212
pub const SYS_PAGE_SIZE: u32 = SYS_FAST.0;
1313
pub const SYS_LOAD: u32 = SYS_FAST.1;
14+
const SYS_STD: (u32, u32) = standard(region("SYS_1"));
15+
pub const SYS_ERASE_SIZE: u32 = SYS_STD.0;
1416

1517
pub const OPT_BASE: u32 = region("OPT").address;
1618
const OPT_STD: (u32, u32) = standard(region("OPT"));
@@ -78,6 +80,50 @@ pub fn fast_page_program(addr: u32, data: &[u8], _page_size: u32, load_size: u32
7880
FLASH.ctlr().modify(|w| w.set_page_pg(false));
7981
}
8082

83+
/// SYS uses standard PER (4 KB) + BTER; FTER silently no-ops on this region.
84+
pub fn boot_page_erase(addr: u32) {
85+
wait_busy();
86+
FLASH.ctlr().modify(|w| {
87+
w.set_per(true);
88+
w.set_bter(true);
89+
});
90+
FLASH.addr().write(|w| w.set_far(addr));
91+
FLASH.ctlr().modify(|w| w.set_strt(true));
92+
wait_busy();
93+
FLASH.ctlr().modify(|w| {
94+
w.set_per(false);
95+
w.set_bter(false);
96+
});
97+
}
98+
99+
/// `fast_page_program` with BTPG OR-ed in; without it the word write to
100+
/// 0x1FFF8000 faults and WR_BSY never clears.
101+
pub fn boot_page_program(addr: u32, data: &[u8], load_size: u32) {
102+
wait_busy();
103+
FLASH.ctlr().modify(|w| {
104+
w.set_page_pg(true);
105+
w.set_btpg(true);
106+
});
107+
108+
let mut cur = addr;
109+
let mut src = data.as_ptr() as *const u32;
110+
let words = data.len() as u32 / load_size;
111+
for _ in 0..words {
112+
let v = unsafe { src.read() };
113+
unsafe { core::ptr::write_volatile(cur as *mut u32, v) };
114+
wait_wr_busy();
115+
cur += load_size;
116+
src = unsafe { src.add(1) };
117+
}
118+
119+
FLASH.ctlr().modify(|w| w.set_pgstart(true));
120+
wait_busy();
121+
FLASH.ctlr().modify(|w| {
122+
w.set_page_pg(false);
123+
w.set_btpg(false);
124+
});
125+
}
126+
81127
pub fn mass_erase() {
82128
wait_busy();
83129
FLASH.ctlr().modify(|w| w.set_mer(true));

xtask/src/algo.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use anyhow::{Context, Result, anyhow, bail};
2-
use probe_rs_target::{FlashProperties, RawFlashAlgorithm};
2+
use probe_rs_target::{FlashProperties, RawFlashAlgorithm, SectorDescription};
33
use std::collections::HashMap;
44
use std::path::Path;
55
use std::process::Command;
@@ -243,7 +243,14 @@ fn extract_algo(buf: &[u8]) -> Result<RawFlashAlgorithm> {
243243
erased_byte_value: dev.erased,
244244
program_page_timeout: dev.program_to,
245245
erase_sector_timeout: dev.erase_to,
246-
sectors: Vec::new(),
246+
sectors: dev
247+
.sectors
248+
.iter()
249+
.map(|(size, address)| SectorDescription {
250+
size: *size as u64,
251+
address: *address as u64,
252+
})
253+
.collect(),
247254
};
248255
// probe-rs schema default (Rust default for u64 is 0).
249256
algo.rtt_poll_interval = 20;
@@ -257,28 +264,44 @@ struct FlashDevice {
257264
erased: u8,
258265
program_to: u32,
259266
erase_to: u32,
267+
sectors: Vec<(u32, u32)>,
260268
}
261269

262270
fn read_flash_device(elf: &goblin::elf::Elf<'_>, buf: &[u8]) -> Result<FlashDevice> {
263271
use scroll::Pread;
264272
let mut addr = None;
273+
let mut sym_size = 0u32;
265274
for s in elf.syms.iter() {
266275
if &elf.strtab[s.st_name] == "FlashDevice" {
267276
addr = Some(s.st_value as u32);
277+
sym_size = s.st_size as u32;
268278
break;
269279
}
270280
}
271281
let addr = addr.ok_or_else(|| anyhow!("ELF missing FlashDevice symbol"))?;
272282

273-
let bytes = read_at(elf, buf, addr, 160)
274-
.ok_or_else(|| anyhow!("FlashDevice not in any LOAD segment"))?;
283+
let want = sym_size.max(160);
284+
let bytes =
285+
read_at(elf, buf, addr, want).ok_or_else(|| anyhow!("FlashDevice not in any LOAD segment"))?;
286+
let mut sectors = Vec::new();
287+
let mut off = 160;
288+
while off + 8 <= bytes.len() {
289+
let size: u32 = bytes.pread(off).unwrap();
290+
let address: u32 = bytes.pread(off + 4).unwrap();
291+
if size == u32::MAX && address == u32::MAX {
292+
break;
293+
}
294+
sectors.push((size, address));
295+
off += 8;
296+
}
275297
Ok(FlashDevice {
276298
start: bytes.pread::<u32>(132).unwrap() as u64,
277299
size: bytes.pread::<u32>(136).unwrap() as u64,
278300
page_size: bytes.pread(140).unwrap(),
279301
erased: bytes.pread(148).unwrap(),
280302
program_to: bytes.pread(152).unwrap(),
281303
erase_to: bytes.pread(156).unwrap(),
304+
sectors,
282305
})
283306
}
284307

xtask/src/render.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,19 @@ fn build_family(
255255
algo.default = true;
256256
algo.flash_properties.address_range = start..end;
257257
algo.flash_properties.page_size = page_size;
258-
algo.flash_properties.sectors = vec![SectorDescription {
259-
size: page_size as u64,
260-
address: 0,
261-
}];
258+
// Keep the erase size declared by the `algorithm!` macro (SYS on
259+
// flash_v3 uses 4 KB; USR/OB match page_size). Rebase to 0 — addresses
260+
// in sectors[] are relative to address_range.start.
261+
if algo.flash_properties.sectors.is_empty() {
262+
algo.flash_properties.sectors = vec![SectorDescription {
263+
size: page_size as u64,
264+
address: 0,
265+
}];
266+
} else {
267+
for s in algo.flash_properties.sectors.iter_mut() {
268+
s.address = 0;
269+
}
270+
}
262271
// Drop EraseChip for SYS — defends against accidental bulk-erase
263272
// routing. USR's MER and OB's page-erase+defaults are fine.
264273
if kind == "sys" {

0 commit comments

Comments
 (0)