diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2023-04-05 11:12:40 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-04-05 11:12:40 +0000 |
| commit | eed2b123253380d67f76bf1d0272688e8053bc9a (patch) | |
| tree | d5d415fd27d7507107fc89a6d45ec46b49dc4f6c | |
| parent | 064ec9581e33fdd42f89ff75984254ccfec3f6c2 (diff) | |
| parent | 2a49e11cb0ffd3e0d9a0cc94444f293de523b47f (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-x | ci.sh | 1 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 8 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 123 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/common.rs | 211 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/f3.rs | 82 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/f4.rs | 277 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/f7.rs | 139 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/h7.rs | 99 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/l.rs | 125 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/mod.rs | 155 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/other.rs | 29 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 3 | ||||
| -rw-r--r-- | examples/boot/bootloader/stm32/src/main.rs | 7 | ||||
| -rw-r--r-- | examples/stm32f3/src/bin/flash.rs | 2 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/flash.rs | 13 | ||||
| -rw-r--r-- | examples/stm32f7/src/bin/flash.rs | 4 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/flash.rs | 4 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/flash.rs | 2 | ||||
| -rw-r--r-- | examples/stm32l1/src/bin/flash.rs | 2 | ||||
| -rw-r--r-- | examples/stm32wl/src/bin/flash.rs | 2 |
20 files changed, 865 insertions, 423 deletions
| @@ -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" | |||
| 60 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } | 60 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } |
| 61 | critical-section = "1.1" | 61 | critical-section = "1.1" |
| 62 | atomic-polyfill = "1.0.1" | 62 | atomic-polyfill = "1.0.1" |
| 63 | stm32-metapac = { version = "2", features = ["rt"] } | 63 | stm32-metapac = "3" |
| 64 | vcell = "0.1.3" | 64 | vcell = "0.1.3" |
| 65 | bxcan = "0.7.0" | 65 | bxcan = "0.7.0" |
| 66 | nb = "1.0.0" | 66 | nb = "1.0.0" |
| @@ -69,12 +69,16 @@ seq-macro = "0.3.0" | |||
| 69 | cfg-if = "1.0.0" | 69 | cfg-if = "1.0.0" |
| 70 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } | 70 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } |
| 71 | 71 | ||
| 72 | [dev-dependencies] | ||
| 73 | critical-section = { version = "1.1", features = ["std"] } | ||
| 74 | |||
| 72 | [build-dependencies] | 75 | [build-dependencies] |
| 73 | proc-macro2 = "1.0.36" | 76 | proc-macro2 = "1.0.36" |
| 74 | quote = "1.0.15" | 77 | quote = "1.0.15" |
| 75 | stm32-metapac = { version = "2", default-features = false, features = ["metadata"]} | 78 | stm32-metapac = { version = "3", default-features = false, features = ["metadata"]} |
| 76 | 79 | ||
| 77 | [features] | 80 | [features] |
| 81 | default = ["stm32-metapac/rt"] | ||
| 78 | defmt = ["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"] | 82 | defmt = ["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"] |
| 79 | memory-x = ["stm32-metapac/memory-x"] | 83 | memory-x = ["stm32-metapac/memory-x"] |
| 80 | subghz = [] | 84 | subghz = [] |
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 _; | |||
| 3 | use std::path::PathBuf; | 3 | use std::path::PathBuf; |
| 4 | use std::{env, fs}; | 4 | use std::{env, fs}; |
| 5 | 5 | ||
| 6 | use proc_macro2::TokenStream; | 6 | use proc_macro2::{Ident, TokenStream}; |
| 7 | use quote::{format_ident, quote}; | 7 | use quote::{format_ident, quote}; |
| 8 | use stm32_metapac::metadata::METADATA; | 8 | use stm32_metapac::metadata::{MemoryRegionKind, METADATA}; |
| 9 | 9 | ||
| 10 | fn main() { | 10 | fn 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 | |||
| 938 | fn 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 | |||
| 947 | fn 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 @@ | |||
| 1 | use atomic_polyfill::{fence, Ordering}; | ||
| 2 | use embassy_hal_common::drop::OnDrop; | ||
| 3 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 4 | |||
| 5 | use super::{family, Error, FlashLayout, FlashRegion, FlashSector, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; | ||
| 6 | use crate::flash::FlashBank; | ||
| 7 | use crate::Peripheral; | ||
| 8 | |||
| 9 | pub struct Flash<'d> { | ||
| 10 | inner: PeripheralRef<'d, crate::peripherals::FLASH>, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl<'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 | |||
| 41 | fn 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 | |||
| 52 | unsafe 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 | |||
| 85 | unsafe 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(§or) | ||
| 121 | })?; | ||
| 122 | address += sector.size; | ||
| 123 | } | ||
| 124 | Ok(()) | ||
| 125 | } | ||
| 126 | |||
| 127 | pub(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 | |||
| 152 | impl 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 | |||
| 166 | foreach_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 @@ | |||
| 1 | use core::convert::TryInto; | 1 | use core::convert::TryInto; |
| 2 | use core::ptr::write_volatile; | 2 | use core::ptr::write_volatile; |
| 3 | 3 | ||
| 4 | use atomic_polyfill::{fence, Ordering}; | ||
| 5 | |||
| 6 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | ||
| 4 | use crate::flash::Error; | 7 | use crate::flash::Error; |
| 5 | use crate::pac; | 8 | use crate::pac; |
| 6 | 9 | ||
| 10 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 11 | &FLASH_REGIONS | ||
| 12 | } | ||
| 13 | |||
| 7 | pub(crate) unsafe fn lock() { | 14 | pub(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 | ||
| 16 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | 23 | pub(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 = { | 29 | pub(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(); | 33 | pub(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 | ||
| 39 | pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { | 46 | pub(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 | ||
| 85 | pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { | 89 | unsafe 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; | |||
| 2 | use core::ptr::write_volatile; | 2 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 4 | ||
| 5 | use super::{ERASE_SIZE, FLASH_BASE, FLASH_SIZE}; | 5 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; |
| 6 | use crate::flash::Error; | 6 | use crate::flash::Error; |
| 7 | use crate::pac; | 7 | use crate::pac; |
| 8 | 8 | ||
| 9 | const SECOND_BANK_SECTOR_START: u32 = 12; | 9 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] |
| 10 | mod alt_regions { | ||
| 11 | use embassy_hal_common::PeripheralRef; | ||
| 12 | use stm32_metapac::FLASH_SIZE; | ||
| 10 | 13 | ||
| 11 | unsafe 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))] | ||
| 93 | pub use alt_regions::{AltFlashLayout, ALT_FLASH_REGIONS}; | ||
| 94 | |||
| 95 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] | ||
| 96 | pub 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)))] | ||
| 105 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 106 | &FLASH_REGIONS | ||
| 26 | } | 107 | } |
| 27 | 108 | ||
| 28 | pub(crate) unsafe fn lock() { | 109 | pub(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 | ||
| 37 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | 118 | pub(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 | ||
| 68 | struct FlashSector { | 127 | pub(crate) unsafe fn end_write() { |
| 69 | index: u8, | 128 | pac::FLASH.cr().write(|w| w.set_pg(false)); |
| 70 | size: u32, | ||
| 71 | } | ||
| 72 | |||
| 73 | fn 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 | ||
| 106 | pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { | 131 | pub(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 | ||
| 119 | unsafe fn erase_sector(sector: u8) -> Result<(), Error> { | 144 | pub(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 | ||
| 151 | pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { | 173 | unsafe 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)] | ||
| 200 | mod 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; | |||
| 2 | use core::ptr::write_volatile; | 2 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 4 | ||
| 5 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | ||
| 5 | use crate::flash::Error; | 6 | use crate::flash::Error; |
| 6 | use crate::pac; | 7 | use crate::pac; |
| 7 | 8 | ||
| 9 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 10 | &FLASH_REGIONS | ||
| 11 | } | ||
| 12 | |||
| 8 | pub(crate) unsafe fn lock() { | 13 | pub(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 | ||
| 17 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | 22 | pub(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 = { | 31 | pub(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 | ||
| 48 | pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { | 35 | pub(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 | ||
| 71 | unsafe fn erase_sector(sector: u8) -> Result<(), Error> { | 48 | pub(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 | ||
| 110 | pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { | 87 | unsafe 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)] | ||
| 114 | mod 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 @@ | |||
| 1 | use core::convert::TryInto; | 1 | use core::convert::TryInto; |
| 2 | use core::ptr::write_volatile; | 2 | use core::ptr::write_volatile; |
| 3 | 3 | ||
| 4 | use atomic_polyfill::{fence, Ordering}; | ||
| 5 | |||
| 6 | use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; | ||
| 4 | use crate::flash::Error; | 7 | use crate::flash::Error; |
| 5 | use crate::pac; | 8 | use crate::pac; |
| 6 | 9 | ||
| 7 | const SECOND_BANK_OFFSET: usize = 0x0010_0000; | ||
| 8 | |||
| 9 | const fn is_dual_bank() -> bool { | 10 | const fn is_dual_bank() -> bool { |
| 10 | super::FLASH_SIZE / 2 > super::ERASE_SIZE | 11 | FLASH_REGIONS.len() == 2 |
| 12 | } | ||
| 13 | |||
| 14 | pub fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 15 | &FLASH_REGIONS | ||
| 11 | } | 16 | } |
| 12 | 17 | ||
| 13 | pub(crate) unsafe fn lock() { | 18 | pub(crate) unsafe fn lock() { |
| @@ -20,90 +25,64 @@ pub(crate) unsafe fn lock() { | |||
| 20 | pub(crate) unsafe fn unlock() { | 25 | pub(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 | ||
| 30 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | 34 | pub(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 | |||
| 38 | pub(crate) unsafe fn end_write() {} | ||
| 39 | |||
| 40 | pub(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 | |||
| 78 | pub(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 | ||
| 103 | unsafe fn erase_sector(bank: pac::flash::Bank, sector: u8) -> Result<(), Error> { | 81 | pub(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 | ||
| 163 | pub(crate) unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { | 142 | unsafe 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 @@ | |||
| 1 | use core::convert::TryInto; | ||
| 2 | use core::ptr::write_volatile; | 1 | use core::ptr::write_volatile; |
| 3 | 2 | ||
| 3 | use atomic_polyfill::{fence, Ordering}; | ||
| 4 | |||
| 5 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | ||
| 4 | use crate::flash::Error; | 6 | use crate::flash::Error; |
| 5 | use crate::pac; | 7 | use crate::pac; |
| 6 | 8 | ||
| 9 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 10 | &FLASH_REGIONS | ||
| 11 | } | ||
| 12 | |||
| 7 | pub(crate) unsafe fn lock() { | 13 | pub(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 | ||
| 36 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | 42 | pub(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 = { | 49 | pub(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 | ||
| 63 | pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { | 54 | pub(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))] | 67 | pub(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 | ||
| 114 | pub(crate) unsafe fn clear_all_err() { | 113 | pub(crate) unsafe fn clear_all_err() { |
| @@ -149,7 +148,7 @@ pub(crate) unsafe fn clear_all_err() { | |||
| 149 | }); | 148 | }); |
| 150 | } | 149 | } |
| 151 | 150 | ||
| 152 | pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { | 151 | unsafe 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 @@ | |||
| 1 | use embassy_hal_common::{into_ref, PeripheralRef}; | 1 | use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; |
| 2 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | ||
| 3 | 2 | ||
| 4 | pub use crate::pac::{ERASE_SIZE, ERASE_VALUE, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; | 3 | #[cfg(flash)] |
| 5 | use crate::peripherals::FLASH; | 4 | mod common; |
| 6 | use crate::Peripheral; | ||
| 7 | const 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")] | 7 | pub 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")] | ||
| 14 | mod family; | ||
| 15 | 8 | ||
| 16 | pub struct Flash<'d> { | 9 | pub use crate::_generated::flash_regions::*; |
| 17 | _inner: PeripheralRef<'d, FLASH>, | 10 | pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; |
| 18 | } | ||
| 19 | 11 | ||
| 20 | impl<'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); | 14 | pub 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; | 25 | pub 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))] | ||
| 34 | pub enum FlashBank { | ||
| 35 | Bank1 = 0, | ||
| 36 | Bank2 = 1, | ||
| 37 | Otp, | ||
| 38 | } | ||
| 68 | 39 | ||
| 69 | unsafe { | 40 | impl 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 | ||
| 82 | impl 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 | )] | ||
| 61 | mod family; | ||
| 62 | |||
| 63 | #[allow(unused_imports)] | ||
| 64 | pub 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 | ||
| 100 | impl<'d> ErrorType for Flash<'d> { | ||
| 101 | type Error = Error; | ||
| 102 | } | ||
| 103 | |||
| 104 | impl NorFlashError for Error { | 78 | impl 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 | |||
| 114 | impl<'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 | |||
| 126 | impl<'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 | |||
| 3 | use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | ||
| 4 | |||
| 5 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 6 | &FLASH_REGIONS | ||
| 7 | } | ||
| 8 | |||
| 9 | pub(crate) unsafe fn lock() { | ||
| 10 | unimplemented!(); | ||
| 11 | } | ||
| 12 | pub(crate) unsafe fn unlock() { | ||
| 13 | unimplemented!(); | ||
| 14 | } | ||
| 15 | pub(crate) unsafe fn begin_write() { | ||
| 16 | unimplemented!(); | ||
| 17 | } | ||
| 18 | pub(crate) unsafe fn end_write() { | ||
| 19 | unimplemented!(); | ||
| 20 | } | ||
| 21 | pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | ||
| 22 | unimplemented!(); | ||
| 23 | } | ||
| 24 | pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> { | ||
| 25 | unimplemented!(); | ||
| 26 | } | ||
| 27 | pub(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)] |
| 45 | pub mod crc; | 45 | pub 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 | ))] | ||
| 49 | pub mod flash; | 46 | pub mod flash; |
| 50 | pub mod pwm; | 47 | pub 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")] |
| 6 | use defmt_rtt as _; | 6 | use defmt_rtt as _; |
| 7 | use embassy_boot_stm32::*; | 7 | use embassy_boot_stm32::*; |
| 8 | use embassy_stm32::flash::{Flash, ERASE_SIZE}; | 8 | use embassy_stm32::flash::Flash; |
| 9 | 9 | ||
| 10 | #[entry] | 10 | #[entry] |
| 11 | fn main() -> ! { | 11 | fn 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 @@ | |||
| 5 | use defmt::{info, unwrap}; | 5 | use defmt::{info, unwrap}; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::flash::Flash; | 7 | use embassy_stm32::flash::Flash; |
| 8 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {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]; |
