const KEY1: u32 = 0x4567_0123;
const KEY2: u32 = 0xCDEF_89AB;
const FLASH: ch32_metapac::flash::Flash = ch32_metapac::FLASH;
#[inline(always)]
fn wait_busy() {
while FLASH.statr().read().bsy() {}
debug_assert!(
!FLASH.statr().read().wrprterr(),
"flash write protection error"
);
FLASH.statr().write(|w| w.set_eop(true));
}
pub fn unlock() {
FLASH.keyr().write(|w| w.set_keyr(KEY1));
FLASH.keyr().write(|w| w.set_keyr(KEY2));
FLASH.modekeyr().write(|w| w.set_modekeyr(KEY1));
FLASH.modekeyr().write(|w| w.set_modekeyr(KEY2));
}
#[inline(always)]
pub fn lock() {
FLASH.ctlr().write(|w| {
w.set_lock(true);
w.set_flock(true);
});
}
pub const PAGE_SIZE: usize = 64;
const BUF_LOAD_SIZE: usize = 4;
pub fn erase(addr: u32) {
FLASH.ctlr().write(|w| w.set_page_er(true));
FLASH.addr().write(|w| w.set_addr(addr));
FLASH.ctlr().write(|w| {
w.set_page_er(true);
w.set_strt(true);
});
wait_busy();
FLASH.ctlr().write(|_| {});
}
pub fn write(addr: u32, data: &[u8]) {
let page_base = addr & !(PAGE_SIZE as u32 - 1);
debug_assert!(
(addr as usize & (BUF_LOAD_SIZE - 1)) == 0,
"write: addr not word-aligned"
);
debug_assert!(
data.len().is_multiple_of(BUF_LOAD_SIZE),
"write: len not word-aligned"
);
debug_assert!(
addr + data.len() as u32 <= page_base + PAGE_SIZE as u32,
"write: crosses page boundary"
);
FLASH.ctlr().write(|w| w.set_page_pg(true));
FLASH.ctlr().write(|w| {
w.set_page_pg(true);
w.set_bufrst(true);
});
wait_busy();
let mut buf_addr = addr;
let mut ptr = data.as_ptr() as *const u32;
for _ in 0..data.len() / BUF_LOAD_SIZE {
let word = unsafe { ptr.read() };
unsafe { core::ptr::write_volatile(buf_addr as *mut u32, word) };
FLASH.ctlr().write(|w| {
w.set_page_pg(true);
w.set_bufload(true);
});
wait_busy();
buf_addr += BUF_LOAD_SIZE as u32;
ptr = unsafe { ptr.add(1) };
}
FLASH.addr().write(|w| w.set_addr(page_base));
FLASH.ctlr().write(|w| {
w.set_page_pg(true);
w.set_strt(true);
});
wait_busy();
FLASH.ctlr().write(|_| {});
}
pub fn boot_mode() -> bool {
FLASH.statr().read().boot_mode()
}
pub fn set_boot_mode(mode: bool) {
FLASH.boot_modekeyp().write(|w| w.set_modekeyr(KEY1));
FLASH.boot_modekeyp().write(|w| w.set_modekeyr(KEY2));
FLASH.statr().write(|w| w.set_boot_mode(mode));
}