tinyboot_ch32_hal/flash/
v0.rs1const KEY1: u32 = 0x4567_0123;
2const KEY2: u32 = 0xCDEF_89AB;
3const FLASH: ch32_metapac::flash::Flash = ch32_metapac::FLASH;
4
5#[inline(always)]
6fn wait_busy() {
7 while FLASH.statr().read().bsy() {}
8 debug_assert!(
9 !FLASH.statr().read().wrprterr(),
10 "flash write protection error"
11 );
12 FLASH.statr().write(|w| w.set_eop(true));
14}
15
16pub fn unlock() {
18 FLASH.keyr().write(|w| w.set_keyr(KEY1));
19 FLASH.keyr().write(|w| w.set_keyr(KEY2));
20 FLASH.modekeyr().write(|w| w.set_modekeyr(KEY1));
21 FLASH.modekeyr().write(|w| w.set_modekeyr(KEY2));
22}
23
24#[inline(always)]
26pub fn lock() {
27 FLASH.ctlr().write(|w| {
28 w.set_lock(true);
29 w.set_flock(true);
30 });
31}
32
33pub const PAGE_SIZE: usize = 64;
35
36const BUF_LOAD_SIZE: usize = 4;
38
39pub fn erase(addr: u32) {
43 FLASH.ctlr().write(|w| w.set_page_er(true));
45 FLASH.addr().write(|w| w.set_addr(addr));
47 FLASH.ctlr().write(|w| {
49 w.set_page_er(true);
50 w.set_strt(true);
51 });
52 wait_busy();
54 FLASH.ctlr().write(|_| {});
56}
57
58pub fn write(addr: u32, data: &[u8]) {
63 let page_base = addr & !(PAGE_SIZE as u32 - 1);
64 debug_assert!(
65 (addr as usize & (BUF_LOAD_SIZE - 1)) == 0,
66 "write: addr not word-aligned"
67 );
68 debug_assert!(
69 data.len().is_multiple_of(BUF_LOAD_SIZE),
70 "write: len not word-aligned"
71 );
72 debug_assert!(
73 addr + data.len() as u32 <= page_base + PAGE_SIZE as u32,
74 "write: crosses page boundary"
75 );
76
77 FLASH.ctlr().write(|w| w.set_page_pg(true));
79 FLASH.ctlr().write(|w| {
81 w.set_page_pg(true);
82 w.set_bufrst(true);
83 });
84 wait_busy();
86
87 let mut buf_addr = addr;
89 let mut ptr = data.as_ptr() as *const u32;
90 for _ in 0..data.len() / BUF_LOAD_SIZE {
91 let word = unsafe { ptr.read() };
92 unsafe { core::ptr::write_volatile(buf_addr as *mut u32, word) };
93 FLASH.ctlr().write(|w| {
94 w.set_page_pg(true);
95 w.set_bufload(true);
96 });
97 wait_busy();
98 buf_addr += BUF_LOAD_SIZE as u32;
99 ptr = unsafe { ptr.add(1) };
100 }
101
102 FLASH.addr().write(|w| w.set_addr(page_base));
104 FLASH.ctlr().write(|w| {
106 w.set_page_pg(true);
107 w.set_strt(true);
108 });
109 wait_busy();
111 FLASH.ctlr().write(|_| {});
113}
114
115pub fn boot_mode() -> bool {
116 FLASH.statr().read().boot_mode()
117}
118
119pub fn set_boot_mode(mode: bool) {
120 FLASH.boot_modekeyp().write(|w| w.set_modekeyr(KEY1));
121 FLASH.boot_modekeyp().write(|w| w.set_modekeyr(KEY2));
122 FLASH.statr().write(|w| w.set_boot_mode(mode));
123}