aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/flash/f4.rs175
-rw-r--r--embassy-stm32/src/flash/mod.rs1
-rw-r--r--embassy-stm32/src/lib.rs4
-rw-r--r--examples/stm32f4/Cargo.toml1
-rw-r--r--examples/stm32f4/src/bin/flash.rs57
5 files changed, 237 insertions, 1 deletions
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
new file mode 100644
index 000000000..0afa9e829
--- /dev/null
+++ b/embassy-stm32/src/flash/f4.rs
@@ -0,0 +1,175 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile;
3
4use atomic_polyfill::{fence, Ordering};
5
6use super::{ERASE_SIZE, FLASH_BASE, FLASH_SIZE};
7use crate::flash::Error;
8use crate::pac;
9
10// Only available on some devices
11const SECOND_BANK_OFFSET: usize = FLASH_SIZE / 2;
12const SECOND_BANK_SECTOR_START: u32 = 12;
13
14unsafe fn is_dual_bank() -> bool {
15 match FLASH_SIZE / 1024 {
16 // 1 MB devices depend on configuration
17 1024 => {
18 if cfg!(any(
19 feature = "stm32f427",
20 feature = "stm32f429",
21 feature = "stm32f437",
22 feature = "stm32f439",
23 feature = "stm32f469",
24 feature = "stm32f479",
25 )) {
26 pac::FLASH.optcr().read().db1m()
27 } else {
28 false
29 }
30 }
31 // 2 MB devices are always dual bank
32 2048 => true,
33 // All other devices are single bank
34 _ => false,
35 }
36}
37
38pub(crate) unsafe fn lock() {
39 pac::FLASH.cr().modify(|w| w.set_lock(true));
40}
41
42pub(crate) unsafe fn unlock() {
43 pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123));
44 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
45}
46
47pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> {
48 pac::FLASH.cr().write(|w| {
49 w.set_pg(true);
50 w.set_psize(pac::flash::vals::Psize::PSIZE32);
51 });
52
53 let ret = {
54 let mut ret: Result<(), Error> = Ok(());
55 let mut offset = offset;
56 for chunk in buf.chunks(super::WRITE_SIZE) {
57 for val in chunk.chunks(4) {
58 write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap()));
59 offset += val.len() as u32;
60
61 // prevents parallelism errors
62 fence(Ordering::SeqCst);
63 }
64
65 ret = blocking_wait_ready();
66 if ret.is_err() {
67 break;
68 }
69 }
70 ret
71 };
72
73 pac::FLASH.cr().write(|w| w.set_pg(false));
74
75 ret
76}
77
78unsafe fn get_sector(addr: u32) -> u8 {
79 let offset = addr - FLASH_BASE as u32;
80
81 let sector = if is_dual_bank() {
82 let bank = offset / SECOND_BANK_OFFSET as u32;
83 let offset_in_bank = offset % SECOND_BANK_OFFSET as u32;
84
85 let sector_in_bank = if offset_in_bank >= ERASE_SIZE as u32 / 2 {
86 4 + offset_in_bank / ERASE_SIZE as u32
87 } else {
88 offset_in_bank / (ERASE_SIZE as u32 / 8)
89 };
90
91 if bank == 1 {
92 SECOND_BANK_SECTOR_START + sector_in_bank
93 } else {
94 sector_in_bank
95 }
96 } else {
97 if offset >= ERASE_SIZE as u32 / 2 {
98 4 + offset / ERASE_SIZE as u32
99 } else {
100 offset / (ERASE_SIZE as u32 / 8)
101 }
102 };
103
104 sector as u8
105}
106
107pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> {
108 let start_sector = get_sector(from);
109 let end_sector = get_sector(to);
110
111 for sector in start_sector..end_sector {
112 let ret = erase_sector(sector as u8);
113 if ret.is_err() {
114 return ret;
115 }
116 }
117
118 Ok(())
119}
120
121unsafe fn erase_sector(sector: u8) -> Result<(), Error> {
122 let bank = (sector >= SECOND_BANK_SECTOR_START) as u8;
123 let snb = (bank << 4) + (sector % SECOND_BANK_SECTOR_START as u8);
124
125 pac::FLASH.cr().modify(|w| {
126 w.set_ser(true);
127 w.set_snb(snb)
128 });
129
130 pac::FLASH.cr().modify(|w| {
131 w.set_strt(true);
132 });
133
134 let ret: Result<(), Error> = blocking_wait_ready();
135
136 clear_all_err();
137
138 ret
139}
140
141pub(crate) unsafe fn clear_all_err() {
142 pac::FLASH.sr().write(|w| {
143 w.set_pgserr(true);
144 w.set_pgperr(true);
145 w.set_pgaerr(true);
146 w.set_wrperr(true);
147 w.set_eop(true);
148 });
149}
150
151pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> {
152 loop {
153 let sr = pac::FLASH.sr().read();
154
155 if !sr.bsy() {
156 if sr.pgserr() {
157 return Err(Error::Seq);
158 }
159
160 if sr.pgperr() {
161 return Err(Error::Parallelism);
162 }
163
164 if sr.pgaerr() {
165 return Err(Error::Unaligned);
166 }
167
168 if sr.wrperr() {
169 return Err(Error::Protected);
170 }
171
172 return Ok(());
173 }
174 }
175}
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 31ca243a6..59ca59f65 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -10,6 +10,7 @@ const FLASH_END: usize = FLASH_BASE + FLASH_SIZE;
10 10
11#[cfg_attr(any(flash_wl, flash_wb, flash_l0, flash_l1, flash_l4), path = "l.rs")] 11#[cfg_attr(any(flash_wl, flash_wb, flash_l0, flash_l1, flash_l4), path = "l.rs")]
12#[cfg_attr(flash_f3, path = "f3.rs")] 12#[cfg_attr(flash_f3, path = "f3.rs")]
13#[cfg_attr(flash_f4, path = "f4.rs")]
13#[cfg_attr(flash_f7, path = "f7.rs")] 14#[cfg_attr(flash_f7, path = "f7.rs")]
14#[cfg_attr(flash_h7, path = "h7.rs")] 15#[cfg_attr(flash_h7, path = "h7.rs")]
15mod family; 16mod family;
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 7be0c77ea..8b8168589 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -39,7 +39,9 @@ pub mod i2c;
39 39
40#[cfg(crc)] 40#[cfg(crc)]
41pub mod crc; 41pub mod crc;
42#[cfg(any(flash_l0, flash_l1, flash_wl, flash_wb, flash_l4, flash_f3, flash_f7, flash_h7))] 42#[cfg(any(
43 flash_l0, flash_l1, flash_wl, flash_wb, flash_l4, flash_f3, flash_f4, flash_f7, flash_h7
44))]
43pub mod flash; 45pub mod flash;
44pub mod pwm; 46pub mod pwm;
45#[cfg(rng)] 47#[cfg(rng)]
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index de33ffad8..100c0e608 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -19,6 +19,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
19futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 19futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
20heapless = { version = "0.7.5", default-features = false } 20heapless = { version = "0.7.5", default-features = false }
21nb = "1.0.0" 21nb = "1.0.0"
22embedded-storage = "0.3.0"
22 23
23usb-device = "0.2" 24usb-device = "0.2"
24usbd-serial = "0.1.1" 25usbd-serial = "0.1.1"
diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs
new file mode 100644
index 000000000..b531d6f13
--- /dev/null
+++ b/examples/stm32f4/src/bin/flash.rs
@@ -0,0 +1,57 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap};
6use embassy::executor::Spawner;
7use embassy::time::{Duration, Timer};
8use embassy_stm32::flash::Flash;
9use embassy_stm32::Peripherals;
10use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy::main]
14async fn main(_spawner: Spawner, p: Peripherals) {
15 info!("Hello Flash!");
16
17 const ADDR: u32 = 0x10_0000;
18
19 // wait a bit before accessing the flash
20 Timer::after(Duration::from_millis(300)).await;
21
22 let mut f = Flash::unlock(p.FLASH);
23
24 info!("Reading...");
25 let mut buf = [0u8; 32];
26 unwrap!(f.read(ADDR, &mut buf));
27 info!("Read: {=[u8]:x}", buf);
28
29 info!("Erasing...");
30 unwrap!(f.erase(ADDR, ADDR + 128 * 1024));
31
32 info!("Reading...");
33 let mut buf = [0u8; 32];
34 unwrap!(f.read(ADDR, &mut buf));
35 info!("Read after erase: {=[u8]:x}", buf);
36
37 info!("Writing...");
38 unwrap!(f.write(
39 ADDR,
40 &[
41 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
42 30, 31, 32
43 ]
44 ));
45
46 info!("Reading...");
47 let mut buf = [0u8; 32];
48 unwrap!(f.read(ADDR, &mut buf));
49 info!("Read: {=[u8]:x}", buf);
50 assert_eq!(
51 &buf[..],
52 &[
53 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
54 30, 31, 32
55 ]
56 );
57}