aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-04-05 11:12:40 +0000
committerGitHub <[email protected]>2023-04-05 11:12:40 +0000
commiteed2b123253380d67f76bf1d0272688e8053bc9a (patch)
treed5d415fd27d7507107fc89a6d45ec46b49dc4f6c
parent064ec9581e33fdd42f89ff75984254ccfec3f6c2 (diff)
parent2a49e11cb0ffd3e0d9a0cc94444f293de523b47f (diff)
Merge #1297
1297: feat(stm32): Support multiple flash regions r=Dirbaio a=rmja This depends on https://github.com/embassy-rs/stm32-data/pull/176 This is a general overhaul of the flash module to support multiple erase sizes. Overall this PR contains: * Move complex sector computation to embassy-hal-common to allow for tests * Implement `FlashRegion` trait for each available flash region * Add Flash::into_regions() to get each region. * Implement embedded-storage traits for each region to support different erase sizes * Split family write operations into begin/do/end * Protection against simultaneous writes/erases for each split region is done through a global mutex Co-authored-by: Rasmus Melchior Jacobsen <[email protected]> Co-authored-by: Dario Nieuwenhuis <[email protected]>
-rwxr-xr-xci.sh1
-rw-r--r--embassy-stm32/Cargo.toml8
-rw-r--r--embassy-stm32/build.rs123
-rw-r--r--embassy-stm32/src/flash/common.rs211
-rw-r--r--embassy-stm32/src/flash/f3.rs82
-rw-r--r--embassy-stm32/src/flash/f4.rs277
-rw-r--r--embassy-stm32/src/flash/f7.rs139
-rw-r--r--embassy-stm32/src/flash/h7.rs99
-rw-r--r--embassy-stm32/src/flash/l.rs125
-rw-r--r--embassy-stm32/src/flash/mod.rs155
-rw-r--r--embassy-stm32/src/flash/other.rs29
-rw-r--r--embassy-stm32/src/lib.rs3
-rw-r--r--examples/boot/bootloader/stm32/src/main.rs7
-rw-r--r--examples/stm32f3/src/bin/flash.rs2
-rw-r--r--examples/stm32f4/src/bin/flash.rs13
-rw-r--r--examples/stm32f7/src/bin/flash.rs4
-rw-r--r--examples/stm32h7/src/bin/flash.rs4
-rw-r--r--examples/stm32l0/src/bin/flash.rs2
-rw-r--r--examples/stm32l1/src/bin/flash.rs2
-rw-r--r--examples/stm32wl/src/bin/flash.rs2
20 files changed, 865 insertions, 423 deletions
diff --git a/ci.sh b/ci.sh
index d86c93520..b9dddad3a 100755
--- a/ci.sh
+++ b/ci.sh
@@ -49,6 +49,7 @@ cargo batch \
49 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \ 49 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \
50 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \ 50 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \
51 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \ 51 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \
52 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \
52 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ 53 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
53 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \ 54 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
54 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \ 55 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 14ec3d70a..504caacb2 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -60,7 +60,7 @@ sdio-host = "0.5.0"
60embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } 60embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true }
61critical-section = "1.1" 61critical-section = "1.1"
62atomic-polyfill = "1.0.1" 62atomic-polyfill = "1.0.1"
63stm32-metapac = { version = "2", features = ["rt"] } 63stm32-metapac = "3"
64vcell = "0.1.3" 64vcell = "0.1.3"
65bxcan = "0.7.0" 65bxcan = "0.7.0"
66nb = "1.0.0" 66nb = "1.0.0"
@@ -69,12 +69,16 @@ seq-macro = "0.3.0"
69cfg-if = "1.0.0" 69cfg-if = "1.0.0"
70embedded-io = { version = "0.4.0", features = ["async"], optional = true } 70embedded-io = { version = "0.4.0", features = ["async"], optional = true }
71 71
72[dev-dependencies]
73critical-section = { version = "1.1", features = ["std"] }
74
72[build-dependencies] 75[build-dependencies]
73proc-macro2 = "1.0.36" 76proc-macro2 = "1.0.36"
74quote = "1.0.15" 77quote = "1.0.15"
75stm32-metapac = { version = "2", default-features = false, features = ["metadata"]} 78stm32-metapac = { version = "3", default-features = false, features = ["metadata"]}
76 79
77[features] 80[features]
81default = ["stm32-metapac/rt"]
78defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"] 82defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"]
79memory-x = ["stm32-metapac/memory-x"] 83memory-x = ["stm32-metapac/memory-x"]
80subghz = [] 84subghz = []
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 481fec677..61aceed93 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -3,9 +3,9 @@ use std::fmt::Write as _;
3use std::path::PathBuf; 3use std::path::PathBuf;
4use std::{env, fs}; 4use std::{env, fs};
5 5
6use proc_macro2::TokenStream; 6use proc_macro2::{Ident, TokenStream};
7use quote::{format_ident, quote}; 7use quote::{format_ident, quote};
8use stm32_metapac::metadata::METADATA; 8use stm32_metapac::metadata::{MemoryRegionKind, METADATA};
9 9
10fn main() { 10fn main() {
11 let chip_name = match env::vars() 11 let chip_name = match env::vars()
@@ -107,6 +107,94 @@ fn main() {
107 }); 107 });
108 108
109 // ======== 109 // ========
110 // Generate FLASH regions
111 let mut flash_regions = TokenStream::new();
112 let flash_memory_regions: Vec<_> = METADATA
113 .memory
114 .iter()
115 .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some())
116 .collect();
117 for region in flash_memory_regions.iter() {
118 let region_name = format_ident!("{}", get_flash_region_name(region.name));
119 let bank_variant = format_ident!(
120 "{}",
121 if region.name.starts_with("BANK_1") {
122 "Bank1"
123 } else if region.name.starts_with("BANK_2") {
124 "Bank2"
125 } else if region.name == "OTP" {
126 "Otp"
127 } else {
128 continue;
129 }
130 );
131 let base = region.address;
132 let size = region.size;
133 let settings = region.settings.as_ref().unwrap();
134 let erase_size = settings.erase_size;
135 let write_size = settings.write_size;
136 let erase_value = settings.erase_value;
137
138 flash_regions.extend(quote! {
139 pub const #region_name: crate::flash::FlashRegion = crate::flash::FlashRegion {
140 bank: crate::flash::FlashBank::#bank_variant,
141 base: #base,
142 size: #size,
143 erase_size: #erase_size,
144 write_size: #write_size,
145 erase_value: #erase_value,
146 };
147 });
148
149 let region_type = format_ident!("{}", get_flash_region_type_name(region.name));
150 flash_regions.extend(quote! {
151 #[cfg(flash)]
152 pub struct #region_type<'d>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>,);
153 });
154 }
155
156 let (fields, (inits, region_names)): (Vec<TokenStream>, (Vec<TokenStream>, Vec<Ident>)) = flash_memory_regions
157 .iter()
158 .map(|f| {
159 let region_name = get_flash_region_name(f.name);
160 let field_name = format_ident!("{}", region_name.to_lowercase());
161 let field_type = format_ident!("{}", get_flash_region_type_name(f.name));
162 let field = quote! {
163 pub #field_name: #field_type<'d>
164 };
165 let region_name = format_ident!("{}", region_name);
166 let init = quote! {
167 #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()})
168 };
169
170 (field, (init, region_name))
171 })
172 .unzip();
173
174 let regions_len = flash_memory_regions.len();
175 flash_regions.extend(quote! {
176 #[cfg(flash)]
177 pub struct FlashLayout<'d> {
178 #(#fields),*
179 }
180
181 #[cfg(flash)]
182 impl<'d> FlashLayout<'d> {
183 pub(crate) fn new(mut p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self {
184 Self {
185 #(#inits),*
186 }
187 }
188 }
189
190 pub const FLASH_REGIONS: [&crate::flash::FlashRegion; #regions_len] = [
191 #(&#region_names),*
192 ];
193 });
194
195 g.extend(quote! { pub mod flash_regions { #flash_regions } });
196
197 // ========
110 // Generate DMA IRQs. 198 // Generate DMA IRQs.
111 199
112 let mut dma_irqs: HashMap<&str, Vec<(&str, &str)>> = HashMap::new(); 200 let mut dma_irqs: HashMap<&str, Vec<(&str, &str)>> = HashMap::new();
@@ -578,11 +666,25 @@ fn main() {
578 // ======== 666 // ========
579 // Write foreach_foo! macrotables 667 // Write foreach_foo! macrotables
580 668
669 let mut flash_regions_table: Vec<Vec<String>> = Vec::new();
581 let mut interrupts_table: Vec<Vec<String>> = Vec::new(); 670 let mut interrupts_table: Vec<Vec<String>> = Vec::new();
582 let mut peripherals_table: Vec<Vec<String>> = Vec::new(); 671 let mut peripherals_table: Vec<Vec<String>> = Vec::new();
583 let mut pins_table: Vec<Vec<String>> = Vec::new(); 672 let mut pins_table: Vec<Vec<String>> = Vec::new();
584 let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); 673 let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
585 674
675 for m in METADATA
676 .memory
677 .iter()
678 .filter(|m| m.kind == MemoryRegionKind::Flash && m.settings.is_some())
679 {
680 let settings = m.settings.as_ref().unwrap();
681 let mut row = Vec::new();
682 row.push(get_flash_region_type_name(m.name));
683 row.push(settings.write_size.to_string());
684 row.push(settings.erase_size.to_string());
685 flash_regions_table.push(row);
686 }
687
586 let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32; 688 let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32;
587 let gpio_stride = 0x400; 689 let gpio_stride = 0x400;
588 690
@@ -679,6 +781,7 @@ fn main() {
679 781
680 let mut m = String::new(); 782 let mut m = String::new();
681 783
784 make_table(&mut m, "foreach_flash_region", &flash_regions_table);
682 make_table(&mut m, "foreach_interrupt", &interrupts_table); 785 make_table(&mut m, "foreach_interrupt", &interrupts_table);
683 make_table(&mut m, "foreach_peripheral", &peripherals_table); 786 make_table(&mut m, "foreach_peripheral", &peripherals_table);
684 make_table(&mut m, "foreach_pin", &pins_table); 787 make_table(&mut m, "foreach_pin", &pins_table);
@@ -831,3 +934,19 @@ macro_rules! {} {{
831 ) 934 )
832 .unwrap(); 935 .unwrap();
833} 936}
937
938fn get_flash_region_name(name: &str) -> String {
939 let name = name.replace("BANK_", "BANK").replace("REGION_", "REGION");
940 if name.contains("REGION") {
941 name
942 } else {
943 name + "_REGION"
944 }
945}
946
947fn get_flash_region_type_name(name: &str) -> String {
948 get_flash_region_name(name)
949 .replace("BANK", "Bank")
950 .replace("REGION", "Region")
951 .replace("_", "")
952}
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
new file mode 100644
index 000000000..8235d6f08
--- /dev/null
+++ b/embassy-stm32/src/flash/common.rs
@@ -0,0 +1,211 @@
1use atomic_polyfill::{fence, Ordering};
2use embassy_hal_common::drop::OnDrop;
3use embassy_hal_common::{into_ref, PeripheralRef};
4
5use super::{family, Error, FlashLayout, FlashRegion, FlashSector, FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
6use crate::flash::FlashBank;
7use crate::Peripheral;
8
9pub struct Flash<'d> {
10 inner: PeripheralRef<'d, crate::peripherals::FLASH>,
11}
12
13impl<'d> Flash<'d> {
14 pub fn new(p: impl Peripheral<P = crate::peripherals::FLASH> + 'd) -> Self {
15 into_ref!(p);
16 Self { inner: p }
17 }
18
19 pub fn into_regions(self) -> FlashLayout<'d> {
20 FlashLayout::new(self.release())
21 }
22
23 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
24 blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes)
25 }
26
27 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
28 unsafe { blocking_write(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) }
29 }
30
31 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
32 unsafe { blocking_erase(FLASH_BASE as u32, from, to) }
33 }
34
35 pub(crate) fn release(self) -> PeripheralRef<'d, crate::peripherals::FLASH> {
36 let mut flash = self;
37 unsafe { flash.inner.clone_unchecked() }
38 }
39}
40
41fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
42 if offset + bytes.len() as u32 > size {
43 return Err(Error::Size);
44 }
45
46 let start_address = base + offset;
47 let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) };
48 bytes.copy_from_slice(flash_data);
49 Ok(())
50}
51
52unsafe fn blocking_write(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> {
53 if offset + bytes.len() as u32 > size {
54 return Err(Error::Size);
55 }
56 if offset % WRITE_SIZE as u32 != 0 || bytes.len() % WRITE_SIZE != 0 {
57 return Err(Error::Unaligned);
58 }
59
60 let mut address = base + offset;
61 trace!("Writing {} bytes at 0x{:x}", bytes.len(), address);
62
63 for chunk in bytes.chunks(WRITE_SIZE) {
64 critical_section::with(|_| {
65 family::clear_all_err();
66 fence(Ordering::SeqCst);
67 family::unlock();
68 fence(Ordering::SeqCst);
69 family::begin_write();
70 fence(Ordering::SeqCst);
71
72 let _on_drop = OnDrop::new(|| {
73 family::end_write();
74 fence(Ordering::SeqCst);
75 family::lock();
76 });
77
78 family::blocking_write(address, chunk.try_into().unwrap())
79 })?;
80 address += WRITE_SIZE as u32;
81 }
82 Ok(())
83}
84
85unsafe fn blocking_erase(base: u32, from: u32, to: u32) -> Result<(), Error> {
86 let start_address = base + from;
87 let end_address = base + to;
88 let regions = family::get_flash_regions();
89
90 // Test if the address range is aligned at sector base addresses
91 let mut address = start_address;
92 while address < end_address {
93 let sector = get_sector(address, regions);
94 if sector.start != address {
95 return Err(Error::Unaligned);
96 }
97 address += sector.size;
98 }
99 if address != end_address {
100 return Err(Error::Unaligned);
101 }
102
103 trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address);
104
105 let mut address = start_address;
106 while address < end_address {
107 let sector = get_sector(address, regions);
108 trace!("Erasing sector: {:?}", sector);
109
110 critical_section::with(|_| {
111 family::clear_all_err();
112 fence(Ordering::SeqCst);
113 family::unlock();
114 fence(Ordering::SeqCst);
115
116 let _on_drop = OnDrop::new(|| {
117 family::lock();
118 });
119
120 family::blocking_erase_sector(&sector)
121 })?;
122 address += sector.size;
123 }
124 Ok(())
125}
126
127pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector {
128 let mut current_bank = FlashBank::Bank1;
129 let mut bank_offset = 0;
130 for region in regions {
131 if region.bank != current_bank {
132 current_bank = region.bank;
133 bank_offset = 0;
134 }
135
136 if address < region.end() {
137 let index_in_region = (address - region.base) / region.erase_size;
138 return FlashSector {
139 bank: region.bank,
140 index_in_bank: bank_offset + index_in_region as u8,
141 start: region.base + index_in_region * region.erase_size,
142 size: region.erase_size,
143 };
144 }
145
146 bank_offset += region.sectors();
147 }
148
149 panic!("Flash sector not found");
150}
151
152impl FlashRegion {
153 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
154 blocking_read(self.base, self.size, offset, bytes)
155 }
156
157 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
158 unsafe { blocking_write(self.base, self.size, offset, bytes) }
159 }
160
161 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
162 unsafe { blocking_erase(self.base, from, to) }
163 }
164}
165
166foreach_flash_region! {
167 ($type_name:ident, $write_size:literal, $erase_size:literal) => {
168 impl crate::_generated::flash_regions::$type_name<'_> {
169 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
170 blocking_read(self.0.base, self.0.size, offset, bytes)
171 }
172
173 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
174 unsafe { blocking_write(self.0.base, self.0.size, offset, bytes) }
175 }
176
177 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
178 unsafe { blocking_erase(self.0.base, from, to) }
179 }
180 }
181
182 impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_> {
183 type Error = Error;
184 }
185
186 impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> {
187 const READ_SIZE: usize = 1;
188
189 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
190 self.blocking_read(offset, bytes)
191 }
192
193 fn capacity(&self) -> usize {
194 self.0.size as usize
195 }
196 }
197
198 impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> {
199 const WRITE_SIZE: usize = $write_size;
200 const ERASE_SIZE: usize = $erase_size;
201
202 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
203 self.blocking_write(offset, bytes)
204 }
205
206 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
207 self.blocking_erase(from, to)
208 }
209 }
210 };
211}
diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs
index 1cb08ee1a..10a09c42c 100644
--- a/embassy-stm32/src/flash/f3.rs
+++ b/embassy-stm32/src/flash/f3.rs
@@ -1,9 +1,16 @@
1use core::convert::TryInto; 1use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3 3
4use atomic_polyfill::{fence, Ordering};
5
6use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
4use crate::flash::Error; 7use crate::flash::Error;
5use crate::pac; 8use crate::pac;
6 9
10pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
11 &FLASH_REGIONS
12}
13
7pub(crate) unsafe fn lock() { 14pub(crate) unsafe fn lock() {
8 pac::FLASH.cr().modify(|w| w.set_lock(true)); 15 pac::FLASH.cr().modify(|w| w.set_lock(true));
9} 16}
@@ -13,58 +20,55 @@ pub(crate) unsafe fn unlock() {
13 pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); 20 pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
14} 21}
15 22
16pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { 23pub(crate) unsafe fn begin_write() {
24 assert_eq!(0, WRITE_SIZE % 2);
25
17 pac::FLASH.cr().write(|w| w.set_pg(true)); 26 pac::FLASH.cr().write(|w| w.set_pg(true));
27}
18 28
19 let ret = { 29pub(crate) unsafe fn end_write() {
20 let mut ret: Result<(), Error> = Ok(()); 30 pac::FLASH.cr().write(|w| w.set_pg(false));
21 let mut offset = offset; 31}
22 for chunk in buf.chunks(2) {
23 write_volatile(offset as *mut u16, u16::from_le_bytes(chunk[0..2].try_into().unwrap()));
24 offset += chunk.len() as u32;
25 32
26 ret = blocking_wait_ready(); 33pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
27 if ret.is_err() { 34 let mut address = start_address;
28 break; 35 for chunk in buf.chunks(2) {
29 } 36 write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap()));
30 } 37 address += chunk.len() as u32;
31 ret
32 };
33 38
34 pac::FLASH.cr().write(|w| w.set_pg(false)); 39 // prevents parallelism errors
40 fence(Ordering::SeqCst);
41 }
35 42
36 ret 43 blocking_wait_ready()
37} 44}
38 45
39pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { 46pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
40 for page in (from..to).step_by(super::ERASE_SIZE) { 47 pac::FLASH.cr().modify(|w| {
41 pac::FLASH.cr().modify(|w| { 48 w.set_per(true);
42 w.set_per(true); 49 });
43 });
44 50
45 pac::FLASH.ar().write(|w| w.set_far(page)); 51 pac::FLASH.ar().write(|w| w.set_far(sector.start));
46 52
47 pac::FLASH.cr().modify(|w| { 53 pac::FLASH.cr().modify(|w| {
48 w.set_strt(true); 54 w.set_strt(true);
49 }); 55 });
50 56
51 let mut ret: Result<(), Error> = blocking_wait_ready(); 57 let mut ret: Result<(), Error> = blocking_wait_ready();
52 58
53 if !pac::FLASH.sr().read().eop() { 59 if !pac::FLASH.sr().read().eop() {
54 trace!("FLASH: EOP not set"); 60 trace!("FLASH: EOP not set");
55 ret = Err(Error::Prog); 61 ret = Err(Error::Prog);
56 } else { 62 } else {
57 pac::FLASH.sr().write(|w| w.set_eop(true)); 63 pac::FLASH.sr().write(|w| w.set_eop(true));
58 } 64 }
59 65
60 pac::FLASH.cr().modify(|w| w.set_per(false)); 66 pac::FLASH.cr().modify(|w| w.set_per(false));
61 67
62 clear_all_err(); 68 clear_all_err();
63 if ret.is_err() { 69 if ret.is_err() {
64 return ret; 70 return ret;
65 }
66 } 71 }
67
68 Ok(()) 72 Ok(())
69} 73}
70 74
@@ -82,7 +86,7 @@ pub(crate) unsafe fn clear_all_err() {
82 }); 86 });
83} 87}
84 88
85pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { 89unsafe fn blocking_wait_ready() -> Result<(), Error> {
86 loop { 90 loop {
87 let sr = pac::FLASH.sr().read(); 91 let sr = pac::FLASH.sr().read();
88 92
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 9e23a8adf..2ce9df69f 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -2,27 +2,108 @@ use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 3use core::sync::atomic::{fence, Ordering};
4 4
5use super::{ERASE_SIZE, FLASH_BASE, FLASH_SIZE}; 5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 6use crate::flash::Error;
7use crate::pac; 7use crate::pac;
8 8
9const SECOND_BANK_SECTOR_START: u32 = 12; 9#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
10mod alt_regions {
11 use embassy_hal_common::PeripheralRef;
12 use stm32_metapac::FLASH_SIZE;
10 13
11unsafe fn is_dual_bank() -> bool { 14 use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3};
12 match FLASH_SIZE / 1024 { 15 use crate::flash::{Bank1Region1, Bank1Region2, Flash, FlashBank, FlashRegion};
13 // 1 MB devices depend on configuration 16 use crate::peripherals::FLASH;
14 1024 => { 17
15 if cfg!(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)) { 18 pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion {
16 pac::FLASH.optcr().read().db1m() 19 size: 3 * BANK1_REGION3.erase_size,
17 } else { 20 ..BANK1_REGION3
18 false 21 };
22 pub const ALT_BANK2_REGION1: FlashRegion = FlashRegion {
23 bank: FlashBank::Bank2,
24 base: BANK1_REGION1.base + FLASH_SIZE as u32 / 2,
25 ..BANK1_REGION1
26 };
27 pub const ALT_BANK2_REGION2: FlashRegion = FlashRegion {
28 bank: FlashBank::Bank2,
29 base: BANK1_REGION2.base + FLASH_SIZE as u32 / 2,
30 ..BANK1_REGION2
31 };
32 pub const ALT_BANK2_REGION3: FlashRegion = FlashRegion {
33 bank: FlashBank::Bank2,
34 base: BANK1_REGION3.base + FLASH_SIZE as u32 / 2,
35 size: 3 * BANK1_REGION3.erase_size,
36 ..BANK1_REGION3
37 };
38
39 pub const ALT_FLASH_REGIONS: [&FlashRegion; 6] = [
40 &BANK1_REGION1,
41 &BANK1_REGION2,
42 &ALT_BANK1_REGION3,
43 &ALT_BANK2_REGION1,
44 &ALT_BANK2_REGION2,
45 &ALT_BANK2_REGION3,
46 ];
47
48 pub type AltBank1Region1<'d> = Bank1Region1<'d>;
49 pub type AltBank1Region2<'d> = Bank1Region2<'d>;
50 pub struct AltBank1Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
51 pub struct AltBank2Region1<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
52 pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
53 pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
54
55 pub struct AltFlashLayout<'d> {
56 pub bank1_region1: AltBank1Region1<'d>,
57 pub bank1_region2: AltBank1Region2<'d>,
58 pub bank1_region3: AltBank1Region3<'d>,
59 pub bank2_region1: AltBank2Region1<'d>,
60 pub bank2_region2: AltBank2Region2<'d>,
61 pub bank2_region3: AltBank2Region3<'d>,
62 }
63
64 impl<'d> Flash<'d> {
65 pub fn into_alt_regions(self) -> AltFlashLayout<'d> {
66 unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) };
67
68 // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
69 // Also, all flash region operations are protected with a cs.
70 let mut p = self.release();
71 AltFlashLayout {
72 bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }),
73 bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }),
74 bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }),
75 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }),
76 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }),
77 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }),
19 } 78 }
20 } 79 }
21 // 2 MB devices are always dual bank
22 2048 => true,
23 // All other devices are single bank
24 _ => false,
25 } 80 }
81
82 impl Drop for AltFlashLayout<'_> {
83 fn drop(&mut self) {
84 unsafe {
85 super::lock();
86 crate::pac::FLASH.optcr().modify(|r| r.set_db1m(false))
87 };
88 }
89 }
90}
91
92#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
93pub use alt_regions::{AltFlashLayout, ALT_FLASH_REGIONS};
94
95#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
96pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
97 if unsafe { pac::FLASH.optcr().read().db1m() } {
98 &ALT_FLASH_REGIONS
99 } else {
100 &FLASH_REGIONS
101 }
102}
103
104#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
105pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
106 &FLASH_REGIONS
26} 107}
27 108
28pub(crate) unsafe fn lock() { 109pub(crate) unsafe fn lock() {
@@ -34,93 +115,34 @@ pub(crate) unsafe fn unlock() {
34 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); 115 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
35} 116}
36 117
37pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { 118pub(crate) unsafe fn begin_write() {
119 assert_eq!(0, WRITE_SIZE % 4);
120
38 pac::FLASH.cr().write(|w| { 121 pac::FLASH.cr().write(|w| {
39 w.set_pg(true); 122 w.set_pg(true);
40 w.set_psize(pac::flash::vals::Psize::PSIZE32); 123 w.set_psize(pac::flash::vals::Psize::PSIZE32);
41 }); 124 });
42
43 let ret = {
44 let mut ret: Result<(), Error> = Ok(());
45 let mut offset = offset;
46 for chunk in buf.chunks(super::WRITE_SIZE) {
47 for val in chunk.chunks(4) {
48 write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap()));
49 offset += val.len() as u32;
50
51 // prevents parallelism errors
52 fence(Ordering::SeqCst);
53 }
54
55 ret = blocking_wait_ready();
56 if ret.is_err() {
57 break;
58 }
59 }
60 ret
61 };
62
63 pac::FLASH.cr().write(|w| w.set_pg(false));
64
65 ret
66} 125}
67 126
68struct FlashSector { 127pub(crate) unsafe fn end_write() {
69 index: u8, 128 pac::FLASH.cr().write(|w| w.set_pg(false));
70 size: u32,
71}
72
73fn get_sector(addr: u32, dual_bank: bool) -> FlashSector {
74 let offset = addr - FLASH_BASE as u32;
75
76 let bank_size = match dual_bank {
77 true => FLASH_SIZE / 2,
78 false => FLASH_SIZE,
79 } as u32;
80
81 let bank = offset / bank_size;
82 let offset_in_bank = offset % bank_size;
83
84 let index_in_bank = if offset_in_bank >= ERASE_SIZE as u32 / 2 {
85 4 + offset_in_bank / ERASE_SIZE as u32
86 } else {
87 offset_in_bank / (ERASE_SIZE as u32 / 8)
88 };
89
90 // First 4 sectors are 16KB, then one 64KB, and rest are 128KB
91 let size = match index_in_bank {
92 0..=3 => 16 * 1024,
93 4 => 64 * 1024,
94 _ => 128 * 1024,
95 };
96
97 let index = if bank == 1 {
98 SECOND_BANK_SECTOR_START + index_in_bank
99 } else {
100 index_in_bank
101 } as u8;
102
103 FlashSector { index, size }
104} 129}
105 130
106pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { 131pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
107 let mut addr = from; 132 let mut address = start_address;
108 let dual_bank = is_dual_bank(); 133 for val in buf.chunks(4) {
134 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
135 address += val.len() as u32;
109 136
110 while addr < to { 137 // prevents parallelism errors
111 let sector = get_sector(addr, dual_bank); 138 fence(Ordering::SeqCst);
112 erase_sector(sector.index)?;
113 addr += sector.size;
114 } 139 }
115 140
116 Ok(()) 141 blocking_wait_ready()
117} 142}
118 143
119unsafe fn erase_sector(sector: u8) -> Result<(), Error> { 144pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
120 let bank = sector / SECOND_BANK_SECTOR_START as u8; 145 let snb = ((sector.bank as u8) << 4) + sector.index_in_bank;
121 let snb = (bank << 4) + (sector % SECOND_BANK_SECTOR_START as u8);
122
123 trace!("Erasing sector: {}", sector);
124 146
125 pac::FLASH.cr().modify(|w| { 147 pac::FLASH.cr().modify(|w| {
126 w.set_ser(true); 148 w.set_ser(true);
@@ -148,7 +170,7 @@ pub(crate) unsafe fn clear_all_err() {
148 }); 170 });
149} 171}
150 172
151pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { 173unsafe fn blocking_wait_ready() -> Result<(), Error> {
152 loop { 174 loop {
153 let sr = pac::FLASH.sr().read(); 175 let sr = pac::FLASH.sr().read();
154 176
@@ -173,3 +195,80 @@ pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> {
173 } 195 }
174 } 196 }
175} 197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202 use crate::flash::{get_sector, FlashBank};
203
204 #[test]
205 #[cfg(stm32f429)]
206 fn can_get_sector_single_bank() {
207 const SMALL_SECTOR_SIZE: u32 = 16 * 1024;
208 const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024;
209 const LARGE_SECTOR_SIZE: u32 = 128 * 1024;
210
211 let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32| {
212 assert_eq!(
213 FlashSector {
214 bank: FlashBank::Bank1,
215 index_in_bank,
216 start,
217 size
218 },
219 get_sector(address, &FLASH_REGIONS)
220 )
221 };
222
223 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
224 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
225 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
226 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
227
228 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000);
229 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF);
230
231 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
232 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
233 assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000);
234 assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
235
236 let assert_sector = |bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| {
237 assert_eq!(
238 FlashSector {
239 bank,
240 index_in_bank,
241 start,
242 size
243 },
244 get_sector(address, &ALT_FLASH_REGIONS)
245 )
246 };
247
248 assert_sector(FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
249 assert_sector(FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
250 assert_sector(FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
251 assert_sector(FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
252
253 assert_sector(FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000);
254 assert_sector(FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF);
255
256 assert_sector(FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
257 assert_sector(FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
258 assert_sector(FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000);
259 assert_sector(FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF);
260
261 assert_sector(FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000);
262 assert_sector(FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF);
263 assert_sector(FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000);
264 assert_sector(FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF);
265
266 assert_sector(FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000);
267 assert_sector(FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF);
268
269 assert_sector(FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000);
270 assert_sector(FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF);
271 assert_sector(FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000);
272 assert_sector(FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
273 }
274}
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index dd0d8439d..6427d5a09 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -2,9 +2,14 @@ use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 3use core::sync::atomic::{fence, Ordering};
4 4
5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
5use crate::flash::Error; 6use crate::flash::Error;
6use crate::pac; 7use crate::pac;
7 8
9pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
10 &FLASH_REGIONS
11}
12
8pub(crate) unsafe fn lock() { 13pub(crate) unsafe fn lock() {
9 pac::FLASH.cr().modify(|w| w.set_lock(true)); 14 pac::FLASH.cr().modify(|w| w.set_lock(true));
10} 15}
@@ -14,64 +19,36 @@ pub(crate) unsafe fn unlock() {
14 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); 19 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
15} 20}
16 21
17pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { 22pub(crate) unsafe fn begin_write() {
23 assert_eq!(0, WRITE_SIZE % 4);
24
18 pac::FLASH.cr().write(|w| { 25 pac::FLASH.cr().write(|w| {
19 w.set_pg(true); 26 w.set_pg(true);
20 w.set_psize(pac::flash::vals::Psize::PSIZE32); 27 w.set_psize(pac::flash::vals::Psize::PSIZE32);
21 }); 28 });
29}
22 30
23 let ret = { 31pub(crate) unsafe fn end_write() {
24 let mut ret: Result<(), Error> = Ok(());
25 let mut offset = offset;
26 for chunk in buf.chunks(super::WRITE_SIZE) {
27 for val in chunk.chunks(4) {
28 write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap()));
29 offset += val.len() as u32;
30
31 // prevents parallelism errors
32 fence(Ordering::SeqCst);
33 }
34
35 ret = blocking_wait_ready();
36 if ret.is_err() {
37 break;
38 }
39 }
40 ret
41 };
42
43 pac::FLASH.cr().write(|w| w.set_pg(false)); 32 pac::FLASH.cr().write(|w| w.set_pg(false));
44
45 ret
46} 33}
47 34
48pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { 35pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
49 let start_sector = if from >= (super::FLASH_BASE + super::ERASE_SIZE / 2) as u32 { 36 let mut address = start_address;
50 4 + (from - super::FLASH_BASE as u32) / super::ERASE_SIZE as u32 37 for val in buf.chunks(4) {
51 } else { 38 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
52 (from - super::FLASH_BASE as u32) / (super::ERASE_SIZE as u32 / 8) 39 address += val.len() as u32;
53 }; 40
54 41 // prevents parallelism errors
55 let end_sector = if to >= (super::FLASH_BASE + super::ERASE_SIZE / 2) as u32 { 42 fence(Ordering::SeqCst);
56 4 + (to - super::FLASH_BASE as u32) / super::ERASE_SIZE as u32
57 } else {
58 (to - super::FLASH_BASE as u32) / (super::ERASE_SIZE as u32 / 8)
59 };
60
61 for sector in start_sector..end_sector {
62 let ret = erase_sector(sector as u8);
63 if ret.is_err() {
64 return ret;
65 }
66 } 43 }
67 44
68 Ok(()) 45 blocking_wait_ready()
69} 46}
70 47
71unsafe fn erase_sector(sector: u8) -> Result<(), Error> { 48pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
72 pac::FLASH.cr().modify(|w| { 49 pac::FLASH.cr().modify(|w| {
73 w.set_ser(true); 50 w.set_ser(true);
74 w.set_snb(sector) 51 w.set_snb(sector.index_in_bank)
75 }); 52 });
76 53
77 pac::FLASH.cr().modify(|w| { 54 pac::FLASH.cr().modify(|w| {
@@ -107,7 +84,7 @@ pub(crate) unsafe fn clear_all_err() {
107 }); 84 });
108} 85}
109 86
110pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { 87unsafe fn blocking_wait_ready() -> Result<(), Error> {
111 loop { 88 loop {
112 let sr = pac::FLASH.sr().read(); 89 let sr = pac::FLASH.sr().read();
113 90
@@ -132,3 +109,75 @@ pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> {
132 } 109 }
133 } 110 }
134} 111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::flash::{get_sector, FlashBank};
117
118 #[test]
119 #[cfg(stm32f732)]
120 fn can_get_sector() {
121 const SMALL_SECTOR_SIZE: u32 = 16 * 1024;
122 const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024;
123 const LARGE_SECTOR_SIZE: u32 = 128 * 1024;
124
125 let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32| {
126 assert_eq!(
127 FlashSector {
128 bank: FlashBank::Bank1,
129 index_in_bank,
130 start,
131 size
132 },
133 get_sector(address, &FLASH_REGIONS)
134 )
135 };
136
137 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
138 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
139 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
140 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
141
142 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000);
143 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF);
144
145 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
146 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
147 assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000);
148 assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF);
149 }
150
151 #[test]
152 #[cfg(stm32f769)]
153 fn can_get_sector() {
154 const SMALL_SECTOR_SIZE: u32 = 32 * 1024;
155 const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024;
156 const LARGE_SECTOR_SIZE: u32 = 256 * 1024;
157
158 let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32| {
159 assert_eq!(
160 FlashSector {
161 bank: FlashBank::Bank1,
162 index_in_bank,
163 start,
164 size
165 },
166 get_sector(address, &FLASH_REGIONS)
167 )
168 };
169
170 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
171 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_7FFF);
172 assert_sector(3, 0x0801_8000, SMALL_SECTOR_SIZE, 0x0801_8000);
173 assert_sector(3, 0x0801_8000, SMALL_SECTOR_SIZE, 0x0801_FFFF);
174
175 assert_sector(4, 0x0802_0000, MEDIUM_SECTOR_SIZE, 0x0802_0000);
176 assert_sector(4, 0x0802_0000, MEDIUM_SECTOR_SIZE, 0x0803_FFFF);
177
178 assert_sector(5, 0x0804_0000, LARGE_SECTOR_SIZE, 0x0804_0000);
179 assert_sector(5, 0x0804_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF);
180 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000);
181 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
182 }
183}
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 7de95ac11..4f38d50c0 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -1,13 +1,18 @@
1use core::convert::TryInto; 1use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3 3
4use atomic_polyfill::{fence, Ordering};
5
6use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE};
4use crate::flash::Error; 7use crate::flash::Error;
5use crate::pac; 8use crate::pac;
6 9
7const SECOND_BANK_OFFSET: usize = 0x0010_0000;
8
9const fn is_dual_bank() -> bool { 10const fn is_dual_bank() -> bool {
10 super::FLASH_SIZE / 2 > super::ERASE_SIZE 11 FLASH_REGIONS.len() == 2
12}
13
14pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
15 &FLASH_REGIONS
11} 16}
12 17
13pub(crate) unsafe fn lock() { 18pub(crate) unsafe fn lock() {
@@ -20,90 +25,64 @@ pub(crate) unsafe fn lock() {
20pub(crate) unsafe fn unlock() { 25pub(crate) unsafe fn unlock() {
21 pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123)); 26 pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123));
22 pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); 27 pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
23
24 if is_dual_bank() { 28 if is_dual_bank() {
25 pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123)); 29 pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123));
26 pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); 30 pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
27 } 31 }
28} 32}
29 33
30pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { 34pub(crate) unsafe fn begin_write() {
31 let bank = if !is_dual_bank() || (offset - super::FLASH_BASE as u32) < SECOND_BANK_OFFSET as u32 { 35 assert_eq!(0, WRITE_SIZE % 4);
36}
37
38pub(crate) unsafe fn end_write() {}
39
40pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
41 // We cannot have the write setup sequence in begin_write as it depends on the address
42 let bank = if start_address < BANK1_REGION.end() {
32 pac::FLASH.bank(0) 43 pac::FLASH.bank(0)
33 } else { 44 } else {
34 pac::FLASH.bank(1) 45 pac::FLASH.bank(1)
35 }; 46 };
36
37 bank.cr().write(|w| { 47 bank.cr().write(|w| {
38 w.set_pg(true); 48 w.set_pg(true);
39 w.set_psize(2); // 32 bits at once 49 w.set_psize(2); // 32 bits at once
40 }); 50 });
41
42 cortex_m::asm::isb(); 51 cortex_m::asm::isb();
43 cortex_m::asm::dsb(); 52 cortex_m::asm::dsb();
44 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst); 53 fence(Ordering::SeqCst);
45 54
46 let ret = { 55 let mut res = None;
47 let mut ret: Result<(), Error> = Ok(()); 56 let mut address = start_address;
48 let mut offset = offset; 57 for val in buf.chunks(4) {
49 'outer: for chunk in buf.chunks(super::WRITE_SIZE) { 58 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
50 for val in chunk.chunks(4) { 59 address += val.len() as u32;
51 trace!("Writing at {:x}", offset); 60
52 write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap())); 61 res = Some(blocking_wait_ready(bank));
53 offset += val.len() as u32; 62 bank.sr().modify(|w| {
54 63 if w.eop() {
55 ret = blocking_wait_ready(bank); 64 w.set_eop(true);
56 bank.sr().modify(|w| {
57 if w.eop() {
58 w.set_eop(true);
59 }
60 });
61 if ret.is_err() {
62 break 'outer;
63 }
64 } 65 }
66 });
67 if res.unwrap().is_err() {
68 break;
65 } 69 }
66 ret 70 }
67 };
68 71
69 bank.cr().write(|w| w.set_pg(false)); 72 bank.cr().write(|w| w.set_pg(false));
70 73
71 cortex_m::asm::isb(); 74 cortex_m::asm::isb();
72 cortex_m::asm::dsb(); 75 cortex_m::asm::dsb();
73 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst); 76 fence(Ordering::SeqCst);
74
75 ret
76}
77
78pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> {
79 let from = from - super::FLASH_BASE as u32;
80 let to = to - super::FLASH_BASE as u32;
81
82 let (start, end) = if to <= super::FLASH_SIZE as u32 {
83 let start_sector = from / super::ERASE_SIZE as u32;
84 let end_sector = to / super::ERASE_SIZE as u32;
85 (start_sector, end_sector)
86 } else {
87 error!("Attempting to write outside of defined sectors {:x} {:x}", from, to);
88 return Err(Error::Unaligned);
89 };
90
91 trace!("Erasing sectors from {} to {}", start, end);
92 for sector in start..end {
93 let bank = if sector >= 8 { 1 } else { 0 };
94 let ret = erase_sector(pac::FLASH.bank(bank), (sector % 8) as u8);
95 if ret.is_err() {
96 return ret;
97 }
98 }
99 77
100 Ok(()) 78 res.unwrap()
101} 79}
102 80
103unsafe fn erase_sector(bank: pac::flash::Bank, sector: u8) -> Result<(), Error> { 81pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
82 let bank = pac::FLASH.bank(sector.bank as usize);
104 bank.cr().modify(|w| { 83 bank.cr().modify(|w| {
105 w.set_ser(true); 84 w.set_ser(true);
106 w.set_snb(sector) 85 w.set_snb(sector.index_in_bank)
107 }); 86 });
108 87
109 bank.cr().modify(|w| { 88 bank.cr().modify(|w| {
@@ -160,7 +139,7 @@ unsafe fn bank_clear_all_err(bank: pac::flash::Bank) {
160 }); 139 });
161} 140}
162 141
163pub(crate) unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { 142unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> {
164 loop { 143 loop {
165 let sr = bank.sr().read(); 144 let sr = bank.sr().read();
166 145
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index 5048a3314..7d9cc6ea3 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -1,9 +1,15 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile; 1use core::ptr::write_volatile;
3 2
3use atomic_polyfill::{fence, Ordering};
4
5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
4use crate::flash::Error; 6use crate::flash::Error;
5use crate::pac; 7use crate::pac;
6 8
9pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
10 &FLASH_REGIONS
11}
12
7pub(crate) unsafe fn lock() { 13pub(crate) unsafe fn lock() {
8 #[cfg(any(flash_wl, flash_wb, flash_l4))] 14 #[cfg(any(flash_wl, flash_wb, flash_l4))]
9 pac::FLASH.cr().modify(|w| w.set_lock(true)); 15 pac::FLASH.cr().modify(|w| w.set_lock(true));
@@ -33,82 +39,75 @@ pub(crate) unsafe fn unlock() {
33 } 39 }
34} 40}
35 41
36pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { 42pub(crate) unsafe fn begin_write() {
43 assert_eq!(0, WRITE_SIZE % 4);
44
37 #[cfg(any(flash_wl, flash_wb, flash_l4))] 45 #[cfg(any(flash_wl, flash_wb, flash_l4))]
38 pac::FLASH.cr().write(|w| w.set_pg(true)); 46 pac::FLASH.cr().write(|w| w.set_pg(true));
47}
39 48
40 let ret = { 49pub(crate) unsafe fn end_write() {
41 let mut ret: Result<(), Error> = Ok(());
42 let mut offset = offset;
43 for chunk in buf.chunks(super::WRITE_SIZE) {
44 for val in chunk.chunks(4) {
45 write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap()));
46 offset += val.len() as u32;
47 }
48
49 ret = blocking_wait_ready();
50 if ret.is_err() {
51 break;
52 }
53 }
54 ret
55 };
56
57 #[cfg(any(flash_wl, flash_wb, flash_l4))] 50 #[cfg(any(flash_wl, flash_wb, flash_l4))]
58 pac::FLASH.cr().write(|w| w.set_pg(false)); 51 pac::FLASH.cr().write(|w| w.set_pg(false));
59
60 ret
61} 52}
62 53
63pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { 54pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
64 for page in (from..to).step_by(super::ERASE_SIZE) { 55 let mut address = start_address;
65 #[cfg(any(flash_l0, flash_l1))] 56 for val in buf.chunks(4) {
66 { 57 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
67 pac::FLASH.pecr().modify(|w| { 58 address += val.len() as u32;
68 w.set_erase(true);
69 w.set_prog(true);
70 });
71 59
72 write_volatile(page as *mut u32, 0xFFFFFFFF); 60 // prevents parallelism errors
73 } 61 fence(Ordering::SeqCst);
74 62 }
75 #[cfg(any(flash_wl, flash_wb, flash_l4))]
76 {
77 let idx = (page - super::FLASH_BASE as u32) / super::ERASE_SIZE as u32;
78
79 #[cfg(flash_l4)]
80 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) };
81
82 pac::FLASH.cr().modify(|w| {
83 w.set_per(true);
84 w.set_pnb(idx as u8);
85 #[cfg(any(flash_wl, flash_wb))]
86 w.set_strt(true);
87 #[cfg(any(flash_l4))]
88 w.set_start(true);
89 #[cfg(any(flash_l4))]
90 w.set_bker(bank);
91 });
92 }
93
94 let ret: Result<(), Error> = blocking_wait_ready();
95 63
96 #[cfg(any(flash_wl, flash_wb, flash_l4))] 64 blocking_wait_ready()
97 pac::FLASH.cr().modify(|w| w.set_per(false)); 65}
98 66
99 #[cfg(any(flash_l0, flash_l1))] 67pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
68 #[cfg(any(flash_l0, flash_l1))]
69 {
100 pac::FLASH.pecr().modify(|w| { 70 pac::FLASH.pecr().modify(|w| {
101 w.set_erase(false); 71 w.set_erase(true);
102 w.set_prog(false); 72 w.set_prog(true);
103 }); 73 });
104 74
105 clear_all_err(); 75 write_volatile(sector.start as *mut u32, 0xFFFFFFFF);
106 if ret.is_err() { 76 }
107 return ret; 77
108 } 78 #[cfg(any(flash_wl, flash_wb, flash_l4))]
79 {
80 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
81
82 #[cfg(flash_l4)]
83 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) };
84
85 pac::FLASH.cr().modify(|w| {
86 w.set_per(true);
87 w.set_pnb(idx as u8);
88 #[cfg(any(flash_wl, flash_wb))]
89 w.set_strt(true);
90 #[cfg(any(flash_l4))]
91 w.set_start(true);
92 #[cfg(any(flash_l4))]
93 w.set_bker(bank);
94 });
109 } 95 }
110 96
111 Ok(()) 97 let ret: Result<(), Error> = blocking_wait_ready();
98
99 #[cfg(any(flash_wl, flash_wb, flash_l4))]
100 pac::FLASH.cr().modify(|w| w.set_per(false));
101
102 #[cfg(any(flash_l0, flash_l1))]
103 pac::FLASH.pecr().modify(|w| {
104 w.set_erase(false);
105 w.set_prog(false);
106 });
107
108 clear_all_err();
109
110 ret
112} 111}
113 112
114pub(crate) unsafe fn clear_all_err() { 113pub(crate) unsafe fn clear_all_err() {
@@ -149,7 +148,7 @@ pub(crate) unsafe fn clear_all_err() {
149 }); 148 });
150} 149}
151 150
152pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { 151unsafe fn blocking_wait_ready() -> Result<(), Error> {
153 loop { 152 loop {
154 let sr = pac::FLASH.sr().read(); 153 let sr = pac::FLASH.sr().read();
155 154
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index b7166a437..231ff1f9e 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -1,89 +1,67 @@
1use embassy_hal_common::{into_ref, PeripheralRef}; 1use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
2use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
3 2
4pub use crate::pac::{ERASE_SIZE, ERASE_VALUE, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; 3#[cfg(flash)]
5use crate::peripherals::FLASH; 4mod common;
6use crate::Peripheral;
7const FLASH_END: usize = FLASH_BASE + FLASH_SIZE;
8 5
9#[cfg_attr(any(flash_wl, flash_wb, flash_l0, flash_l1, flash_l4), path = "l.rs")] 6#[cfg(flash)]
10#[cfg_attr(flash_f3, path = "f3.rs")] 7pub use common::*;
11#[cfg_attr(flash_f4, path = "f4.rs")]
12#[cfg_attr(flash_f7, path = "f7.rs")]
13#[cfg_attr(flash_h7, path = "h7.rs")]
14mod family;
15 8
16pub struct Flash<'d> { 9pub use crate::_generated::flash_regions::*;
17 _inner: PeripheralRef<'d, FLASH>, 10pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
18}
19 11
20impl<'d> Flash<'d> { 12#[derive(Debug)]
21 pub fn new(p: impl Peripheral<P = FLASH> + 'd) -> Self { 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22 into_ref!(p); 14pub struct FlashRegion {
23 Self { _inner: p } 15 pub bank: FlashBank,
24 } 16 pub base: u32,
25 17 pub size: u32,
26 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 18 pub erase_size: u32,
27 let offset = FLASH_BASE as u32 + offset; 19 pub write_size: u32,
28 if offset as usize >= FLASH_END || offset as usize + bytes.len() > FLASH_END { 20 pub erase_value: u8,
29 return Err(Error::Size); 21}
30 }
31
32 let flash_data = unsafe { core::slice::from_raw_parts(offset as *const u8, bytes.len()) };
33 bytes.copy_from_slice(flash_data);
34 Ok(())
35 }
36
37 pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> {
38 let offset = FLASH_BASE as u32 + offset;
39 if offset as usize + buf.len() > FLASH_END {
40 return Err(Error::Size);
41 }
42 if offset as usize % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 {
43 return Err(Error::Unaligned);
44 }
45 trace!("Writing {} bytes at 0x{:x}", buf.len(), offset);
46
47 self.clear_all_err();
48
49 unsafe {
50 family::unlock();
51 let res = family::blocking_write(offset, buf);
52 family::lock();
53 res
54 }
55 }
56 22
57 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 23#[derive(Debug, PartialEq)]
58 let from = FLASH_BASE as u32 + from; 24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59 let to = FLASH_BASE as u32 + to; 25pub struct FlashSector {
60 if to < from || to as usize > FLASH_END { 26 pub bank: FlashBank,
61 return Err(Error::Size); 27 pub index_in_bank: u8,
62 } 28 pub start: u32,
63 if (from as usize % ERASE_SIZE) != 0 || (to as usize % ERASE_SIZE) != 0 { 29 pub size: u32,
64 return Err(Error::Unaligned); 30}
65 }
66 31
67 self.clear_all_err(); 32#[derive(Clone, Copy, Debug, PartialEq)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34pub enum FlashBank {
35 Bank1 = 0,
36 Bank2 = 1,
37 Otp,
38}
68 39
69 unsafe { 40impl FlashRegion {
70 family::unlock(); 41 pub const fn end(&self) -> u32 {
71 let res = family::blocking_erase(from, to); 42 self.base + self.size
72 family::lock();
73 res
74 }
75 } 43 }
76 44
77 fn clear_all_err(&mut self) { 45 pub const fn sectors(&self) -> u8 {
78 unsafe { family::clear_all_err() }; 46 (self.size / self.erase_size) as u8
79 } 47 }
80} 48}
81 49
82impl Drop for Flash<'_> { 50#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")]
83 fn drop(&mut self) { 51#[cfg_attr(flash_f3, path = "f3.rs")]
84 unsafe { family::lock() }; 52#[cfg_attr(flash_f4, path = "f4.rs")]
85 } 53#[cfg_attr(flash_f7, path = "f7.rs")]
86} 54#[cfg_attr(flash_h7, path = "h7.rs")]
55#[cfg_attr(
56 not(any(
57 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f3, flash_f4, flash_f7, flash_h7
58 )),
59 path = "other.rs"
60)]
61mod family;
62
63#[allow(unused_imports)]
64pub use family::*;
87 65
88#[derive(Debug, Copy, Clone, PartialEq, Eq)] 66#[derive(Debug, Copy, Clone, PartialEq, Eq)]
89#[cfg_attr(feature = "defmt", derive(defmt::Format))] 67#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -97,10 +75,6 @@ pub enum Error {
97 Parallelism, 75 Parallelism,
98} 76}
99 77
100impl<'d> ErrorType for Flash<'d> {
101 type Error = Error;
102}
103
104impl NorFlashError for Error { 78impl NorFlashError for Error {
105 fn kind(&self) -> NorFlashErrorKind { 79 fn kind(&self) -> NorFlashErrorKind {
106 match self { 80 match self {
@@ -110,28 +84,3 @@ impl NorFlashError for Error {
110 } 84 }
111 } 85 }
112} 86}
113
114impl<'d> ReadNorFlash for Flash<'d> {
115 const READ_SIZE: usize = WRITE_SIZE;
116
117 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
118 self.blocking_read(offset, bytes)
119 }
120
121 fn capacity(&self) -> usize {
122 FLASH_SIZE
123 }
124}
125
126impl<'d> NorFlash for Flash<'d> {
127 const WRITE_SIZE: usize = WRITE_SIZE;
128 const ERASE_SIZE: usize = ERASE_SIZE;
129
130 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
131 self.blocking_erase(from, to)
132 }
133
134 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
135 self.blocking_write(offset, bytes)
136 }
137}
diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs
new file mode 100644
index 000000000..c151cb828
--- /dev/null
+++ b/embassy-stm32/src/flash/other.rs
@@ -0,0 +1,29 @@
1#![allow(unused)]
2
3use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
4
5pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
6 &FLASH_REGIONS
7}
8
9pub(crate) unsafe fn lock() {
10 unimplemented!();
11}
12pub(crate) unsafe fn unlock() {
13 unimplemented!();
14}
15pub(crate) unsafe fn begin_write() {
16 unimplemented!();
17}
18pub(crate) unsafe fn end_write() {
19 unimplemented!();
20}
21pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
22 unimplemented!();
23}
24pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> {
25 unimplemented!();
26}
27pub(crate) unsafe fn clear_all_err() {
28 unimplemented!();
29}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 8dc4df2dc..3f2d078f8 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -43,9 +43,6 @@ pub mod i2c;
43 43
44#[cfg(crc)] 44#[cfg(crc)]
45pub mod crc; 45pub mod crc;
46#[cfg(any(
47 flash_l0, flash_l1, flash_wl, flash_wb, flash_l4, flash_f3, flash_f4, flash_f7, flash_h7
48))]
49pub mod flash; 46pub mod flash;
50pub mod pwm; 47pub mod pwm;
51#[cfg(quadspi)] 48#[cfg(quadspi)]
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index b8027d19a..49c21920b 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -5,7 +5,7 @@ use cortex_m_rt::{entry, exception};
5#[cfg(feature = "defmt")] 5#[cfg(feature = "defmt")]
6use defmt_rtt as _; 6use defmt_rtt as _;
7use embassy_boot_stm32::*; 7use embassy_boot_stm32::*;
8use embassy_stm32::flash::{Flash, ERASE_SIZE}; 8use embassy_stm32::flash::Flash;
9 9
10#[entry] 10#[entry]
11fn main() -> ! { 11fn main() -> ! {
@@ -19,9 +19,10 @@ fn main() -> ! {
19 } 19 }
20 */ 20 */
21 21
22 let mut bl: BootLoader<ERASE_SIZE> = BootLoader::default(); 22 let mut bl: BootLoader<2048> = BootLoader::default();
23 let flash = Flash::new(p.FLASH); 23 let flash = Flash::new(p.FLASH);
24 let mut flash = BootFlash::new(flash); 24 let layout = flash.into_regions();
25 let mut flash = BootFlash::new(layout.bank1_region);
25 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash)); 26 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash));
26 core::mem::drop(flash); 27 core::mem::drop(flash);
27 unsafe { bl.load(start) } 28 unsafe { bl.load(start) }
diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs
index baa7484d0..e40ad4fc0 100644
--- a/examples/stm32f3/src/bin/flash.rs
+++ b/examples/stm32f3/src/bin/flash.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 15
16 const ADDR: u32 = 0x26000; 16 const ADDR: u32 = 0x26000;
17 17
18 let mut f = Flash::new(p.FLASH); 18 let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
19 19
20 info!("Reading..."); 20 info!("Reading...");
21 let mut buf = [0u8; 8]; 21 let mut buf = [0u8; 8];
diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs
index 7ea068a42..bd3a7c95e 100644
--- a/examples/stm32f4/src/bin/flash.rs
+++ b/examples/stm32f4/src/bin/flash.rs
@@ -5,7 +5,6 @@
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::flash::Flash; 7use embassy_stm32::flash::Flash;
8use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
@@ -13,6 +12,8 @@ async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
14 info!("Hello Flash!"); 13 info!("Hello Flash!");
15 14
15 // Once can also call `into_regions()` to get access to NorFlash implementations
16 // for each of the unique characteristics.
16 let mut f = Flash::new(p.FLASH); 17 let mut f = Flash::new(p.FLASH);
17 18
18 // Sector 5 19 // Sector 5
@@ -30,19 +31,19 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) {
30 31
31 info!("Reading..."); 32 info!("Reading...");
32 let mut buf = [0u8; 32]; 33 let mut buf = [0u8; 32];
33 unwrap!(f.read(offset, &mut buf)); 34 unwrap!(f.blocking_read(offset, &mut buf));
34 info!("Read: {=[u8]:x}", buf); 35 info!("Read: {=[u8]:x}", buf);
35 36
36 info!("Erasing..."); 37 info!("Erasing...");
37 unwrap!(f.erase(offset, offset + size)); 38 unwrap!(f.blocking_erase(offset, offset + size));
38 39
39 info!("Reading..."); 40 info!("Reading...");
40 let mut buf = [0u8; 32]; 41 let mut buf = [0u8; 32];
41 unwrap!(f.read(offset, &mut buf)); 42 unwrap!(f.blocking_read(offset, &mut buf));
42 info!("Read after erase: {=[u8]:x}", buf); 43 info!("Read after erase: {=[u8]:x}", buf);
43 44
44 info!("Writing..."); 45 info!("Writing...");
45 unwrap!(f.write( 46 unwrap!(f.blocking_write(
46 offset, 47 offset,
47 &[ 48 &[
48 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, 49 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,
@@ -52,7 +53,7 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) {
52 53
53 info!("Reading..."); 54 info!("Reading...");
54 let mut buf = [0u8; 32]; 55 let mut buf = [0u8; 32];
55 unwrap!(f.read(offset, &mut buf)); 56 unwrap!(f.blocking_read(offset, &mut buf));
56 info!("Read: {=[u8]:x}", buf); 57 info!("Read: {=[u8]:x}", buf);
57 assert_eq!( 58 assert_eq!(
58 &buf[..], 59 &buf[..],
diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs
index 4a7bca1fa..aabfe8557 100644
--- a/examples/stm32f7/src/bin/flash.rs
+++ b/examples/stm32f7/src/bin/flash.rs
@@ -14,12 +14,12 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default()); 14 let p = embassy_stm32::init(Default::default());
15 info!("Hello Flash!"); 15 info!("Hello Flash!");
16 16
17 const ADDR: u32 = 0x8_0000; 17 const ADDR: u32 = 0x8_0000; // This is the offset into the third region, the absolute address is 4x32K + 128K + 0x8_0000.
18 18
19 // wait a bit before accessing the flash 19 // wait a bit before accessing the flash
20 Timer::after(Duration::from_millis(300)).await; 20 Timer::after(Duration::from_millis(300)).await;
21 21
22 let mut f = Flash::new(p.FLASH); 22 let mut f = Flash::new(p.FLASH).into_regions().bank1_region3;
23 23
24 info!("Reading..."); 24 info!("Reading...");
25 let mut buf = [0u8; 32]; 25 let mut buf = [0u8; 32];
diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs
index ee86bdbf6..7ee9838c9 100644
--- a/examples/stm32h7/src/bin/flash.rs
+++ b/examples/stm32h7/src/bin/flash.rs
@@ -14,12 +14,12 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default()); 14 let p = embassy_stm32::init(Default::default());
15 info!("Hello Flash!"); 15 info!("Hello Flash!");
16 16
17 const ADDR: u32 = 0x08_0000; 17 const ADDR: u32 = 0; // This is the offset into bank 2, the absolute address is 0x8_0000
18 18
19 // wait a bit before accessing the flash 19 // wait a bit before accessing the flash
20 Timer::after(Duration::from_millis(300)).await; 20 Timer::after(Duration::from_millis(300)).await;
21 21
22 let mut f = Flash::new(p.FLASH); 22 let mut f = Flash::new(p.FLASH).into_regions().bank2_region;
23 23
24 info!("Reading..."); 24 info!("Reading...");
25 let mut buf = [0u8; 32]; 25 let mut buf = [0u8; 32];
diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs
index ffe4fb10b..337425028 100644
--- a/examples/stm32l0/src/bin/flash.rs
+++ b/examples/stm32l0/src/bin/flash.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 15
16 const ADDR: u32 = 0x26000; 16 const ADDR: u32 = 0x26000;
17 17
18 let mut f = Flash::new(p.FLASH); 18 let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
19 19
20 info!("Reading..."); 20 info!("Reading...");
21 let mut buf = [0u8; 8]; 21 let mut buf = [0u8; 8];
diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs
index 476ed51a4..38feb0d76 100644
--- a/examples/stm32l1/src/bin/flash.rs
+++ b/examples/stm32l1/src/bin/flash.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 15
16 const ADDR: u32 = 0x26000; 16 const ADDR: u32 = 0x26000;
17 17
18 let mut f = Flash::new(p.FLASH); 18 let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
19 19
20 info!("Reading..."); 20 info!("Reading...");
21 let mut buf = [0u8; 8]; 21 let mut buf = [0u8; 8];
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index 2a8880624..e6bc2865c 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 15
16 const ADDR: u32 = 0x36000; 16 const ADDR: u32 = 0x36000;
17 17
18 let mut f = Flash::new(p.FLASH); 18 let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
19 19
20 info!("Reading..."); 20 info!("Reading...");
21 let mut buf = [0u8; 8]; 21 let mut buf = [0u8; 8];