From d8b265856f73ae0e7985a6c2fe1a8f0fb811328d Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 05:52:48 +0100 Subject: [PATCH 01/43] Add f4 flash sector computation to hal-common to allow for tests --- embassy-hal-common/src/lib.rs | 1 + embassy-hal-common/src/stm32/flash.rs | 113 ++++++++++++++++++++++++++ embassy-hal-common/src/stm32/mod.rs | 1 + 3 files changed, 115 insertions(+) create mode 100644 embassy-hal-common/src/stm32/flash.rs create mode 100644 embassy-hal-common/src/stm32/mod.rs diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs index b2a35cd3..1b253719 100644 --- a/embassy-hal-common/src/lib.rs +++ b/embassy-hal-common/src/lib.rs @@ -10,4 +10,5 @@ mod macros; mod peripheral; pub mod ratio; pub mod ring_buffer; +pub mod stm32; pub use peripheral::{Peripheral, PeripheralRef}; diff --git a/embassy-hal-common/src/stm32/flash.rs b/embassy-hal-common/src/stm32/flash.rs new file mode 100644 index 00000000..46c42aff --- /dev/null +++ b/embassy-hal-common/src/stm32/flash.rs @@ -0,0 +1,113 @@ +pub mod f4 { + const FLASH_BASE: u32 = 0x08_00_00_00; + pub(crate) const SMALL_SECTOR_SIZE: u32 = 16 * 1024; + pub(crate) const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; + pub(crate) const LARGE_SECTOR_SIZE: u32 = 128 * 1024; + pub const SECOND_BANK_SECTOR_OFFSET: u8 = 12; + + #[derive(Debug, PartialEq)] + pub struct FlashSector { + pub index: u8, + pub size: u32, + } + + pub fn get_sector(addr: u32, dual_bank: bool, flash_size: u32) -> FlashSector { + let offset = addr - FLASH_BASE; + if !dual_bank { + get_single_bank_sector(offset) + } else { + let bank_size = flash_size / 2; + if offset < bank_size { + get_single_bank_sector(offset) + } else { + let sector = get_single_bank_sector(offset - bank_size); + FlashSector { + index: SECOND_BANK_SECTOR_OFFSET + sector.index, + ..sector + } + } + } + } + + fn get_single_bank_sector(offset: u32) -> FlashSector { + // First 4 sectors are 16KB, then one 64KB, and rest are 128KB + + match offset / LARGE_SECTOR_SIZE { + 0 => { + if offset < 4 * SMALL_SECTOR_SIZE { + FlashSector { + index: (offset / SMALL_SECTOR_SIZE) as u8, + size: SMALL_SECTOR_SIZE, + } + } else { + FlashSector { + index: 4, + size: MEDIUM_SECTOR_SIZE, + } + } + } + i => FlashSector { + index: 4 + i as u8, + size: LARGE_SECTOR_SIZE, + }, + } + } +} + +#[cfg(test)] +mod tests { + use super::f4::*; + + #[test] + fn can_get_sector_single_bank() { + let assert_sector = |index: u8, size: u32, addr: u32| { + assert_eq!(FlashSector { index, size }, get_sector(addr, false, 1024 * 1024)) + }; + + assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(3, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(3, SMALL_SECTOR_SIZE, 0x0800_FFFF); + + assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + + assert_sector(5, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(5, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(11, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(11, LARGE_SECTOR_SIZE, 0x080F_FFFF); + } + + #[test] + fn can_get_sector_dual_bank() { + let assert_sector = |index: u8, size: u32, addr: u32| { + assert_eq!(FlashSector { index, size }, get_sector(addr, true, 1024 * 1024)) + }; + + assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(3, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(3, SMALL_SECTOR_SIZE, 0x0800_FFFF); + + assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + + assert_sector(5, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(5, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(7, LARGE_SECTOR_SIZE, 0x0806_0000); + assert_sector(7, LARGE_SECTOR_SIZE, 0x0807_FFFF); + + assert_sector(12, SMALL_SECTOR_SIZE, 0x0808_0000); + assert_sector(12, SMALL_SECTOR_SIZE, 0x0808_3FFF); + assert_sector(15, SMALL_SECTOR_SIZE, 0x0808_C000); + assert_sector(15, SMALL_SECTOR_SIZE, 0x0808_FFFF); + + assert_sector(16, MEDIUM_SECTOR_SIZE, 0x0809_0000); + assert_sector(16, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); + + assert_sector(17, LARGE_SECTOR_SIZE, 0x080A_0000); + assert_sector(17, LARGE_SECTOR_SIZE, 0x080B_FFFF); + assert_sector(19, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(19, LARGE_SECTOR_SIZE, 0x080F_FFFF); + } +} diff --git a/embassy-hal-common/src/stm32/mod.rs b/embassy-hal-common/src/stm32/mod.rs new file mode 100644 index 00000000..2e50f82b --- /dev/null +++ b/embassy-hal-common/src/stm32/mod.rs @@ -0,0 +1 @@ +pub mod flash; From cccceb88f2c91adcbdc6c1d07d785a97742f996b Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 05:57:15 +0100 Subject: [PATCH 02/43] Generate flash regions during build --- embassy-stm32/build.rs | 76 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index dbfc1370..89281912 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -5,7 +5,7 @@ use std::{env, fs}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; -use stm32_metapac::metadata::METADATA; +use stm32_metapac::metadata::{MemoryRegionKind, METADATA}; fn main() { let chip_name = match env::vars() @@ -103,6 +103,68 @@ fn main() { } }); + // ======== + // Generate FLASH regions + let mut flash_regions = TokenStream::new(); + let flash_memory_regions = METADATA + .memory + .iter() + .filter(|x| x.kind == MemoryRegionKind::Flash || x.kind == MemoryRegionKind::Otp); + for region in flash_memory_regions.clone() { + let region_name = format_ident!("{}", region.name); + let base = region.address as usize; + let size = region.size as usize; + let settings = region.settings.as_ref().unwrap(); + let erase_size = settings.erase_size as usize; + let write_size = settings.write_size as usize; + let erase_value = settings.erase_value; + + flash_regions.extend(quote! { + pub struct #region_name(()); + }); + + flash_regions.extend(quote! { + impl crate::flash::FlashRegion for #region_name { + const BASE: usize = #base; + const SIZE: usize = #size; + const ERASE_SIZE: usize = #erase_size; + const WRITE_SIZE: usize = #write_size; + const ERASE_VALUE: u8 = #erase_value; + } + }); + } + + let (fields, inits): (Vec, Vec) = flash_memory_regions + .map(|f| { + let field_name = format_ident!("{}", f.name.to_lowercase()); + let field_type = format_ident!("{}", f.name); + let field = quote! { + pub #field_name: #field_type + }; + let init = quote! { + #field_name: #field_type(()) + }; + + (field, init) + }) + .unzip(); + + flash_regions.extend(quote! { + pub struct FlashRegions { + #(#fields),* + } + + impl FlashRegions { + pub(crate) const fn take() -> Self { + Self { + #(#inits),* + } + } + } + }); + + g.extend(quote! { pub mod flash_regions { #flash_regions } }); + // ======== // Generate DMA IRQs. @@ -558,11 +620,22 @@ fn main() { // ======== // Write foreach_foo! macrotables + let mut flash_regions_table: Vec> = Vec::new(); let mut interrupts_table: Vec> = Vec::new(); let mut peripherals_table: Vec> = Vec::new(); let mut pins_table: Vec> = Vec::new(); let mut dma_channels_table: Vec> = Vec::new(); + for m in METADATA + .memory + .iter() + .filter(|m| m.kind == MemoryRegionKind::Flash || m.kind == MemoryRegionKind::Otp) + { + let mut row = Vec::new(); + row.push(m.name.to_string()); + flash_regions_table.push(row); + } + let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32; let gpio_stride = 0x400; @@ -659,6 +732,7 @@ fn main() { let mut m = String::new(); + make_table(&mut m, "foreach_flash_region", &flash_regions_table); make_table(&mut m, "foreach_interrupt", &interrupts_table); make_table(&mut m, "foreach_peripheral", &peripherals_table); make_table(&mut m, "foreach_pin", &pins_table); From 6b44027eab273d1589eb289044d1bd4d172477f6 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 05:58:40 +0100 Subject: [PATCH 03/43] Add FlashRegion trait and implement embedded_storage traits for each region --- embassy-stm32/src/flash/mod.rs | 162 +++++++++++++++++++++++---------- 1 file changed, 116 insertions(+), 46 deletions(-) diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index b7166a43..b6cecfdb 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -1,10 +1,10 @@ use embassy_hal_common::{into_ref, PeripheralRef}; use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; -pub use crate::pac::{ERASE_SIZE, ERASE_VALUE, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +pub use crate::_generated::flash_regions::*; +pub use crate::pac::{FLASH_BASE, FLASH_SIZE}; use crate::peripherals::FLASH; use crate::Peripheral; -const FLASH_END: usize = FLASH_BASE + FLASH_SIZE; #[cfg_attr(any(flash_wl, flash_wb, flash_l0, flash_l1, flash_l4), path = "l.rs")] #[cfg_attr(flash_f3, path = "f3.rs")] @@ -23,60 +23,63 @@ impl<'d> Flash<'d> { Self { _inner: p } } + pub fn into_regions(self) -> FlashRegions { + FlashRegions::take() + } + pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - let offset = FLASH_BASE as u32 + offset; - if offset as usize >= FLASH_END || offset as usize + bytes.len() > FLASH_END { + if offset as usize + bytes.len() > FLASH_SIZE { return Err(Error::Size); } - let flash_data = unsafe { core::slice::from_raw_parts(offset as *const u8, bytes.len()) }; + let first_address = FLASH_BASE as u32 + offset; + + let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; bytes.copy_from_slice(flash_data); Ok(()) } pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { - let offset = FLASH_BASE as u32 + offset; - if offset as usize + buf.len() > FLASH_END { + if offset as usize + buf.len() > FLASH_SIZE { return Err(Error::Size); } - if offset as usize % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { + if offset as usize % family::MAX_WRITE_SIZE != 0 || buf.len() as usize % family::MAX_WRITE_SIZE != 0 { return Err(Error::Unaligned); } - trace!("Writing {} bytes at 0x{:x}", buf.len(), offset); - self.clear_all_err(); + let first_address = FLASH_BASE as u32 + offset; + trace!("Writing {} bytes at 0x{:x}", buf.len(), first_address); unsafe { + family::clear_all_err(); + family::unlock(); - let res = family::blocking_write(offset, buf); + let res = family::blocking_write(first_address, buf); family::lock(); res } } pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let from = FLASH_BASE as u32 + from; - let to = FLASH_BASE as u32 + to; - if to < from || to as usize > FLASH_END { + if to < from || to as usize > FLASH_SIZE { return Err(Error::Size); } - if (from as usize % ERASE_SIZE) != 0 || (to as usize % ERASE_SIZE) != 0 { + if (from as usize % family::MAX_ERASE_SIZE) != 0 || (to as usize % family::MAX_ERASE_SIZE) != 0 { return Err(Error::Unaligned); } - self.clear_all_err(); + let from_address = FLASH_BASE as u32 + from; + let to_address = FLASH_BASE as u32 + to; unsafe { + family::clear_all_err(); + family::unlock(); - let res = family::blocking_erase(from, to); + let res = family::blocking_erase(from_address, to_address); family::lock(); res } } - - fn clear_all_err(&mut self) { - unsafe { family::clear_all_err() }; - } } impl Drop for Flash<'_> { @@ -85,6 +88,69 @@ impl Drop for Flash<'_> { } } +pub trait FlashRegion { + const BASE: usize; + const SIZE: usize; + const ERASE_SIZE: usize; + const WRITE_SIZE: usize; + const ERASE_VALUE: u8; + + fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + if offset as usize + bytes.len() > Self::SIZE { + return Err(Error::Size); + } + + let first_address = Self::BASE as u32 + offset; + + let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; + bytes.copy_from_slice(flash_data); + Ok(()) + } + + fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { + if offset as usize + buf.len() > Self::SIZE { + return Err(Error::Size); + } + if offset as usize % Self::WRITE_SIZE != 0 || buf.len() as usize % Self::WRITE_SIZE != 0 { + return Err(Error::Unaligned); + } + + let first_address = Self::BASE as u32 + offset; + trace!("Writing {} bytes from 0x{:x}", buf.len(), first_address); + + critical_section::with(|_| unsafe { + family::clear_all_err(); + + family::unlock(); + let res = family::blocking_write(first_address, buf); + family::lock(); + res + }) + } + + fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { + if to < from || to as usize > Self::SIZE { + return Err(Error::Size); + } + if (from as usize % Self::ERASE_SIZE) != 0 || (to as usize % Self::ERASE_SIZE) != 0 { + return Err(Error::Unaligned); + } + + let from_address = Self::BASE as u32 + from; + let to_address = Self::BASE as u32 + to; + trace!("Erasing from 0x{:x} to 0x{:x}", from_address, to_address); + + critical_section::with(|_| unsafe { + family::clear_all_err(); + + family::unlock(); + let res = family::blocking_erase(from_address, to_address); + family::lock(); + res + }) + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { @@ -97,10 +163,6 @@ pub enum Error { Parallelism, } -impl<'d> ErrorType for Flash<'d> { - type Error = Error; -} - impl NorFlashError for Error { fn kind(&self) -> NorFlashErrorKind { match self { @@ -111,27 +173,35 @@ impl NorFlashError for Error { } } -impl<'d> ReadNorFlash for Flash<'d> { - const READ_SIZE: usize = WRITE_SIZE; +foreach_flash_region! { + ($name:ident) => { + impl ErrorType for crate::_generated::flash_regions::$name { + type Error = Error; + } - fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(offset, bytes) - } + impl ReadNorFlash for crate::_generated::flash_regions::$name { + const READ_SIZE: usize = ::WRITE_SIZE; - fn capacity(&self) -> usize { - FLASH_SIZE - } -} - -impl<'d> NorFlash for Flash<'d> { - const WRITE_SIZE: usize = WRITE_SIZE; - const ERASE_SIZE: usize = ERASE_SIZE; - - fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - self.blocking_erase(from, to) - } - - fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(offset, bytes) - } + fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(offset, bytes) + } + + fn capacity(&self) -> usize { + ::SIZE + } + } + + impl NorFlash for crate::_generated::flash_regions::$name { + const WRITE_SIZE: usize = ::WRITE_SIZE; + const ERASE_SIZE: usize = ::ERASE_SIZE; + + fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + self.blocking_erase(from, to) + } + + fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(offset, bytes) + } + } + }; } From 6c73b23f384b4814ad9d13e8d108ef71464f72af Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 05:59:40 +0100 Subject: [PATCH 04/43] Align F4 family --- embassy-stm32/src/flash/f4.rs | 70 ++++++++++------------------------- 1 file changed, 19 insertions(+), 51 deletions(-) diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 9e23a8ad..d739c46b 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -1,12 +1,16 @@ use core::convert::TryInto; +use core::mem::size_of; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{ERASE_SIZE, FLASH_BASE, FLASH_SIZE}; +use embassy_hal_common::stm32::flash::f4::{get_sector, SECOND_BANK_SECTOR_OFFSET}; + +use super::{FlashRegion, FLASH_SIZE, MAINC}; use crate::flash::Error; use crate::pac; -const SECOND_BANK_SECTOR_START: u32 = 12; +pub(crate) const MAX_WRITE_SIZE: usize = MAINC::WRITE_SIZE; +pub(crate) const MAX_ERASE_SIZE: usize = MAINC::ERASE_SIZE; unsafe fn is_dual_bank() -> bool { match FLASH_SIZE / 1024 { @@ -34,7 +38,7 @@ pub(crate) unsafe fn unlock() { pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); } -pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { +pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<(), Error> { pac::FLASH.cr().write(|w| { w.set_pg(true); w.set_psize(pac::flash::vals::Psize::PSIZE32); @@ -42,10 +46,12 @@ pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error let ret = { let mut ret: Result<(), Error> = Ok(()); - let mut offset = offset; - for chunk in buf.chunks(super::WRITE_SIZE) { - for val in chunk.chunks(4) { - write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap())); + let mut offset = first_address; + for chunk in buf.chunks(MAX_WRITE_SIZE) { + let vals = chunk.chunks_exact(size_of::()); + assert!(vals.remainder().is_empty()); + for val in vals { + write_volatile(offset as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); offset += val.len() as u32; // prevents parallelism errors @@ -65,50 +71,12 @@ pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error ret } -struct FlashSector { - index: u8, - size: u32, -} - -fn get_sector(addr: u32, dual_bank: bool) -> FlashSector { - let offset = addr - FLASH_BASE as u32; - - let bank_size = match dual_bank { - true => FLASH_SIZE / 2, - false => FLASH_SIZE, - } as u32; - - let bank = offset / bank_size; - let offset_in_bank = offset % bank_size; - - let index_in_bank = if offset_in_bank >= ERASE_SIZE as u32 / 2 { - 4 + offset_in_bank / ERASE_SIZE as u32 - } else { - offset_in_bank / (ERASE_SIZE as u32 / 8) - }; - - // First 4 sectors are 16KB, then one 64KB, and rest are 128KB - let size = match index_in_bank { - 0..=3 => 16 * 1024, - 4 => 64 * 1024, - _ => 128 * 1024, - }; - - let index = if bank == 1 { - SECOND_BANK_SECTOR_START + index_in_bank - } else { - index_in_bank - } as u8; - - FlashSector { index, size } -} - -pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { - let mut addr = from; +pub(crate) unsafe fn blocking_erase(from_address: u32, to_address: u32) -> Result<(), Error> { + let mut addr = from_address; let dual_bank = is_dual_bank(); - while addr < to { - let sector = get_sector(addr, dual_bank); + while addr < to_address { + let sector = get_sector(addr, dual_bank, FLASH_SIZE as u32); erase_sector(sector.index)?; addr += sector.size; } @@ -117,8 +85,8 @@ pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { } unsafe fn erase_sector(sector: u8) -> Result<(), Error> { - let bank = sector / SECOND_BANK_SECTOR_START as u8; - let snb = (bank << 4) + (sector % SECOND_BANK_SECTOR_START as u8); + let bank = sector / SECOND_BANK_SECTOR_OFFSET as u8; + let snb = (bank << 4) + (sector % SECOND_BANK_SECTOR_OFFSET as u8); trace!("Erasing sector: {}", sector); From 7edd72f8f542e81143d2375f1783418404d1dc58 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 06:05:37 +0100 Subject: [PATCH 05/43] Align F3 family --- embassy-stm32/src/flash/f3.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 1cb08ee1..294fcffc 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -1,9 +1,14 @@ use core::convert::TryInto; +use core::mem::size_of; use core::ptr::write_volatile; +use super::FlashRegion; use crate::flash::Error; use crate::pac; +pub(crate) const MAX_WRITE_SIZE: usize = super::MAINA::WRITE_SIZE; +pub(crate) const MAX_ERASE_SIZE: usize = super::MAINA::ERASE_SIZE; + pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -13,15 +18,17 @@ pub(crate) unsafe fn unlock() { pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); } -pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { +pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<(), Error> { pac::FLASH.cr().write(|w| w.set_pg(true)); let ret = { let mut ret: Result<(), Error> = Ok(()); - let mut offset = offset; - for chunk in buf.chunks(2) { - write_volatile(offset as *mut u16, u16::from_le_bytes(chunk[0..2].try_into().unwrap())); - offset += chunk.len() as u32; + let mut address = first_address; + let chunks = buf.chunks_exact(size_of::()); + assert!(chunks.remainder().is_empty()); + for chunk in chunks { + write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap())); + address += chunk.len() as u32; ret = blocking_wait_ready(); if ret.is_err() { @@ -36,8 +43,8 @@ pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error ret } -pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { - for page in (from..to).step_by(super::ERASE_SIZE) { +pub(crate) unsafe fn blocking_erase(from_address: u32, to_address: u32) -> Result<(), Error> { + for page in (from_address..to_address).step_by(MAX_ERASE_SIZE) { pac::FLASH.cr().modify(|w| { w.set_per(true); }); From 99c4346579cd000128d6b14aca98968bc4bbad22 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 06:25:12 +0100 Subject: [PATCH 06/43] Add f7 computation to hal common and add tests --- .../src/stm32/{flash.rs => flash/f4.rs} | 82 +++++++++---------- embassy-hal-common/src/stm32/flash/f7.rs | 57 +++++++++++++ embassy-hal-common/src/stm32/flash/mod.rs | 2 + 3 files changed, 99 insertions(+), 42 deletions(-) rename embassy-hal-common/src/stm32/{flash.rs => flash/f4.rs} (61%) create mode 100644 embassy-hal-common/src/stm32/flash/f7.rs create mode 100644 embassy-hal-common/src/stm32/flash/mod.rs diff --git a/embassy-hal-common/src/stm32/flash.rs b/embassy-hal-common/src/stm32/flash/f4.rs similarity index 61% rename from embassy-hal-common/src/stm32/flash.rs rename to embassy-hal-common/src/stm32/flash/f4.rs index 46c42aff..44d6c08c 100644 --- a/embassy-hal-common/src/stm32/flash.rs +++ b/embassy-hal-common/src/stm32/flash/f4.rs @@ -1,62 +1,60 @@ -pub mod f4 { - const FLASH_BASE: u32 = 0x08_00_00_00; - pub(crate) const SMALL_SECTOR_SIZE: u32 = 16 * 1024; - pub(crate) const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; - pub(crate) const LARGE_SECTOR_SIZE: u32 = 128 * 1024; - pub const SECOND_BANK_SECTOR_OFFSET: u8 = 12; +const FLASH_BASE: u32 = 0x0800_0000; +pub(crate) const SMALL_SECTOR_SIZE: u32 = 16 * 1024; +pub(crate) const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; +pub(crate) const LARGE_SECTOR_SIZE: u32 = 128 * 1024; +pub const SECOND_BANK_SECTOR_OFFSET: u8 = 12; - #[derive(Debug, PartialEq)] - pub struct FlashSector { - pub index: u8, - pub size: u32, - } +#[derive(Debug, PartialEq)] +pub struct FlashSector { + pub index: u8, + pub size: u32, +} - pub fn get_sector(addr: u32, dual_bank: bool, flash_size: u32) -> FlashSector { - let offset = addr - FLASH_BASE; - if !dual_bank { +pub fn get_sector(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector { + let offset = address - FLASH_BASE; + if !dual_bank { + get_single_bank_sector(offset) + } else { + let bank_size = flash_size / 2; + if offset < bank_size { get_single_bank_sector(offset) } else { - let bank_size = flash_size / 2; - if offset < bank_size { - get_single_bank_sector(offset) - } else { - let sector = get_single_bank_sector(offset - bank_size); - FlashSector { - index: SECOND_BANK_SECTOR_OFFSET + sector.index, - ..sector - } + let sector = get_single_bank_sector(offset - bank_size); + FlashSector { + index: SECOND_BANK_SECTOR_OFFSET + sector.index, + ..sector } } } +} - fn get_single_bank_sector(offset: u32) -> FlashSector { - // First 4 sectors are 16KB, then one 64KB, and rest are 128KB +fn get_single_bank_sector(offset: u32) -> FlashSector { + // First 4 sectors are 16KB, then one 64KB, and rest are 128KB - match offset / LARGE_SECTOR_SIZE { - 0 => { - if offset < 4 * SMALL_SECTOR_SIZE { - FlashSector { - index: (offset / SMALL_SECTOR_SIZE) as u8, - size: SMALL_SECTOR_SIZE, - } - } else { - FlashSector { - index: 4, - size: MEDIUM_SECTOR_SIZE, - } + match offset / LARGE_SECTOR_SIZE { + 0 => { + if offset < 4 * SMALL_SECTOR_SIZE { + FlashSector { + index: (offset / SMALL_SECTOR_SIZE) as u8, + size: SMALL_SECTOR_SIZE, + } + } else { + FlashSector { + index: 4, + size: MEDIUM_SECTOR_SIZE, } } - i => FlashSector { - index: 4 + i as u8, - size: LARGE_SECTOR_SIZE, - }, } + i => FlashSector { + index: 4 + i as u8, + size: LARGE_SECTOR_SIZE, + }, } } #[cfg(test)] mod tests { - use super::f4::*; + use super::*; #[test] fn can_get_sector_single_bank() { diff --git a/embassy-hal-common/src/stm32/flash/f7.rs b/embassy-hal-common/src/stm32/flash/f7.rs new file mode 100644 index 00000000..90938e6a --- /dev/null +++ b/embassy-hal-common/src/stm32/flash/f7.rs @@ -0,0 +1,57 @@ +const FLASH_BASE: u32 = 0x0800_0000; +pub(crate) const SMALL_SECTOR_SIZE: u32 = 32 * 1024; +pub(crate) const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024; +pub(crate) const LARGE_SECTOR_SIZE: u32 = 256 * 1024; + +#[derive(Debug, PartialEq)] +pub struct FlashSector { + pub index: u8, + pub size: u32, +} + +pub fn get_sector(address: u32) -> FlashSector { + // First 4 sectors are 32KB, then one 128KB, and rest are 256KB + let offset = address - FLASH_BASE; + match offset / LARGE_SECTOR_SIZE { + 0 => { + if offset < 4 * SMALL_SECTOR_SIZE { + FlashSector { + index: (offset / SMALL_SECTOR_SIZE) as u8, + size: SMALL_SECTOR_SIZE, + } + } else { + FlashSector { + index: 4, + size: MEDIUM_SECTOR_SIZE, + } + } + } + i => FlashSector { + index: 4 + i as u8, + size: LARGE_SECTOR_SIZE, + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_get_sector() { + let assert_sector = |index: u8, size: u32, addr: u32| assert_eq!(FlashSector { index, size }, get_sector(addr)); + + assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_7FFF); + assert_sector(3, SMALL_SECTOR_SIZE, 0x0801_8000); + assert_sector(3, SMALL_SECTOR_SIZE, 0x0801_FFFF); + + assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0802_0000); + assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0803_FFFF); + + assert_sector(5, LARGE_SECTOR_SIZE, 0x0804_0000); + assert_sector(5, LARGE_SECTOR_SIZE, 0x0807_FFFF); + assert_sector(7, LARGE_SECTOR_SIZE, 0x080C_0000); + assert_sector(7, LARGE_SECTOR_SIZE, 0x080F_FFFF); + } +} diff --git a/embassy-hal-common/src/stm32/flash/mod.rs b/embassy-hal-common/src/stm32/flash/mod.rs new file mode 100644 index 00000000..1452b491 --- /dev/null +++ b/embassy-hal-common/src/stm32/flash/mod.rs @@ -0,0 +1,2 @@ +pub mod f4; +pub mod f7; From a8567f06174c7a3fc2c708a2acb3763d9a59c8b7 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 06:26:00 +0100 Subject: [PATCH 07/43] Align F7 family --- embassy-stm32/src/flash/f7.rs | 39 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index dd0d8439..ee0513fa 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -1,10 +1,17 @@ use core::convert::TryInto; +use core::mem::size_of; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; +use embassy_hal_common::stm32::flash::f7::get_sector; + +use super::FlashRegion; use crate::flash::Error; use crate::pac; +pub(crate) const MAX_WRITE_SIZE: usize = super::MAINC::WRITE_SIZE; +pub(crate) const MAX_ERASE_SIZE: usize = super::MAINC::ERASE_SIZE; + pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -14,7 +21,7 @@ pub(crate) unsafe fn unlock() { pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); } -pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { +pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<(), Error> { pac::FLASH.cr().write(|w| { w.set_pg(true); w.set_psize(pac::flash::vals::Psize::PSIZE32); @@ -22,11 +29,13 @@ pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error let ret = { let mut ret: Result<(), Error> = Ok(()); - let mut offset = offset; - for chunk in buf.chunks(super::WRITE_SIZE) { - for val in chunk.chunks(4) { - write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap())); - offset += val.len() as u32; + let mut address = first_address; + for chunk in buf.chunks(MAX_WRITE_SIZE) { + let vals = chunk.chunks_exact(size_of::()); + assert!(vals.remainder().is_empty()); + for val in vals { + write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); + address += val.len() as u32; // prevents parallelism errors fence(Ordering::SeqCst); @@ -45,20 +54,10 @@ pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error ret } -pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { - let start_sector = if from >= (super::FLASH_BASE + super::ERASE_SIZE / 2) as u32 { - 4 + (from - super::FLASH_BASE as u32) / super::ERASE_SIZE as u32 - } else { - (from - super::FLASH_BASE as u32) / (super::ERASE_SIZE as u32 / 8) - }; - - let end_sector = if to >= (super::FLASH_BASE + super::ERASE_SIZE / 2) as u32 { - 4 + (to - super::FLASH_BASE as u32) / super::ERASE_SIZE as u32 - } else { - (to - super::FLASH_BASE as u32) / (super::ERASE_SIZE as u32 / 8) - }; - - for sector in start_sector..end_sector { +pub(crate) unsafe fn blocking_erase(from_address: u32, to_address: u32) -> Result<(), Error> { + let start_sector = get_sector(from_address); + let end_sector = get_sector(to_address); + for sector in start_sector.index..end_sector.index { let ret = erase_sector(sector as u8); if ret.is_err() { return ret; From c848bd9c9c0589e987918fb72647b9002f0eb4e4 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 13:02:42 +0100 Subject: [PATCH 08/43] Align with removal of MemoryRegionKind::Otp --- embassy-stm32/build.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 89281912..ca55681f 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -109,9 +109,9 @@ fn main() { let flash_memory_regions = METADATA .memory .iter() - .filter(|x| x.kind == MemoryRegionKind::Flash || x.kind == MemoryRegionKind::Otp); + .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()); for region in flash_memory_regions.clone() { - let region_name = format_ident!("{}", region.name); + let region_name = format_ident!("{}", region.name.replace("_", "")); let base = region.address as usize; let size = region.size as usize; let settings = region.settings.as_ref().unwrap(); @@ -136,8 +136,9 @@ fn main() { let (fields, inits): (Vec, Vec) = flash_memory_regions .map(|f| { - let field_name = format_ident!("{}", f.name.to_lowercase()); - let field_type = format_ident!("{}", f.name); + let trimmed_name = f.name.replace("_", ""); + let field_name = format_ident!("{}", trimmed_name.to_lowercase()); + let field_type = format_ident!("{}", trimmed_name); let field = quote! { pub #field_name: #field_type }; @@ -629,10 +630,10 @@ fn main() { for m in METADATA .memory .iter() - .filter(|m| m.kind == MemoryRegionKind::Flash || m.kind == MemoryRegionKind::Otp) + .filter(|m| m.kind == MemoryRegionKind::Flash && m.settings.is_some()) { let mut row = Vec::new(); - row.push(m.name.to_string()); + row.push(m.name.replace("_", "")); flash_regions_table.push(row); } From 47e07584cacf9b632736185d95be2f703df9a8f8 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 13:03:00 +0100 Subject: [PATCH 09/43] Align H7 family --- embassy-stm32/src/flash/h7.rs | 41 ++++++++++++++++------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 7de95ac1..6ab8e7b7 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -1,13 +1,19 @@ use core::convert::TryInto; +use core::mem::size_of; use core::ptr::write_volatile; +use super::{FlashRegion, FLASH_SIZE}; use crate::flash::Error; use crate::pac; +const WRITE_SIZE: usize = super::BANK1::WRITE_SIZE; +const ERASE_SIZE: usize = super::BANK1::ERASE_SIZE; +pub(crate) const MAX_WRITE_SIZE: usize = WRITE_SIZE; +pub(crate) const MAX_ERASE_SIZE: usize = ERASE_SIZE; const SECOND_BANK_OFFSET: usize = 0x0010_0000; const fn is_dual_bank() -> bool { - super::FLASH_SIZE / 2 > super::ERASE_SIZE + FLASH_SIZE / 2 > ERASE_SIZE } pub(crate) unsafe fn lock() { @@ -27,8 +33,8 @@ pub(crate) unsafe fn unlock() { } } -pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { - let bank = if !is_dual_bank() || (offset - super::FLASH_BASE as u32) < SECOND_BANK_OFFSET as u32 { +pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<(), Error> { + let bank = if !is_dual_bank() || (first_address - super::FLASH_BASE as u32) < SECOND_BANK_OFFSET as u32 { pac::FLASH.bank(0) } else { pac::FLASH.bank(1) @@ -45,12 +51,13 @@ pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error let ret = { let mut ret: Result<(), Error> = Ok(()); - let mut offset = offset; - 'outer: for chunk in buf.chunks(super::WRITE_SIZE) { - for val in chunk.chunks(4) { - trace!("Writing at {:x}", offset); - write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap())); - offset += val.len() as u32; + let mut address = first_address; + 'outer: for chunk in buf.chunks(WRITE_SIZE) { + let vals = chunk.chunks_exact(size_of::()); + assert!(vals.remainder().is_empty()); + for val in vals { + write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); + address += val.len() as u32; ret = blocking_wait_ready(bank); bank.sr().modify(|w| { @@ -76,20 +83,10 @@ pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error } pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { - let from = from - super::FLASH_BASE as u32; - let to = to - super::FLASH_BASE as u32; + let start_sector = (from - super::FLASH_BASE as u32) / ERASE_SIZE as u32; + let end_sector = (to - super::FLASH_BASE as u32) / ERASE_SIZE as u32; - let (start, end) = if to <= super::FLASH_SIZE as u32 { - let start_sector = from / super::ERASE_SIZE as u32; - let end_sector = to / super::ERASE_SIZE as u32; - (start_sector, end_sector) - } else { - error!("Attempting to write outside of defined sectors {:x} {:x}", from, to); - return Err(Error::Unaligned); - }; - - trace!("Erasing sectors from {} to {}", start, end); - for sector in start..end { + for sector in start_sector..end_sector { let bank = if sector >= 8 { 1 } else { 0 }; let ret = erase_sector(pac::FLASH.bank(bank), (sector % 8) as u8); if ret.is_err() { From 47d5f127bb307f441bc7765d6d053ce41168ce53 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 13:30:24 +0100 Subject: [PATCH 10/43] Align L family --- embassy-stm32/src/flash/l.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 5048a331..9ab732b8 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -1,9 +1,15 @@ use core::convert::TryInto; use core::ptr::write_volatile; +use super::FlashRegion; use crate::flash::Error; use crate::pac; +const WRITE_SIZE: usize = super::BANK1::WRITE_SIZE; +const ERASE_SIZE: usize = super::BANK1::ERASE_SIZE; +pub(crate) const MAX_WRITE_SIZE: usize = WRITE_SIZE; +pub(crate) const MAX_ERASE_SIZE: usize = ERASE_SIZE; + pub(crate) unsafe fn lock() { #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().modify(|w| w.set_lock(true)); @@ -33,17 +39,17 @@ pub(crate) unsafe fn unlock() { } } -pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { +pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<(), Error> { #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().write(|w| w.set_pg(true)); let ret = { let mut ret: Result<(), Error> = Ok(()); - let mut offset = offset; - for chunk in buf.chunks(super::WRITE_SIZE) { + let mut address = first_address; + for chunk in buf.chunks(WRITE_SIZE) { for val in chunk.chunks(4) { - write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap())); - offset += val.len() as u32; + write_volatile(address as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap())); + address += val.len() as u32; } ret = blocking_wait_ready(); @@ -60,8 +66,8 @@ pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error ret } -pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { - for page in (from..to).step_by(super::ERASE_SIZE) { +pub(crate) unsafe fn blocking_erase(from_address: u32, to_address: u32) -> Result<(), Error> { + for page in (from_address..to_address).step_by(ERASE_SIZE) { #[cfg(any(flash_l0, flash_l1))] { pac::FLASH.pecr().modify(|w| { @@ -74,7 +80,7 @@ pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { #[cfg(any(flash_wl, flash_wb, flash_l4))] { - let idx = (page - super::FLASH_BASE as u32) / super::ERASE_SIZE as u32; + let idx = (page - super::FLASH_BASE as u32) / ERASE_SIZE as u32; #[cfg(flash_l4)] let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; From 73ccc04231adb4c4e2f00c3ecaea8481afb218d4 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 13:39:10 +0100 Subject: [PATCH 11/43] Change region type name --- embassy-stm32/build.rs | 15 ++++++++++----- embassy-stm32/src/flash/f3.rs | 4 ++-- embassy-stm32/src/flash/f4.rs | 12 ++++++------ embassy-stm32/src/flash/f7.rs | 4 ++-- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ca55681f..393efc42 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -111,7 +111,7 @@ fn main() { .iter() .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()); for region in flash_memory_regions.clone() { - let region_name = format_ident!("{}", region.name.replace("_", "")); + let region_name = format_ident!("{}", get_flash_region_name(region.name)); let base = region.address as usize; let size = region.size as usize; let settings = region.settings.as_ref().unwrap(); @@ -120,6 +120,7 @@ fn main() { let erase_value = settings.erase_value; flash_regions.extend(quote! { + #[allow(non_camel_case_types)] pub struct #region_name(()); }); @@ -136,9 +137,9 @@ fn main() { let (fields, inits): (Vec, Vec) = flash_memory_regions .map(|f| { - let trimmed_name = f.name.replace("_", ""); - let field_name = format_ident!("{}", trimmed_name.to_lowercase()); - let field_type = format_ident!("{}", trimmed_name); + let region_name = get_flash_region_name(f.name); + let field_name = format_ident!("{}", region_name.to_lowercase()); + let field_type = format_ident!("{}", region_name); let field = quote! { pub #field_name: #field_type }; @@ -633,7 +634,7 @@ fn main() { .filter(|m| m.kind == MemoryRegionKind::Flash && m.settings.is_some()) { let mut row = Vec::new(); - row.push(m.name.replace("_", "")); + row.push(get_flash_region_name(m.name)); flash_regions_table.push(row); } @@ -886,3 +887,7 @@ macro_rules! {} {{ ) .unwrap(); } + +fn get_flash_region_name(name: &str) -> String { + name.replace("BANK_", "BANK").replace("REGION_", "REGION") +} diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 294fcffc..b24dfb4a 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -6,8 +6,8 @@ use super::FlashRegion; use crate::flash::Error; use crate::pac; -pub(crate) const MAX_WRITE_SIZE: usize = super::MAINA::WRITE_SIZE; -pub(crate) const MAX_ERASE_SIZE: usize = super::MAINA::ERASE_SIZE; +pub(crate) const MAX_WRITE_SIZE: usize = super::BANK1::WRITE_SIZE; +pub(crate) const MAX_ERASE_SIZE: usize = super::BANK1::ERASE_SIZE; pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index d739c46b..0d9d405b 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -5,12 +5,12 @@ use core::sync::atomic::{fence, Ordering}; use embassy_hal_common::stm32::flash::f4::{get_sector, SECOND_BANK_SECTOR_OFFSET}; -use super::{FlashRegion, FLASH_SIZE, MAINC}; +use super::{FlashRegion, FLASH_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const MAX_WRITE_SIZE: usize = MAINC::WRITE_SIZE; -pub(crate) const MAX_ERASE_SIZE: usize = MAINC::ERASE_SIZE; +pub(crate) const MAX_WRITE_SIZE: usize = super::BANK1_REGION3::WRITE_SIZE; +pub(crate) const MAX_ERASE_SIZE: usize = super::BANK1_REGION3::ERASE_SIZE; unsafe fn is_dual_bank() -> bool { match FLASH_SIZE / 1024 { @@ -46,13 +46,13 @@ pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<() let ret = { let mut ret: Result<(), Error> = Ok(()); - let mut offset = first_address; + let mut address = first_address; for chunk in buf.chunks(MAX_WRITE_SIZE) { let vals = chunk.chunks_exact(size_of::()); assert!(vals.remainder().is_empty()); for val in vals { - write_volatile(offset as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); - offset += val.len() as u32; + write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); + address += val.len() as u32; // prevents parallelism errors fence(Ordering::SeqCst); diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index ee0513fa..8b8076e0 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -9,8 +9,8 @@ use super::FlashRegion; use crate::flash::Error; use crate::pac; -pub(crate) const MAX_WRITE_SIZE: usize = super::MAINC::WRITE_SIZE; -pub(crate) const MAX_ERASE_SIZE: usize = super::MAINC::ERASE_SIZE; +pub(crate) const MAX_WRITE_SIZE: usize = super::BANK1_REGION3::WRITE_SIZE; +pub(crate) const MAX_ERASE_SIZE: usize = super::BANK1_REGION3::ERASE_SIZE; pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); From 245147634bfbdcd325eea20be19286708bb29c9f Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 16:03:06 +0100 Subject: [PATCH 12/43] Add region start to flash sectors --- embassy-hal-common/src/stm32/flash/f4.rs | 90 +++++++++++++----------- embassy-hal-common/src/stm32/flash/f7.rs | 42 ++++++----- 2 files changed, 75 insertions(+), 57 deletions(-) diff --git a/embassy-hal-common/src/stm32/flash/f4.rs b/embassy-hal-common/src/stm32/flash/f4.rs index 44d6c08c..a8069ddd 100644 --- a/embassy-hal-common/src/stm32/flash/f4.rs +++ b/embassy-hal-common/src/stm32/flash/f4.rs @@ -7,6 +7,7 @@ pub const SECOND_BANK_SECTOR_OFFSET: u8 = 12; #[derive(Debug, PartialEq)] pub struct FlashSector { pub index: u8, + pub start: u32, pub size: u32, } @@ -22,7 +23,8 @@ pub fn get_sector(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector let sector = get_single_bank_sector(offset - bank_size); FlashSector { index: SECOND_BANK_SECTOR_OFFSET + sector.index, - ..sector + start: sector.start + bank_size, + size: sector.size, } } } @@ -30,25 +32,31 @@ pub fn get_sector(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector fn get_single_bank_sector(offset: u32) -> FlashSector { // First 4 sectors are 16KB, then one 64KB, and rest are 128KB - match offset / LARGE_SECTOR_SIZE { 0 => { if offset < 4 * SMALL_SECTOR_SIZE { + let small_sector_index = offset / SMALL_SECTOR_SIZE; FlashSector { - index: (offset / SMALL_SECTOR_SIZE) as u8, + index: small_sector_index as u8, + start: FLASH_BASE + small_sector_index * SMALL_SECTOR_SIZE, size: SMALL_SECTOR_SIZE, } } else { FlashSector { index: 4, + start: FLASH_BASE + 4 * SMALL_SECTOR_SIZE, size: MEDIUM_SECTOR_SIZE, } } } - i => FlashSector { - index: 4 + i as u8, - size: LARGE_SECTOR_SIZE, - }, + i => { + let large_sector_index = i - 1; + FlashSector { + index: (5 + large_sector_index) as u8, + start: FLASH_BASE + 4 * SMALL_SECTOR_SIZE + MEDIUM_SECTOR_SIZE + large_sector_index * LARGE_SECTOR_SIZE, + size: LARGE_SECTOR_SIZE, + } + } } } @@ -58,54 +66,54 @@ mod tests { #[test] fn can_get_sector_single_bank() { - let assert_sector = |index: u8, size: u32, addr: u32| { - assert_eq!(FlashSector { index, size }, get_sector(addr, false, 1024 * 1024)) + let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { + assert_eq!(FlashSector { index, start, size }, get_sector(addr, false, 1024 * 1024)) }; - assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_3FFF); - assert_sector(3, SMALL_SECTOR_SIZE, 0x0800_C000); - assert_sector(3, SMALL_SECTOR_SIZE, 0x0800_FFFF); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); - assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0801_0000); - assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); - assert_sector(5, LARGE_SECTOR_SIZE, 0x0802_0000); - assert_sector(5, LARGE_SECTOR_SIZE, 0x0803_FFFF); - assert_sector(11, LARGE_SECTOR_SIZE, 0x080E_0000); - assert_sector(11, LARGE_SECTOR_SIZE, 0x080F_FFFF); + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); } #[test] fn can_get_sector_dual_bank() { - let assert_sector = |index: u8, size: u32, addr: u32| { - assert_eq!(FlashSector { index, size }, get_sector(addr, true, 1024 * 1024)) + let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { + assert_eq!(FlashSector { index, start, size }, get_sector(addr, true, 1024 * 1024)) }; - assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_3FFF); - assert_sector(3, SMALL_SECTOR_SIZE, 0x0800_C000); - assert_sector(3, SMALL_SECTOR_SIZE, 0x0800_FFFF); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); - assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0801_0000); - assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); - assert_sector(5, LARGE_SECTOR_SIZE, 0x0802_0000); - assert_sector(5, LARGE_SECTOR_SIZE, 0x0803_FFFF); - assert_sector(7, LARGE_SECTOR_SIZE, 0x0806_0000); - assert_sector(7, LARGE_SECTOR_SIZE, 0x0807_FFFF); + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); + assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); - assert_sector(12, SMALL_SECTOR_SIZE, 0x0808_0000); - assert_sector(12, SMALL_SECTOR_SIZE, 0x0808_3FFF); - assert_sector(15, SMALL_SECTOR_SIZE, 0x0808_C000); - assert_sector(15, SMALL_SECTOR_SIZE, 0x0808_FFFF); + assert_sector(12, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); + assert_sector(12, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); + assert_sector(15, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); + assert_sector(15, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); - assert_sector(16, MEDIUM_SECTOR_SIZE, 0x0809_0000); - assert_sector(16, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); + assert_sector(16, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); + assert_sector(16, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); - assert_sector(17, LARGE_SECTOR_SIZE, 0x080A_0000); - assert_sector(17, LARGE_SECTOR_SIZE, 0x080B_FFFF); - assert_sector(19, LARGE_SECTOR_SIZE, 0x080E_0000); - assert_sector(19, LARGE_SECTOR_SIZE, 0x080F_FFFF); + assert_sector(17, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); + assert_sector(17, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); + assert_sector(19, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(19, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); } } diff --git a/embassy-hal-common/src/stm32/flash/f7.rs b/embassy-hal-common/src/stm32/flash/f7.rs index 90938e6a..2f586ade 100644 --- a/embassy-hal-common/src/stm32/flash/f7.rs +++ b/embassy-hal-common/src/stm32/flash/f7.rs @@ -6,6 +6,7 @@ pub(crate) const LARGE_SECTOR_SIZE: u32 = 256 * 1024; #[derive(Debug, PartialEq)] pub struct FlashSector { pub index: u8, + pub start: u32, pub size: u32, } @@ -15,21 +16,28 @@ pub fn get_sector(address: u32) -> FlashSector { match offset / LARGE_SECTOR_SIZE { 0 => { if offset < 4 * SMALL_SECTOR_SIZE { + let small_sector_index = offset / SMALL_SECTOR_SIZE; FlashSector { - index: (offset / SMALL_SECTOR_SIZE) as u8, + index: small_sector_index as u8, + start: FLASH_BASE + small_sector_index * SMALL_SECTOR_SIZE, size: SMALL_SECTOR_SIZE, } } else { FlashSector { index: 4, + start: FLASH_BASE + 4 * SMALL_SECTOR_SIZE, size: MEDIUM_SECTOR_SIZE, } } } - i => FlashSector { - index: 4 + i as u8, - size: LARGE_SECTOR_SIZE, - }, + i => { + let large_sector_index = i - 1; + FlashSector { + index: (5 + large_sector_index) as u8, + start: FLASH_BASE + 4 * SMALL_SECTOR_SIZE + MEDIUM_SECTOR_SIZE + large_sector_index * LARGE_SECTOR_SIZE, + size: LARGE_SECTOR_SIZE, + } + } } } @@ -39,19 +47,21 @@ mod tests { #[test] fn can_get_sector() { - let assert_sector = |index: u8, size: u32, addr: u32| assert_eq!(FlashSector { index, size }, get_sector(addr)); + let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { + assert_eq!(FlashSector { index, start, size }, get_sector(addr)) + }; - assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(0, SMALL_SECTOR_SIZE, 0x0800_7FFF); - assert_sector(3, SMALL_SECTOR_SIZE, 0x0801_8000); - assert_sector(3, SMALL_SECTOR_SIZE, 0x0801_FFFF); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_7FFF); + assert_sector(3, 0x0801_8000, SMALL_SECTOR_SIZE, 0x0801_8000); + assert_sector(3, 0x0801_8000, SMALL_SECTOR_SIZE, 0x0801_FFFF); - assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0802_0000); - assert_sector(4, MEDIUM_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(4, 0x0802_0000, MEDIUM_SECTOR_SIZE, 0x0802_0000); + assert_sector(4, 0x0802_0000, MEDIUM_SECTOR_SIZE, 0x0803_FFFF); - assert_sector(5, LARGE_SECTOR_SIZE, 0x0804_0000); - assert_sector(5, LARGE_SECTOR_SIZE, 0x0807_FFFF); - assert_sector(7, LARGE_SECTOR_SIZE, 0x080C_0000); - assert_sector(7, LARGE_SECTOR_SIZE, 0x080F_FFFF); + assert_sector(5, 0x0804_0000, LARGE_SECTOR_SIZE, 0x0804_0000); + assert_sector(5, 0x0804_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); + assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000); + assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); } } From bc69eb596e2496a5eb0cf1252ada12f2710aaff2 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 16:04:45 +0100 Subject: [PATCH 13/43] Add is_eraseable_range and split write into consecutive parts --- embassy-stm32/src/flash/f3.rs | 61 ++++++++++++------------ embassy-stm32/src/flash/f4.rs | 84 ++++++++++++++++----------------- embassy-stm32/src/flash/f7.rs | 80 ++++++++++++++++---------------- embassy-stm32/src/flash/h7.rs | 72 ++++++++++++++-------------- embassy-stm32/src/flash/l.rs | 62 ++++++++++++------------- embassy-stm32/src/flash/mod.rs | 85 +++++++++++++++++++++++----------- 6 files changed, 236 insertions(+), 208 deletions(-) diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index b24dfb4a..99ac1a15 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -1,13 +1,13 @@ use core::convert::TryInto; -use core::mem::size_of; use core::ptr::write_volatile; -use super::FlashRegion; +use atomic_polyfill::{fence, Ordering}; + +use super::{FlashRegion, BANK1, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const MAX_WRITE_SIZE: usize = super::BANK1::WRITE_SIZE; -pub(crate) const MAX_ERASE_SIZE: usize = super::BANK1::ERASE_SIZE; +const ERASE_SIZE: usize = BANK1::ERASE_SIZE; pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); @@ -18,33 +18,35 @@ pub(crate) unsafe fn unlock() { pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); } -pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<(), Error> { +pub(crate) unsafe fn begin_write() { + assert_eq!(0, WRITE_SIZE % 2); + pac::FLASH.cr().write(|w| w.set_pg(true)); - - let ret = { - let mut ret: Result<(), Error> = Ok(()); - let mut address = first_address; - let chunks = buf.chunks_exact(size_of::()); - assert!(chunks.remainder().is_empty()); - for chunk in chunks { - write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap())); - address += chunk.len() as u32; - - ret = blocking_wait_ready(); - if ret.is_err() { - break; - } - } - ret - }; - - pac::FLASH.cr().write(|w| w.set_pg(false)); - - ret } -pub(crate) unsafe fn blocking_erase(from_address: u32, to_address: u32) -> Result<(), Error> { - for page in (from_address..to_address).step_by(MAX_ERASE_SIZE) { +pub(crate) unsafe fn end_write() { + pac::FLASH.cr().write(|w| w.set_pg(false)); +} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + let mut address = start_address; + for chunk in buf.chunks(2) { + write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap())); + address += chunk.len() as u32; + + // prevents parallelism errors + fence(Ordering::SeqCst); + } + + blocking_wait_ready() +} + +pub(crate) fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { + start_address % ERASE_SIZE as u32 == 0 && end_address % ERASE_SIZE as u32 == 0 +} + +pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { + for page in (start_address..end_address).step_by(ERASE_SIZE) { pac::FLASH.cr().modify(|w| { w.set_per(true); }); @@ -71,7 +73,6 @@ pub(crate) unsafe fn blocking_erase(from_address: u32, to_address: u32) -> Resul return ret; } } - Ok(()) } @@ -89,7 +90,7 @@ pub(crate) unsafe fn clear_all_err() { }); } -pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { +unsafe fn blocking_wait_ready() -> Result<(), Error> { loop { let sr = pac::FLASH.sr().read(); diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 0d9d405b..7428fd57 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -1,23 +1,19 @@ use core::convert::TryInto; -use core::mem::size_of; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; use embassy_hal_common::stm32::flash::f4::{get_sector, SECOND_BANK_SECTOR_OFFSET}; -use super::{FlashRegion, FLASH_SIZE}; +use super::{FLASH_SIZE, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const MAX_WRITE_SIZE: usize = super::BANK1_REGION3::WRITE_SIZE; -pub(crate) const MAX_ERASE_SIZE: usize = super::BANK1_REGION3::ERASE_SIZE; - -unsafe fn is_dual_bank() -> bool { +fn is_dual_bank() -> bool { match FLASH_SIZE / 1024 { // 1 MB devices depend on configuration 1024 => { if cfg!(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)) { - pac::FLASH.optcr().read().db1m() + unsafe { pac::FLASH.optcr().read().db1m() } } else { false } @@ -38,49 +34,53 @@ pub(crate) unsafe fn unlock() { pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); } -pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<(), Error> { +pub(crate) unsafe fn begin_write() { + assert_eq!(0, WRITE_SIZE % 4); + pac::FLASH.cr().write(|w| { w.set_pg(true); w.set_psize(pac::flash::vals::Psize::PSIZE32); }); - - let ret = { - let mut ret: Result<(), Error> = Ok(()); - let mut address = first_address; - for chunk in buf.chunks(MAX_WRITE_SIZE) { - let vals = chunk.chunks_exact(size_of::()); - assert!(vals.remainder().is_empty()); - for val in vals { - write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); - address += val.len() as u32; - - // prevents parallelism errors - fence(Ordering::SeqCst); - } - - ret = blocking_wait_ready(); - if ret.is_err() { - break; - } - } - ret - }; - - pac::FLASH.cr().write(|w| w.set_pg(false)); - - ret } -pub(crate) unsafe fn blocking_erase(from_address: u32, to_address: u32) -> Result<(), Error> { - let mut addr = from_address; - let dual_bank = is_dual_bank(); +pub(crate) unsafe fn end_write() { + pac::FLASH.cr().write(|w| w.set_pg(false)); +} - while addr < to_address { - let sector = get_sector(addr, dual_bank, FLASH_SIZE as u32); - erase_sector(sector.index)?; - addr += sector.size; +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + let mut address = start_address; + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); + address += val.len() as u32; + + // prevents parallelism errors + fence(Ordering::SeqCst); } + blocking_wait_ready() +} + +pub(crate) fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { + let dual_bank = is_dual_bank(); + let mut address = start_address; + while address < end_address { + let sector = get_sector(address, dual_bank, FLASH_SIZE as u32); + if sector.start != address { + return false; + } + address += sector.size; + } + address == end_address +} + +pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { + let dual_bank = is_dual_bank(); + let mut address = start_address; + while address < end_address { + let sector = get_sector(address, dual_bank, FLASH_SIZE as u32); + erase_sector(sector.index)?; + address += sector.size; + } Ok(()) } @@ -116,7 +116,7 @@ pub(crate) unsafe fn clear_all_err() { }); } -pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { +unsafe fn blocking_wait_ready() -> Result<(), Error> { loop { let sr = pac::FLASH.sr().read(); diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 8b8076e0..16b68458 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -1,17 +1,13 @@ use core::convert::TryInto; -use core::mem::size_of; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; use embassy_hal_common::stm32::flash::f7::get_sector; -use super::FlashRegion; +use super::WRITE_SIZE; use crate::flash::Error; use crate::pac; -pub(crate) const MAX_WRITE_SIZE: usize = super::BANK1_REGION3::WRITE_SIZE; -pub(crate) const MAX_ERASE_SIZE: usize = super::BANK1_REGION3::ERASE_SIZE; - pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -21,49 +17,51 @@ pub(crate) unsafe fn unlock() { pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); } -pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<(), Error> { +pub(crate) unsafe fn begin_write() { + assert_eq!(0, WRITE_SIZE % 4); + pac::FLASH.cr().write(|w| { w.set_pg(true); w.set_psize(pac::flash::vals::Psize::PSIZE32); }); - - let ret = { - let mut ret: Result<(), Error> = Ok(()); - let mut address = first_address; - for chunk in buf.chunks(MAX_WRITE_SIZE) { - let vals = chunk.chunks_exact(size_of::()); - assert!(vals.remainder().is_empty()); - for val in vals { - write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); - address += val.len() as u32; - - // prevents parallelism errors - fence(Ordering::SeqCst); - } - - ret = blocking_wait_ready(); - if ret.is_err() { - break; - } - } - ret - }; - - pac::FLASH.cr().write(|w| w.set_pg(false)); - - ret } -pub(crate) unsafe fn blocking_erase(from_address: u32, to_address: u32) -> Result<(), Error> { - let start_sector = get_sector(from_address); - let end_sector = get_sector(to_address); - for sector in start_sector.index..end_sector.index { - let ret = erase_sector(sector as u8); - if ret.is_err() { - return ret; - } +pub(crate) unsafe fn end_write() { + pac::FLASH.cr().write(|w| w.set_pg(false)); +} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + let mut address = start_address; + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); + address += val.len() as u32; + + // prevents parallelism errors + fence(Ordering::SeqCst); } + blocking_wait_ready() +} + +pub(crate) fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { + let mut address = start_address; + while address < end_address { + let sector = get_sector(address); + if sector.start != address { + return false; + } + address += sector.size; + } + address == end_address +} + +pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { + let mut address = start_address; + while address < end_address { + let sector = get_sector(address); + erase_sector(sector.index)?; + address += sector.size; + } Ok(()) } @@ -106,7 +104,7 @@ pub(crate) unsafe fn clear_all_err() { }); } -pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { +unsafe fn blocking_wait_ready() -> Result<(), Error> { loop { let sr = pac::FLASH.sr().read(); diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 6ab8e7b7..21a9e45d 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -1,15 +1,13 @@ use core::convert::TryInto; -use core::mem::size_of; use core::ptr::write_volatile; -use super::{FlashRegion, FLASH_SIZE}; +use atomic_polyfill::{fence, Ordering}; + +use super::{FlashRegion, FLASH_SIZE, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -const WRITE_SIZE: usize = super::BANK1::WRITE_SIZE; const ERASE_SIZE: usize = super::BANK1::ERASE_SIZE; -pub(crate) const MAX_WRITE_SIZE: usize = WRITE_SIZE; -pub(crate) const MAX_ERASE_SIZE: usize = ERASE_SIZE; const SECOND_BANK_OFFSET: usize = 0x0010_0000; const fn is_dual_bank() -> bool { @@ -33,59 +31,60 @@ pub(crate) unsafe fn unlock() { } } -pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<(), Error> { - let bank = if !is_dual_bank() || (first_address - super::FLASH_BASE as u32) < SECOND_BANK_OFFSET as u32 { +pub(crate) unsafe fn begin_write() { + assert_eq!(0, WRITE_SIZE % 4); +} + +pub(crate) unsafe fn end_write() {} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + // We cannot have the write setup sequence in begin_write as it depends on the address + let bank = if !is_dual_bank() || (start_address - super::FLASH_BASE as u32) < SECOND_BANK_OFFSET as u32 { pac::FLASH.bank(0) } else { pac::FLASH.bank(1) }; - bank.cr().write(|w| { w.set_pg(true); w.set_psize(2); // 32 bits at once }); - cortex_m::asm::isb(); cortex_m::asm::dsb(); - core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst); + fence(Ordering::SeqCst); - let ret = { - let mut ret: Result<(), Error> = Ok(()); - let mut address = first_address; - 'outer: for chunk in buf.chunks(WRITE_SIZE) { - let vals = chunk.chunks_exact(size_of::()); - assert!(vals.remainder().is_empty()); - for val in vals { - write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); - address += val.len() as u32; + let mut res = None; + let mut address = start_address; + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); + address += val.len() as u32; - ret = blocking_wait_ready(bank); - bank.sr().modify(|w| { - if w.eop() { - w.set_eop(true); - } - }); - if ret.is_err() { - break 'outer; - } + res = Some(blocking_wait_ready(bank)); + bank.sr().modify(|w| { + if w.eop() { + w.set_eop(true); } + }); + if res.unwrap().is_err() { + break; } - ret - }; + } bank.cr().write(|w| w.set_pg(false)); cortex_m::asm::isb(); cortex_m::asm::dsb(); - core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst); + fence(Ordering::SeqCst); - ret + res.unwrap() } -pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { - let start_sector = (from - super::FLASH_BASE as u32) / ERASE_SIZE as u32; - let end_sector = (to - super::FLASH_BASE as u32) / ERASE_SIZE as u32; +pub(crate) fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { + start_address % ERASE_SIZE as u32 == 0 && end_address % ERASE_SIZE as u32 == 0 +} +pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { + let start_sector = (start_address - super::FLASH_BASE as u32) / ERASE_SIZE as u32; + let end_sector = (end_address - super::FLASH_BASE as u32) / ERASE_SIZE as u32; for sector in start_sector..end_sector { let bank = if sector >= 8 { 1 } else { 0 }; let ret = erase_sector(pac::FLASH.bank(bank), (sector % 8) as u8); @@ -93,7 +92,6 @@ pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { return ret; } } - Ok(()) } @@ -157,7 +155,7 @@ unsafe fn bank_clear_all_err(bank: pac::flash::Bank) { }); } -pub(crate) unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { +unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { loop { let sr = bank.sr().read(); diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 9ab732b8..57989625 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -1,14 +1,12 @@ -use core::convert::TryInto; use core::ptr::write_volatile; -use super::FlashRegion; +use atomic_polyfill::{fence, Ordering}; + +use super::{FlashRegion, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -const WRITE_SIZE: usize = super::BANK1::WRITE_SIZE; const ERASE_SIZE: usize = super::BANK1::ERASE_SIZE; -pub(crate) const MAX_WRITE_SIZE: usize = WRITE_SIZE; -pub(crate) const MAX_ERASE_SIZE: usize = ERASE_SIZE; pub(crate) unsafe fn lock() { #[cfg(any(flash_wl, flash_wb, flash_l4))] @@ -39,35 +37,37 @@ pub(crate) unsafe fn unlock() { } } -pub(crate) unsafe fn blocking_write(first_address: u32, buf: &[u8]) -> Result<(), Error> { +pub(crate) unsafe fn begin_write() { + assert_eq!(0, WRITE_SIZE % 4); + #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().write(|w| w.set_pg(true)); - - let ret = { - let mut ret: Result<(), Error> = Ok(()); - let mut address = first_address; - for chunk in buf.chunks(WRITE_SIZE) { - for val in chunk.chunks(4) { - write_volatile(address as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap())); - address += val.len() as u32; - } - - ret = blocking_wait_ready(); - if ret.is_err() { - break; - } - } - ret - }; - - #[cfg(any(flash_wl, flash_wb, flash_l4))] - pac::FLASH.cr().write(|w| w.set_pg(false)); - - ret } -pub(crate) unsafe fn blocking_erase(from_address: u32, to_address: u32) -> Result<(), Error> { - for page in (from_address..to_address).step_by(ERASE_SIZE) { +pub(crate) unsafe fn end_write() { + #[cfg(any(flash_wl, flash_wb, flash_l4))] + pac::FLASH.cr().write(|w| w.set_pg(false)); +} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + let mut address = start_address; + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); + address += val.len() as u32; + + // prevents parallelism errors + fence(Ordering::SeqCst); + } + + blocking_wait_ready() +} + +pub(crate) fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { + start_address % ERASE_SIZE as u32 == 0 && end_address % ERASE_SIZE as u32 == 0 +} + +pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { + for page in (start_address..end_address).step_by(ERASE_SIZE) { #[cfg(any(flash_l0, flash_l1))] { pac::FLASH.pecr().modify(|w| { @@ -155,7 +155,7 @@ pub(crate) unsafe fn clear_all_err() { }); } -pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { +unsafe fn blocking_wait_ready() -> Result<(), Error> { loop { let sr = pac::FLASH.sr().read(); diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index b6cecfdb..c704909a 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -1,8 +1,10 @@ use embassy_hal_common::{into_ref, PeripheralRef}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::mutex::{Mutex, MutexGuard}; use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; pub use crate::_generated::flash_regions::*; -pub use crate::pac::{FLASH_BASE, FLASH_SIZE}; +pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; use crate::peripherals::FLASH; use crate::Peripheral; @@ -17,6 +19,8 @@ pub struct Flash<'d> { _inner: PeripheralRef<'d, FLASH>, } +static REGION_LOCK: Mutex = Mutex::new(()); + impl<'d> Flash<'d> { pub fn new(p: impl Peripheral

+ 'd) -> Self { into_ref!(p); @@ -33,7 +37,6 @@ impl<'d> Flash<'d> { } let first_address = FLASH_BASE as u32 + offset; - let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; bytes.copy_from_slice(flash_data); Ok(()) @@ -43,39 +46,56 @@ impl<'d> Flash<'d> { if offset as usize + buf.len() > FLASH_SIZE { return Err(Error::Size); } - if offset as usize % family::MAX_WRITE_SIZE != 0 || buf.len() as usize % family::MAX_WRITE_SIZE != 0 { + if offset as usize % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { return Err(Error::Unaligned); } - let first_address = FLASH_BASE as u32 + offset; - trace!("Writing {} bytes at 0x{:x}", buf.len(), first_address); + let start_address = FLASH_BASE as u32 + offset; + trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address); + + // No need to take lock here as we only have one mut flash reference. unsafe { family::clear_all_err(); - family::unlock(); - let res = family::blocking_write(first_address, buf); + let res = Flash::blocking_write_all(start_address, buf); family::lock(); res } } + unsafe fn blocking_write_all(start_address: u32, buf: &[u8]) -> Result<(), Error> { + family::begin_write(); + let mut address = start_address; + for chunk in buf.chunks(WRITE_SIZE) { + let res = unsafe { family::blocking_write(address, chunk.try_into().unwrap()) }; + if res.is_err() { + family::end_write(); + return res; + } + address += WRITE_SIZE as u32; + } + + family::end_write(); + Ok(()) + } + pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { if to < from || to as usize > FLASH_SIZE { return Err(Error::Size); } - if (from as usize % family::MAX_ERASE_SIZE) != 0 || (to as usize % family::MAX_ERASE_SIZE) != 0 { + + let start_address = FLASH_BASE as u32 + from; + let end_address = FLASH_BASE as u32 + to; + if !family::is_eraseable_range(start_address, end_address) { return Err(Error::Unaligned); } - - let from_address = FLASH_BASE as u32 + from; - let to_address = FLASH_BASE as u32 + to; + trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); unsafe { family::clear_all_err(); - family::unlock(); - let res = family::blocking_erase(from_address, to_address); + let res = family::blocking_erase(start_address, end_address); family::lock(); res } @@ -101,7 +121,6 @@ pub trait FlashRegion { } let first_address = Self::BASE as u32 + offset; - let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; bytes.copy_from_slice(flash_data); Ok(()) @@ -115,17 +134,19 @@ pub trait FlashRegion { return Err(Error::Unaligned); } - let first_address = Self::BASE as u32 + offset; - trace!("Writing {} bytes from 0x{:x}", buf.len(), first_address); + let start_address = Self::BASE as u32 + offset; + trace!("Writing {} bytes from 0x{:x}", buf.len(), start_address); - critical_section::with(|_| unsafe { + // Protect agains simultaneous write/erase to multiple regions. + let _guard = take_lock_spin(); + + unsafe { family::clear_all_err(); - family::unlock(); - let res = family::blocking_write(first_address, buf); + let res = Flash::blocking_write_all(start_address, buf); family::lock(); res - }) + } } fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { @@ -136,18 +157,28 @@ pub trait FlashRegion { return Err(Error::Unaligned); } - let from_address = Self::BASE as u32 + from; - let to_address = Self::BASE as u32 + to; - trace!("Erasing from 0x{:x} to 0x{:x}", from_address, to_address); + let start_address = Self::BASE as u32 + from; + let end_address = Self::BASE as u32 + to; + trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); - critical_section::with(|_| unsafe { + // Protect agains simultaneous write/erase to multiple regions. + let _guard = take_lock_spin(); + + unsafe { family::clear_all_err(); - family::unlock(); - let res = family::blocking_erase(from_address, to_address); + let res = family::blocking_erase(start_address, end_address); family::lock(); res - }) + } + } +} + +fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { + loop { + if let Ok(guard) = REGION_LOCK.try_lock() { + return guard; + } } } From e8fc7a66a344776463026fba8c91231951fcf2b4 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 16:32:32 +0100 Subject: [PATCH 14/43] Ensure flash module and FlashRegion trait is always defined --- embassy-stm32/src/flash/other.rs | 7 +++++++ embassy-stm32/src/lib.rs | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 embassy-stm32/src/flash/other.rs diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs new file mode 100644 index 00000000..c9836d09 --- /dev/null +++ b/embassy-stm32/src/flash/other.rs @@ -0,0 +1,7 @@ +pub trait FlashRegion { + const BASE: usize; + const SIZE: usize; + const ERASE_SIZE: usize; + const WRITE_SIZE: usize; + const ERASE_VALUE: u8; +} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index eeaa04f6..ddd5c0fd 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -47,6 +47,13 @@ pub mod crc; flash_l0, flash_l1, flash_wl, flash_wb, flash_l4, flash_f3, flash_f4, flash_f7, flash_h7 ))] pub mod flash; +#[cfg(not(any( + flash_l0, flash_l1, flash_wl, flash_wb, flash_l4, flash_f3, flash_f4, flash_f7, flash_h7 +)))] +pub mod flash { + mod other; + pub use other::FlashRegion; +} pub mod pwm; #[cfg(rng)] pub mod rng; From e9a5b31fa83f7a261a79a810666039381553037f Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 17:00:52 +0100 Subject: [PATCH 15/43] Implement drop for FlashRegions --- embassy-stm32/src/flash/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index c704909a..1294ace4 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -108,6 +108,12 @@ impl Drop for Flash<'_> { } } +impl Drop for FlashRegions { + fn drop(&mut self) { + unsafe { family::lock() }; + } +} + pub trait FlashRegion { const BASE: usize; const SIZE: usize; From d6ce1c4325179a813d47f2f068c178fe858ac49f Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 11:31:45 +0200 Subject: [PATCH 16/43] Support running tests in embassy-stm32 and move impl from common back to stm32 --- embassy-hal-common/src/lib.rs | 1 - embassy-hal-common/src/stm32/flash/f4.rs | 119 ---------------------- embassy-hal-common/src/stm32/flash/f7.rs | 67 ------------ embassy-hal-common/src/stm32/flash/mod.rs | 2 - embassy-hal-common/src/stm32/mod.rs | 1 - embassy-stm32/Cargo.toml | 6 +- embassy-stm32/src/flash/f4.rs | 116 ++++++++++++++++++++- embassy-stm32/src/flash/f7.rs | 64 +++++++++++- embassy-stm32/src/flash/mod.rs | 7 ++ 9 files changed, 186 insertions(+), 197 deletions(-) delete mode 100644 embassy-hal-common/src/stm32/flash/f4.rs delete mode 100644 embassy-hal-common/src/stm32/flash/f7.rs delete mode 100644 embassy-hal-common/src/stm32/flash/mod.rs delete mode 100644 embassy-hal-common/src/stm32/mod.rs diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs index 1b253719..b2a35cd3 100644 --- a/embassy-hal-common/src/lib.rs +++ b/embassy-hal-common/src/lib.rs @@ -10,5 +10,4 @@ mod macros; mod peripheral; pub mod ratio; pub mod ring_buffer; -pub mod stm32; pub use peripheral::{Peripheral, PeripheralRef}; diff --git a/embassy-hal-common/src/stm32/flash/f4.rs b/embassy-hal-common/src/stm32/flash/f4.rs deleted file mode 100644 index a8069ddd..00000000 --- a/embassy-hal-common/src/stm32/flash/f4.rs +++ /dev/null @@ -1,119 +0,0 @@ -const FLASH_BASE: u32 = 0x0800_0000; -pub(crate) const SMALL_SECTOR_SIZE: u32 = 16 * 1024; -pub(crate) const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; -pub(crate) const LARGE_SECTOR_SIZE: u32 = 128 * 1024; -pub const SECOND_BANK_SECTOR_OFFSET: u8 = 12; - -#[derive(Debug, PartialEq)] -pub struct FlashSector { - pub index: u8, - pub start: u32, - pub size: u32, -} - -pub fn get_sector(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector { - let offset = address - FLASH_BASE; - if !dual_bank { - get_single_bank_sector(offset) - } else { - let bank_size = flash_size / 2; - if offset < bank_size { - get_single_bank_sector(offset) - } else { - let sector = get_single_bank_sector(offset - bank_size); - FlashSector { - index: SECOND_BANK_SECTOR_OFFSET + sector.index, - start: sector.start + bank_size, - size: sector.size, - } - } - } -} - -fn get_single_bank_sector(offset: u32) -> FlashSector { - // First 4 sectors are 16KB, then one 64KB, and rest are 128KB - match offset / LARGE_SECTOR_SIZE { - 0 => { - if offset < 4 * SMALL_SECTOR_SIZE { - let small_sector_index = offset / SMALL_SECTOR_SIZE; - FlashSector { - index: small_sector_index as u8, - start: FLASH_BASE + small_sector_index * SMALL_SECTOR_SIZE, - size: SMALL_SECTOR_SIZE, - } - } else { - FlashSector { - index: 4, - start: FLASH_BASE + 4 * SMALL_SECTOR_SIZE, - size: MEDIUM_SECTOR_SIZE, - } - } - } - i => { - let large_sector_index = i - 1; - FlashSector { - index: (5 + large_sector_index) as u8, - start: FLASH_BASE + 4 * SMALL_SECTOR_SIZE + MEDIUM_SECTOR_SIZE + large_sector_index * LARGE_SECTOR_SIZE, - size: LARGE_SECTOR_SIZE, - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn can_get_sector_single_bank() { - let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { - assert_eq!(FlashSector { index, start, size }, get_sector(addr, false, 1024 * 1024)) - }; - - assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); - assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); - assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); - - assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); - assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); - - assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); - assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); - assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); - assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); - } - - #[test] - fn can_get_sector_dual_bank() { - let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { - assert_eq!(FlashSector { index, start, size }, get_sector(addr, true, 1024 * 1024)) - }; - - assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); - assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); - assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); - - assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); - assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); - - assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); - assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); - assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); - assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); - - assert_sector(12, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); - assert_sector(12, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); - assert_sector(15, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); - assert_sector(15, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); - - assert_sector(16, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); - assert_sector(16, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); - - assert_sector(17, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); - assert_sector(17, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); - assert_sector(19, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); - assert_sector(19, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); - } -} diff --git a/embassy-hal-common/src/stm32/flash/f7.rs b/embassy-hal-common/src/stm32/flash/f7.rs deleted file mode 100644 index 2f586ade..00000000 --- a/embassy-hal-common/src/stm32/flash/f7.rs +++ /dev/null @@ -1,67 +0,0 @@ -const FLASH_BASE: u32 = 0x0800_0000; -pub(crate) const SMALL_SECTOR_SIZE: u32 = 32 * 1024; -pub(crate) const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024; -pub(crate) const LARGE_SECTOR_SIZE: u32 = 256 * 1024; - -#[derive(Debug, PartialEq)] -pub struct FlashSector { - pub index: u8, - pub start: u32, - pub size: u32, -} - -pub fn get_sector(address: u32) -> FlashSector { - // First 4 sectors are 32KB, then one 128KB, and rest are 256KB - let offset = address - FLASH_BASE; - match offset / LARGE_SECTOR_SIZE { - 0 => { - if offset < 4 * SMALL_SECTOR_SIZE { - let small_sector_index = offset / SMALL_SECTOR_SIZE; - FlashSector { - index: small_sector_index as u8, - start: FLASH_BASE + small_sector_index * SMALL_SECTOR_SIZE, - size: SMALL_SECTOR_SIZE, - } - } else { - FlashSector { - index: 4, - start: FLASH_BASE + 4 * SMALL_SECTOR_SIZE, - size: MEDIUM_SECTOR_SIZE, - } - } - } - i => { - let large_sector_index = i - 1; - FlashSector { - index: (5 + large_sector_index) as u8, - start: FLASH_BASE + 4 * SMALL_SECTOR_SIZE + MEDIUM_SECTOR_SIZE + large_sector_index * LARGE_SECTOR_SIZE, - size: LARGE_SECTOR_SIZE, - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn can_get_sector() { - let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { - assert_eq!(FlashSector { index, start, size }, get_sector(addr)) - }; - - assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_7FFF); - assert_sector(3, 0x0801_8000, SMALL_SECTOR_SIZE, 0x0801_8000); - assert_sector(3, 0x0801_8000, SMALL_SECTOR_SIZE, 0x0801_FFFF); - - assert_sector(4, 0x0802_0000, MEDIUM_SECTOR_SIZE, 0x0802_0000); - assert_sector(4, 0x0802_0000, MEDIUM_SECTOR_SIZE, 0x0803_FFFF); - - assert_sector(5, 0x0804_0000, LARGE_SECTOR_SIZE, 0x0804_0000); - assert_sector(5, 0x0804_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); - assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000); - assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); - } -} diff --git a/embassy-hal-common/src/stm32/flash/mod.rs b/embassy-hal-common/src/stm32/flash/mod.rs deleted file mode 100644 index 1452b491..00000000 --- a/embassy-hal-common/src/stm32/flash/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod f4; -pub mod f7; diff --git a/embassy-hal-common/src/stm32/mod.rs b/embassy-hal-common/src/stm32/mod.rs deleted file mode 100644 index 2e50f82b..00000000 --- a/embassy-hal-common/src/stm32/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod flash; diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index b66d724d..1dd6202d 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -60,7 +60,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { version = "1", features = ["rt"] } +stm32-metapac = "1" vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -69,12 +69,16 @@ seq-macro = "0.3.0" cfg-if = "1.0.0" embedded-io = { version = "0.4.0", features = ["async"], optional = true } +[dev-dependencies] +critical-section = { version = "1.1", features = ["std"] } + [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" stm32-metapac = { version = "1", default-features = false, features = ["metadata"]} [features] +default = ["stm32-metapac/rt"] 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"] memory-x = ["stm32-metapac/memory-x"] subghz = [] diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 7428fd57..0fdfecb9 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -2,12 +2,15 @@ use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use embassy_hal_common::stm32::flash::f4::{get_sector, SECOND_BANK_SECTOR_OFFSET}; - -use super::{FLASH_SIZE, WRITE_SIZE}; +use super::{FlashSector, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; use crate::flash::Error; use crate::pac; +const SMALL_SECTOR_SIZE: u32 = 16 * 1024; +const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; +const LARGE_SECTOR_SIZE: u32 = 128 * 1024; +const SECOND_BANK_SECTOR_OFFSET: u8 = 12; + fn is_dual_bank() -> bool { match FLASH_SIZE / 1024 { // 1 MB devices depend on configuration @@ -141,3 +144,110 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } } } + +fn get_sector(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector { + let offset = address - FLASH_BASE as u32; + if !dual_bank { + get_single_bank_sector(offset) + } else { + let bank_size = flash_size / 2; + if offset < bank_size { + get_single_bank_sector(offset) + } else { + let sector = get_single_bank_sector(offset - bank_size); + FlashSector { + index: SECOND_BANK_SECTOR_OFFSET + sector.index, + start: sector.start + bank_size, + size: sector.size, + } + } + } +} + +fn get_single_bank_sector(offset: u32) -> FlashSector { + // First 4 sectors are 16KB, then one 64KB, and rest are 128KB + match offset / LARGE_SECTOR_SIZE { + 0 => { + if offset < 4 * SMALL_SECTOR_SIZE { + let small_sector_index = offset / SMALL_SECTOR_SIZE; + FlashSector { + index: small_sector_index as u8, + start: FLASH_BASE as u32 + small_sector_index * SMALL_SECTOR_SIZE, + size: SMALL_SECTOR_SIZE, + } + } else { + FlashSector { + index: 4, + start: FLASH_BASE as u32 + 4 * SMALL_SECTOR_SIZE, + size: MEDIUM_SECTOR_SIZE, + } + } + } + i => { + let large_sector_index = i - 1; + FlashSector { + index: (5 + large_sector_index) as u8, + start: FLASH_BASE as u32 + 4 * SMALL_SECTOR_SIZE + MEDIUM_SECTOR_SIZE + large_sector_index * LARGE_SECTOR_SIZE, + size: LARGE_SECTOR_SIZE, + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_get_sector_single_bank() { + let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { + assert_eq!(FlashSector { index, start, size }, get_sector(addr, false, 1024 * 1024)) + }; + + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); + + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); + } + + #[test] + fn can_get_sector_dual_bank() { + let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { + assert_eq!(FlashSector { index, start, size }, get_sector(addr, true, 1024 * 1024)) + }; + + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); + + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); + assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); + + assert_sector(12, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); + assert_sector(12, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); + assert_sector(15, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); + assert_sector(15, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); + + assert_sector(16, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); + assert_sector(16, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); + + assert_sector(17, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); + assert_sector(17, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); + assert_sector(19, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(19, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); + } +} diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 16b68458..0d3b738c 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -2,12 +2,14 @@ use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use embassy_hal_common::stm32::flash::f7::get_sector; - -use super::WRITE_SIZE; +use super::{FlashSector, FLASH_BASE, WRITE_SIZE}; use crate::flash::Error; use crate::pac; +const SMALL_SECTOR_SIZE: u32 = 32 * 1024; +const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024; +const LARGE_SECTOR_SIZE: u32 = 256 * 1024; + pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -129,3 +131,59 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } } } + +fn get_sector(address: u32) -> FlashSector { + // First 4 sectors are 32KB, then one 128KB, and rest are 256KB + let offset = address - FLASH_BASE as u32; + match offset / LARGE_SECTOR_SIZE { + 0 => { + if offset < 4 * SMALL_SECTOR_SIZE { + let small_sector_index = offset / SMALL_SECTOR_SIZE; + FlashSector { + index: small_sector_index as u8, + start: FLASH_BASE as u32 + small_sector_index * SMALL_SECTOR_SIZE, + size: SMALL_SECTOR_SIZE, + } + } else { + FlashSector { + index: 4, + start: FLASH_BASE as u32 + 4 * SMALL_SECTOR_SIZE, + size: MEDIUM_SECTOR_SIZE, + } + } + } + i => { + let large_sector_index = i - 1; + FlashSector { + index: (5 + large_sector_index) as u8, + start: FLASH_BASE as u32 + 4 * SMALL_SECTOR_SIZE + MEDIUM_SECTOR_SIZE + large_sector_index * LARGE_SECTOR_SIZE, + size: LARGE_SECTOR_SIZE, + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_get_sector() { + let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { + assert_eq!(FlashSector { index, start, size }, get_sector(addr)) + }; + + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_7FFF); + assert_sector(3, 0x0801_8000, SMALL_SECTOR_SIZE, 0x0801_8000); + assert_sector(3, 0x0801_8000, SMALL_SECTOR_SIZE, 0x0801_FFFF); + + assert_sector(4, 0x0802_0000, MEDIUM_SECTOR_SIZE, 0x0802_0000); + assert_sector(4, 0x0802_0000, MEDIUM_SECTOR_SIZE, 0x0803_FFFF); + + assert_sector(5, 0x0804_0000, LARGE_SECTOR_SIZE, 0x0804_0000); + assert_sector(5, 0x0804_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); + assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000); + assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); + } +} diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 1294ace4..6906bd09 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -19,6 +19,13 @@ pub struct Flash<'d> { _inner: PeripheralRef<'d, FLASH>, } +#[derive(Debug, PartialEq)] +pub struct FlashSector { + pub index: u8, + pub start: u32, + pub size: u32, +} + static REGION_LOCK: Mutex = Mutex::new(()); impl<'d> Flash<'d> { From 6806bb969278acc9d3cde34897453b29807157c1 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 11:52:18 +0200 Subject: [PATCH 17/43] Expose flash region settings as an array --- embassy-stm32/build.rs | 42 ++++++++++++++++++++++------------ embassy-stm32/src/flash/mod.rs | 40 +++++++++++++++++--------------- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 393efc42..53f20978 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -3,7 +3,7 @@ use std::fmt::Write as _; use std::path::PathBuf; use std::{env, fs}; -use proc_macro2::TokenStream; +use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use stm32_metapac::metadata::{MemoryRegionKind, METADATA}; @@ -106,12 +106,15 @@ fn main() { // ======== // Generate FLASH regions let mut flash_regions = TokenStream::new(); - let flash_memory_regions = METADATA + let flash_memory_regions: Vec<_> = METADATA .memory .iter() - .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()); - for region in flash_memory_regions.clone() { - let region_name = format_ident!("{}", get_flash_region_name(region.name)); + .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()) + .collect(); + for region in flash_memory_regions.iter() { + let region_name = get_flash_region_name(region.name); + let region_type = format_ident!("{}", region_name); + let settings_name = format_ident!("{}_SETTINGS", region_name); let base = region.address as usize; let size = region.size as usize; let settings = region.settings.as_ref().unwrap(); @@ -121,21 +124,26 @@ fn main() { flash_regions.extend(quote! { #[allow(non_camel_case_types)] - pub struct #region_name(()); + pub struct #region_type(()); }); flash_regions.extend(quote! { - impl crate::flash::FlashRegion for #region_name { - const BASE: usize = #base; - const SIZE: usize = #size; - const ERASE_SIZE: usize = #erase_size; - const WRITE_SIZE: usize = #write_size; - const ERASE_VALUE: u8 = #erase_value; + pub const #settings_name: crate::flash::FlashRegionSettings = crate::flash::FlashRegionSettings { + base: #base, + size: #size, + erase_size: #erase_size, + write_size: #write_size, + erase_value: #erase_value, + }; + + impl crate::flash::FlashRegion for #region_type { + const SETTINGS: crate::flash::FlashRegionSettings = #settings_name; } }); } - let (fields, inits): (Vec, Vec) = flash_memory_regions + let (fields, (inits, settings)): (Vec, (Vec, Vec)) = flash_memory_regions + .iter() .map(|f| { let region_name = get_flash_region_name(f.name); let field_name = format_ident!("{}", region_name.to_lowercase()); @@ -146,11 +154,13 @@ fn main() { let init = quote! { #field_name: #field_type(()) }; + let settings_name = format_ident!("{}_SETTINGS", region_name); - (field, init) + (field, (init, settings_name)) }) .unzip(); + let regions_len = flash_memory_regions.len(); flash_regions.extend(quote! { pub struct FlashRegions { #(#fields),* @@ -163,6 +173,10 @@ fn main() { } } } + + pub const FLASH_REGIONS: [&crate::flash::FlashRegionSettings; #regions_len] = [ + #(&#settings),* + ]; }); g.extend(quote! { pub mod flash_regions { #flash_regions } }); diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 6906bd09..29db2d13 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -19,6 +19,14 @@ pub struct Flash<'d> { _inner: PeripheralRef<'d, FLASH>, } +pub struct FlashRegionSettings { + pub base: usize, + pub size: usize, + pub erase_size: usize, + pub write_size: usize, + pub erase_value: u8, +} + #[derive(Debug, PartialEq)] pub struct FlashSector { pub index: u8, @@ -122,32 +130,28 @@ impl Drop for FlashRegions { } pub trait FlashRegion { - const BASE: usize; - const SIZE: usize; - const ERASE_SIZE: usize; - const WRITE_SIZE: usize; - const ERASE_VALUE: u8; + const SETTINGS: FlashRegionSettings; fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - if offset as usize + bytes.len() > Self::SIZE { + if offset as usize + bytes.len() > Self::SETTINGS.size { return Err(Error::Size); } - let first_address = Self::BASE as u32 + offset; + let first_address = Self::SETTINGS.base as u32 + offset; let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; bytes.copy_from_slice(flash_data); Ok(()) } fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { - if offset as usize + buf.len() > Self::SIZE { + if offset as usize + buf.len() > Self::SETTINGS.size { return Err(Error::Size); } - if offset as usize % Self::WRITE_SIZE != 0 || buf.len() as usize % Self::WRITE_SIZE != 0 { + if offset as usize % Self::SETTINGS.write_size != 0 || buf.len() as usize % Self::SETTINGS.write_size != 0 { return Err(Error::Unaligned); } - let start_address = Self::BASE as u32 + offset; + let start_address = Self::SETTINGS.base as u32 + offset; trace!("Writing {} bytes from 0x{:x}", buf.len(), start_address); // Protect agains simultaneous write/erase to multiple regions. @@ -163,15 +167,15 @@ pub trait FlashRegion { } fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - if to < from || to as usize > Self::SIZE { + if to < from || to as usize > Self::SETTINGS.size { return Err(Error::Size); } - if (from as usize % Self::ERASE_SIZE) != 0 || (to as usize % Self::ERASE_SIZE) != 0 { + if (from as usize % Self::SETTINGS.erase_size) != 0 || (to as usize % Self::SETTINGS.erase_size) != 0 { return Err(Error::Unaligned); } - let start_address = Self::BASE as u32 + from; - let end_address = Self::BASE as u32 + to; + let start_address = Self::SETTINGS.base as u32 + from; + let end_address = Self::SETTINGS.base as u32 + to; trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); // Protect agains simultaneous write/erase to multiple regions. @@ -224,20 +228,20 @@ foreach_flash_region! { } impl ReadNorFlash for crate::_generated::flash_regions::$name { - const READ_SIZE: usize = ::WRITE_SIZE; + const READ_SIZE: usize = ::SETTINGS.write_size; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { self.blocking_read(offset, bytes) } fn capacity(&self) -> usize { - ::SIZE + ::SETTINGS.size } } impl NorFlash for crate::_generated::flash_regions::$name { - const WRITE_SIZE: usize = ::WRITE_SIZE; - const ERASE_SIZE: usize = ::ERASE_SIZE; + const WRITE_SIZE: usize = ::SETTINGS.write_size; + const ERASE_SIZE: usize = ::SETTINGS.erase_size; fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { self.blocking_erase(from, to) From 4ee3d15519aaf3a290fd78063b88d182ff3aab53 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 12:10:24 +0200 Subject: [PATCH 18/43] Keep peripheral lifetime when calling into_regions() --- embassy-stm32/build.rs | 8 +++++--- embassy-stm32/src/flash/mod.rs | 12 +++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 53f20978..f5bdadf5 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -162,13 +162,15 @@ fn main() { let regions_len = flash_memory_regions.len(); flash_regions.extend(quote! { - pub struct FlashRegions { + pub struct FlashRegions<'d> { + _inner: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, #(#fields),* } - impl FlashRegions { - pub(crate) const fn take() -> Self { + impl<'d> FlashRegions<'d> { + pub(crate) const fn new(p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self { Self { + _inner: p, #(#inits),* } } diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 29db2d13..1d1f034a 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -16,7 +16,7 @@ use crate::Peripheral; mod family; pub struct Flash<'d> { - _inner: PeripheralRef<'d, FLASH>, + inner: PeripheralRef<'d, FLASH>, } pub struct FlashRegionSettings { @@ -39,11 +39,13 @@ static REGION_LOCK: Mutex = Mutex::new(()); impl<'d> Flash<'d> { pub fn new(p: impl Peripheral

+ 'd) -> Self { into_ref!(p); - Self { _inner: p } + Self { inner: p } } - pub fn into_regions(self) -> FlashRegions { - FlashRegions::take() + pub fn into_regions(self) -> FlashRegions<'d> { + let mut flash = self; + let p = unsafe { flash.inner.clone_unchecked() }; + FlashRegions::new(p) } pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { @@ -123,7 +125,7 @@ impl Drop for Flash<'_> { } } -impl Drop for FlashRegions { +impl Drop for FlashRegions<'_> { fn drop(&mut self) { unsafe { family::lock() }; } From 69944675a3c35a8479fa3b1499246c0f3f971d95 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 12:49:13 +0200 Subject: [PATCH 19/43] Expose get_sector in favor of is_eraseable_range --- embassy-stm32/src/flash/f3.rs | 18 ++++++++++------ embassy-stm32/src/flash/f4.rs | 37 ++++++++++++++++---------------- embassy-stm32/src/flash/f7.rs | 19 +++++----------- embassy-stm32/src/flash/h7.rs | 18 ++++++++++------ embassy-stm32/src/flash/l.rs | 18 ++++++++++------ embassy-stm32/src/flash/mod.rs | 14 +++++++++++- embassy-stm32/src/flash/other.rs | 14 +++++++----- 7 files changed, 81 insertions(+), 57 deletions(-) diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 99ac1a15..3da3962e 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -3,11 +3,11 @@ use core::ptr::write_volatile; use atomic_polyfill::{fence, Ordering}; -use super::{FlashRegion, BANK1, WRITE_SIZE}; +use super::{FlashRegion, FlashSector, BANK1, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -const ERASE_SIZE: usize = BANK1::ERASE_SIZE; +const ERASE_SIZE: usize = BANK1::SETTINGS.erase_size; pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); @@ -41,10 +41,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) blocking_wait_ready() } -pub(crate) fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { - start_address % ERASE_SIZE as u32 == 0 && end_address % ERASE_SIZE as u32 == 0 -} - pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { for page in (start_address..end_address).step_by(ERASE_SIZE) { pac::FLASH.cr().modify(|w| { @@ -107,3 +103,13 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } } } + +pub(crate) fn get_sector(address: u32) -> FlashSector { + let sector_size = BANK1::SETTINGS.erase_size as u32; + let index = address / sector_size; + FlashSector { + index: index as u8, + start: BANK1::SETTINGS.base as u32 + index * sector_size, + size: sector_size, + } +} diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 0fdfecb9..306359be 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -63,24 +63,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) blocking_wait_ready() } -pub(crate) fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { - let dual_bank = is_dual_bank(); - let mut address = start_address; - while address < end_address { - let sector = get_sector(address, dual_bank, FLASH_SIZE as u32); - if sector.start != address { - return false; - } - address += sector.size; - } - address == end_address -} - pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { - let dual_bank = is_dual_bank(); let mut address = start_address; while address < end_address { - let sector = get_sector(address, dual_bank, FLASH_SIZE as u32); + let sector = get_sector(address); erase_sector(sector.index)?; address += sector.size; } @@ -145,7 +131,11 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } } -fn get_sector(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector { +pub(crate) fn get_sector(address: u32) -> FlashSector { + get_sector_inner(address, is_dual_bank(), FLASH_SIZE) +} + +fn get_sector_inner(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector { let offset = address - FLASH_BASE as u32; if !dual_bank { get_single_bank_sector(offset) @@ -187,7 +177,10 @@ fn get_single_bank_sector(offset: u32) -> FlashSector { let large_sector_index = i - 1; FlashSector { index: (5 + large_sector_index) as u8, - start: FLASH_BASE as u32 + 4 * SMALL_SECTOR_SIZE + MEDIUM_SECTOR_SIZE + large_sector_index * LARGE_SECTOR_SIZE, + start: FLASH_BASE as u32 + + 4 * SMALL_SECTOR_SIZE + + MEDIUM_SECTOR_SIZE + + large_sector_index * LARGE_SECTOR_SIZE, size: LARGE_SECTOR_SIZE, } } @@ -201,7 +194,10 @@ mod tests { #[test] fn can_get_sector_single_bank() { let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { - assert_eq!(FlashSector { index, start, size }, get_sector(addr, false, 1024 * 1024)) + assert_eq!( + FlashSector { index, start, size }, + get_sector_inner(addr, false, 1024 * 1024) + ) }; assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); @@ -221,7 +217,10 @@ mod tests { #[test] fn can_get_sector_dual_bank() { let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { - assert_eq!(FlashSector { index, start, size }, get_sector(addr, true, 1024 * 1024)) + assert_eq!( + FlashSector { index, start, size }, + get_sector_inner(addr, true, 1024 * 1024) + ) }; assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 0d3b738c..588fc7a5 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -45,18 +45,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) blocking_wait_ready() } -pub(crate) fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { - let mut address = start_address; - while address < end_address { - let sector = get_sector(address); - if sector.start != address { - return false; - } - address += sector.size; - } - address == end_address -} - pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { let mut address = start_address; while address < end_address { @@ -132,7 +120,7 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } } -fn get_sector(address: u32) -> FlashSector { +pub(crate) fn get_sector(address: u32) -> FlashSector { // First 4 sectors are 32KB, then one 128KB, and rest are 256KB let offset = address - FLASH_BASE as u32; match offset / LARGE_SECTOR_SIZE { @@ -156,7 +144,10 @@ fn get_sector(address: u32) -> FlashSector { let large_sector_index = i - 1; FlashSector { index: (5 + large_sector_index) as u8, - start: FLASH_BASE as u32 + 4 * SMALL_SECTOR_SIZE + MEDIUM_SECTOR_SIZE + large_sector_index * LARGE_SECTOR_SIZE, + start: FLASH_BASE as u32 + + 4 * SMALL_SECTOR_SIZE + + MEDIUM_SECTOR_SIZE + + large_sector_index * LARGE_SECTOR_SIZE, size: LARGE_SECTOR_SIZE, } } diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 21a9e45d..732af853 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -3,11 +3,11 @@ use core::ptr::write_volatile; use atomic_polyfill::{fence, Ordering}; -use super::{FlashRegion, FLASH_SIZE, WRITE_SIZE}; +use super::{FlashRegion, FlashSector, BANK1, FLASH_SIZE, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -const ERASE_SIZE: usize = super::BANK1::ERASE_SIZE; +const ERASE_SIZE: usize = BANK1::SETTINGS.erase_size; const SECOND_BANK_OFFSET: usize = 0x0010_0000; const fn is_dual_bank() -> bool { @@ -78,10 +78,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) res.unwrap() } -pub(crate) fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { - start_address % ERASE_SIZE as u32 == 0 && end_address % ERASE_SIZE as u32 == 0 -} - pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { let start_sector = (start_address - super::FLASH_BASE as u32) / ERASE_SIZE as u32; let end_sector = (end_address - super::FLASH_BASE as u32) / ERASE_SIZE as u32; @@ -194,3 +190,13 @@ unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { } } } + +pub(crate) fn get_sector(address: u32) -> FlashSector { + let sector_size = BANK1::SETTINGS.erase_size as u32; + let index = address / sector_size; + FlashSector { + index: index as u8, + start: BANK1::SETTINGS.base as u32 + index * sector_size, + size: sector_size, + } +} diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 57989625..56a21885 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -2,11 +2,11 @@ use core::ptr::write_volatile; use atomic_polyfill::{fence, Ordering}; -use super::{FlashRegion, WRITE_SIZE}; +use super::{FlashRegion, FlashSector, BANK1, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -const ERASE_SIZE: usize = super::BANK1::ERASE_SIZE; +const ERASE_SIZE: usize = BANK1::SETTINGS.erase_size; pub(crate) unsafe fn lock() { #[cfg(any(flash_wl, flash_wb, flash_l4))] @@ -62,10 +62,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) blocking_wait_ready() } -pub(crate) fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { - start_address % ERASE_SIZE as u32 == 0 && end_address % ERASE_SIZE as u32 == 0 -} - pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { for page in (start_address..end_address).step_by(ERASE_SIZE) { #[cfg(any(flash_l0, flash_l1))] @@ -191,3 +187,13 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } } } + +pub(crate) fn get_sector(address: u32) -> FlashSector { + let sector_size = BANK1::SETTINGS.erase_size as u32; + let index = address / sector_size; + FlashSector { + index: index as u8, + start: BANK1::SETTINGS.base as u32 + index * sector_size, + size: sector_size, + } +} diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 1d1f034a..29cf3cc5 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -104,7 +104,7 @@ impl<'d> Flash<'d> { let start_address = FLASH_BASE as u32 + from; let end_address = FLASH_BASE as u32 + to; - if !family::is_eraseable_range(start_address, end_address) { + if !is_eraseable_range(start_address, end_address) { return Err(Error::Unaligned); } trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); @@ -193,6 +193,18 @@ pub trait FlashRegion { } } +fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { + let mut address = start_address; + while address < end_address { + let sector = family::get_sector(address); + if sector.start != address { + return false; + } + address += sector.size; + } + address == end_address +} + fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { loop { if let Ok(guard) = REGION_LOCK.try_lock() { diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs index c9836d09..4ffb4cc3 100644 --- a/embassy-stm32/src/flash/other.rs +++ b/embassy-stm32/src/flash/other.rs @@ -1,7 +1,11 @@ pub trait FlashRegion { - const BASE: usize; - const SIZE: usize; - const ERASE_SIZE: usize; - const WRITE_SIZE: usize; - const ERASE_VALUE: u8; + const SETTINGS: FlashRegionSettings; +} + +pub struct FlashRegionSettings { + pub base: usize, + pub size: usize, + pub erase_size: usize, + pub write_size: usize, + pub erase_value: u8, } From ddbd5098658612e1421cdd081956c3e6ee3c92f8 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 13:37:10 +0200 Subject: [PATCH 20/43] Move as much logic from families to shared module as possible --- embassy-stm32/src/flash/f3.rs | 40 +++++---- embassy-stm32/src/flash/f4.rs | 15 +--- embassy-stm32/src/flash/f7.rs | 14 +--- embassy-stm32/src/flash/h7.rs | 17 +--- embassy-stm32/src/flash/l.rs | 83 +++++++++---------- embassy-stm32/src/flash/mod.rs | 147 ++++++++++++++------------------- 6 files changed, 129 insertions(+), 187 deletions(-) diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 3da3962e..7b339ccc 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -41,33 +41,31 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) blocking_wait_ready() } -pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { - for page in (start_address..end_address).step_by(ERASE_SIZE) { - pac::FLASH.cr().modify(|w| { - w.set_per(true); - }); +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + pac::FLASH.cr().modify(|w| { + w.set_per(true); + }); - pac::FLASH.ar().write(|w| w.set_far(page)); + pac::FLASH.ar().write(|w| w.set_far(sector.first)); - pac::FLASH.cr().modify(|w| { - w.set_strt(true); - }); + pac::FLASH.cr().modify(|w| { + w.set_strt(true); + }); - let mut ret: Result<(), Error> = blocking_wait_ready(); + let mut ret: Result<(), Error> = blocking_wait_ready(); - if !pac::FLASH.sr().read().eop() { - trace!("FLASH: EOP not set"); - ret = Err(Error::Prog); - } else { - pac::FLASH.sr().write(|w| w.set_eop(true)); - } + if !pac::FLASH.sr().read().eop() { + trace!("FLASH: EOP not set"); + ret = Err(Error::Prog); + } else { + pac::FLASH.sr().write(|w| w.set_eop(true)); + } - pac::FLASH.cr().modify(|w| w.set_per(false)); + pac::FLASH.cr().modify(|w| w.set_per(false)); - clear_all_err(); - if ret.is_err() { - return ret; - } + clear_all_err(); + if ret.is_err() { + return ret; } Ok(()) } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 306359be..cb420c69 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -63,17 +63,8 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) blocking_wait_ready() } -pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { - let mut address = start_address; - while address < end_address { - let sector = get_sector(address); - erase_sector(sector.index)?; - address += sector.size; - } - Ok(()) -} - -unsafe fn erase_sector(sector: u8) -> Result<(), Error> { +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + let sector = sector.index; let bank = sector / SECOND_BANK_SECTOR_OFFSET as u8; let snb = (bank << 4) + (sector % SECOND_BANK_SECTOR_OFFSET as u8); @@ -132,7 +123,7 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } pub(crate) fn get_sector(address: u32) -> FlashSector { - get_sector_inner(address, is_dual_bank(), FLASH_SIZE) + get_sector_inner(address, is_dual_bank(), FLASH_SIZE as u32) } fn get_sector_inner(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector { diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 588fc7a5..eba7df46 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -45,20 +45,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) blocking_wait_ready() } -pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { - let mut address = start_address; - while address < end_address { - let sector = get_sector(address); - erase_sector(sector.index)?; - address += sector.size; - } - Ok(()) -} - -unsafe fn erase_sector(sector: u8) -> Result<(), Error> { +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { pac::FLASH.cr().modify(|w| { w.set_ser(true); - w.set_snb(sector) + w.set_snb(sector.index) }); pac::FLASH.cr().modify(|w| { diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 732af853..28999999 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -78,20 +78,9 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) res.unwrap() } -pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { - let start_sector = (start_address - super::FLASH_BASE as u32) / ERASE_SIZE as u32; - let end_sector = (end_address - super::FLASH_BASE as u32) / ERASE_SIZE as u32; - for sector in start_sector..end_sector { - let bank = if sector >= 8 { 1 } else { 0 }; - let ret = erase_sector(pac::FLASH.bank(bank), (sector % 8) as u8); - if ret.is_err() { - return ret; - } - } - Ok(()) -} - -unsafe fn erase_sector(bank: pac::flash::Bank, sector: u8) -> Result<(), Error> { +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + let bank = pac::FLASH::bank(if sector.index >= 8 { 1 } else { 0 }); + let sector = sector.index % 8; bank.cr().modify(|w| { w.set_ser(true); w.set_snb(sector) diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 56a21885..c8d060f0 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -62,55 +62,50 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) blocking_wait_ready() } -pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { - for page in (start_address..end_address).step_by(ERASE_SIZE) { - #[cfg(any(flash_l0, flash_l1))] - { - pac::FLASH.pecr().modify(|w| { - w.set_erase(true); - w.set_prog(true); - }); - - write_volatile(page as *mut u32, 0xFFFFFFFF); - } - - #[cfg(any(flash_wl, flash_wb, flash_l4))] - { - let idx = (page - super::FLASH_BASE as u32) / ERASE_SIZE as u32; - - #[cfg(flash_l4)] - let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; - - pac::FLASH.cr().modify(|w| { - w.set_per(true); - w.set_pnb(idx as u8); - #[cfg(any(flash_wl, flash_wb))] - w.set_strt(true); - #[cfg(any(flash_l4))] - w.set_start(true); - #[cfg(any(flash_l4))] - w.set_bker(bank); - }); - } - - let ret: Result<(), Error> = blocking_wait_ready(); - - #[cfg(any(flash_wl, flash_wb, flash_l4))] - pac::FLASH.cr().modify(|w| w.set_per(false)); - - #[cfg(any(flash_l0, flash_l1))] +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + #[cfg(any(flash_l0, flash_l1))] + { pac::FLASH.pecr().modify(|w| { - w.set_erase(false); - w.set_prog(false); + w.set_erase(true); + w.set_prog(true); }); - clear_all_err(); - if ret.is_err() { - return ret; - } + write_volatile(sector.start as *mut u32, 0xFFFFFFFF); } - Ok(()) + #[cfg(any(flash_wl, flash_wb, flash_l4))] + { + let idx = (sector.start - super::FLASH_BASE as u32) / ERASE_SIZE as u32; + + #[cfg(flash_l4)] + let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; + + pac::FLASH.cr().modify(|w| { + w.set_per(true); + w.set_pnb(idx as u8); + #[cfg(any(flash_wl, flash_wb))] + w.set_strt(true); + #[cfg(any(flash_l4))] + w.set_start(true); + #[cfg(any(flash_l4))] + w.set_bker(bank); + }); + } + + let ret: Result<(), Error> = blocking_wait_ready(); + + #[cfg(any(flash_wl, flash_wb, flash_l4))] + pac::FLASH.cr().modify(|w| w.set_per(false)); + + #[cfg(any(flash_l0, flash_l1))] + pac::FLASH.pecr().modify(|w| { + w.set_erase(false); + w.set_prog(false); + }); + + clear_all_err(); + + ret } pub(crate) unsafe fn clear_all_err() { diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 29cf3cc5..89fdabd4 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -1,3 +1,4 @@ +use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::{Mutex, MutexGuard}; @@ -14,7 +15,6 @@ use crate::Peripheral; #[cfg_attr(flash_f7, path = "f7.rs")] #[cfg_attr(flash_h7, path = "h7.rs")] mod family; - pub struct Flash<'d> { inner: PeripheralRef<'d, FLASH>, } @@ -49,73 +49,93 @@ impl<'d> Flash<'d> { } pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - if offset as usize + bytes.len() > FLASH_SIZE { + Self::blocking_read_inner(FLASH_BASE as u32 + offset, bytes) + } + + fn blocking_read_inner(start_address: u32, bytes: &mut [u8]) -> Result<(), Error> { + assert!(start_address >= FLASH_BASE as u32); + if start_address as usize + bytes.len() > FLASH_BASE + FLASH_SIZE { return Err(Error::Size); } - let first_address = FLASH_BASE as u32 + offset; - let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; + let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) }; bytes.copy_from_slice(flash_data); Ok(()) } pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { - if offset as usize + buf.len() > FLASH_SIZE { - return Err(Error::Size); - } - if offset as usize % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { - return Err(Error::Unaligned); - } - let start_address = FLASH_BASE as u32 + offset; - trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address); // No need to take lock here as we only have one mut flash reference. - unsafe { - family::clear_all_err(); - family::unlock(); - let res = Flash::blocking_write_all(start_address, buf); - family::lock(); - res - } + unsafe { Flash::blocking_write_inner(start_address, buf) } } - unsafe fn blocking_write_all(start_address: u32, buf: &[u8]) -> Result<(), Error> { - family::begin_write(); - let mut address = start_address; - for chunk in buf.chunks(WRITE_SIZE) { - let res = unsafe { family::blocking_write(address, chunk.try_into().unwrap()) }; - if res.is_err() { - family::end_write(); - return res; - } - address += WRITE_SIZE as u32; + unsafe fn blocking_write_inner(start_address: u32, buf: &[u8]) -> Result<(), Error> { + assert!(start_address >= FLASH_BASE as u32); + if start_address as usize + buf.len() > FLASH_BASE + FLASH_SIZE { + return Err(Error::Size); + } + if (start_address as usize - FLASH_BASE) % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { + return Err(Error::Unaligned); } - family::end_write(); + trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address); + + family::clear_all_err(); + family::unlock(); + family::begin_write(); + + let _ = OnDrop::new(|| { + family::end_write(); + family::lock(); + }); + + let mut address = start_address; + for chunk in buf.chunks(WRITE_SIZE) { + unsafe { family::blocking_write(address, chunk.try_into().unwrap())? }; + address += WRITE_SIZE as u32; + } Ok(()) } pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - if to < from || to as usize > FLASH_SIZE { - return Err(Error::Size); - } - let start_address = FLASH_BASE as u32 + from; let end_address = FLASH_BASE as u32 + to; - if !is_eraseable_range(start_address, end_address) { + + unsafe { Flash::blocking_erase_inner(start_address, end_address) } + } + + unsafe fn blocking_erase_inner(start_address: u32, end_address: u32) -> Result<(), Error> { + // Test if the address range is aligned at sector base addresses + let mut address = start_address; + while address < end_address { + let sector = family::get_sector(address); + if sector.start != address { + return Err(Error::Unaligned); + } + address += sector.size; + } + if address != end_address { return Err(Error::Unaligned); } + trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); - unsafe { - family::clear_all_err(); - family::unlock(); - let res = family::blocking_erase(start_address, end_address); + family::clear_all_err(); + family::unlock(); + + let _ = OnDrop::new(|| { family::lock(); - res + }); + + let mut address = start_address; + while address < end_address { + let sector = family::get_sector(address); + family::blocking_erase_sector(§or)?; + address += sector.size; } + Ok(()) } } @@ -135,76 +155,35 @@ pub trait FlashRegion { const SETTINGS: FlashRegionSettings; fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - if offset as usize + bytes.len() > Self::SETTINGS.size { - return Err(Error::Size); - } - - let first_address = Self::SETTINGS.base as u32 + offset; - let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; - bytes.copy_from_slice(flash_data); - Ok(()) + Flash::blocking_read_inner(Self::SETTINGS.base as u32 + offset, bytes) } fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { - if offset as usize + buf.len() > Self::SETTINGS.size { - return Err(Error::Size); - } - if offset as usize % Self::SETTINGS.write_size != 0 || buf.len() as usize % Self::SETTINGS.write_size != 0 { - return Err(Error::Unaligned); - } - let start_address = Self::SETTINGS.base as u32 + offset; - trace!("Writing {} bytes from 0x{:x}", buf.len(), start_address); // Protect agains simultaneous write/erase to multiple regions. let _guard = take_lock_spin(); unsafe { family::clear_all_err(); - family::unlock(); - let res = Flash::blocking_write_all(start_address, buf); - family::lock(); - res + Flash::blocking_write_inner(start_address, buf) } } fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - if to < from || to as usize > Self::SETTINGS.size { - return Err(Error::Size); - } - if (from as usize % Self::SETTINGS.erase_size) != 0 || (to as usize % Self::SETTINGS.erase_size) != 0 { - return Err(Error::Unaligned); - } - let start_address = Self::SETTINGS.base as u32 + from; let end_address = Self::SETTINGS.base as u32 + to; - trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); // Protect agains simultaneous write/erase to multiple regions. let _guard = take_lock_spin(); unsafe { family::clear_all_err(); - family::unlock(); - let res = family::blocking_erase(start_address, end_address); - family::lock(); - res + Flash::blocking_erase_inner(start_address, end_address) } } } -fn is_eraseable_range(start_address: u32, end_address: u32) -> bool { - let mut address = start_address; - while address < end_address { - let sector = family::get_sector(address); - if sector.start != address { - return false; - } - address += sector.size; - } - address == end_address -} - fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { loop { if let Ok(guard) = REGION_LOCK.try_lock() { From b7dfc8de10ceddd6c2e8c078e529eb5e266ea7db Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 13:52:52 +0200 Subject: [PATCH 21/43] Let flash module be conditionally included --- embassy-stm32/build.rs | 2 ++ embassy-stm32/src/flash/l.rs | 4 +--- embassy-stm32/src/flash/other.rs | 11 ----------- embassy-stm32/src/lib.rs | 11 +---------- 4 files changed, 4 insertions(+), 24 deletions(-) delete mode 100644 embassy-stm32/src/flash/other.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index f5bdadf5..d179f5e0 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -162,11 +162,13 @@ fn main() { let regions_len = flash_memory_regions.len(); flash_regions.extend(quote! { + #[cfg(flash)] pub struct FlashRegions<'d> { _inner: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, #(#fields),* } + #[cfg(flash)] impl<'d> FlashRegions<'d> { pub(crate) const fn new(p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self { Self { diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index c8d060f0..edcf2b2f 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -6,8 +6,6 @@ use super::{FlashRegion, FlashSector, BANK1, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -const ERASE_SIZE: usize = BANK1::SETTINGS.erase_size; - pub(crate) unsafe fn lock() { #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().modify(|w| w.set_lock(true)); @@ -75,7 +73,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(any(flash_wl, flash_wb, flash_l4))] { - let idx = (sector.start - super::FLASH_BASE as u32) / ERASE_SIZE as u32; + let idx = (sector.start - super::FLASH_BASE as u32) / BANK1::SETTINGS.erase_size as u32; #[cfg(flash_l4)] let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs deleted file mode 100644 index 4ffb4cc3..00000000 --- a/embassy-stm32/src/flash/other.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub trait FlashRegion { - const SETTINGS: FlashRegionSettings; -} - -pub struct FlashRegionSettings { - pub base: usize, - pub size: usize, - pub erase_size: usize, - pub write_size: usize, - pub erase_value: u8, -} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index ddd5c0fd..2d49c85b 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -43,17 +43,8 @@ pub mod i2c; #[cfg(crc)] pub mod crc; -#[cfg(any( - flash_l0, flash_l1, flash_wl, flash_wb, flash_l4, flash_f3, flash_f4, flash_f7, flash_h7 -))] +#[cfg(flash)] pub mod flash; -#[cfg(not(any( - flash_l0, flash_l1, flash_wl, flash_wb, flash_l4, flash_f3, flash_f4, flash_f7, flash_h7 -)))] -pub mod flash { - mod other; - pub use other::FlashRegion; -} pub mod pwm; #[cfg(rng)] pub mod rng; From 5a12fd6c75a41b976b2c935cbd8269fd03000a9a Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 13:57:33 +0200 Subject: [PATCH 22/43] Add unimplemented family section --- embassy-stm32/src/flash/mod.rs | 95 ++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 89fdabd4..d4e74553 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -9,12 +9,45 @@ pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; use crate::peripherals::FLASH; use crate::Peripheral; -#[cfg_attr(any(flash_wl, flash_wb, flash_l0, flash_l1, flash_l4), path = "l.rs")] +#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] #[cfg_attr(flash_f3, path = "f3.rs")] #[cfg_attr(flash_f4, path = "f4.rs")] #[cfg_attr(flash_f7, path = "f7.rs")] #[cfg_attr(flash_h7, path = "h7.rs")] mod family; + +#[cfg(not(any( + flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f3, flash_f4, flash_f7, flash_h7 +)))] +mod family { + use super::{Error, FlashSector}; + + pub(crate) unsafe fn lock() { + unimplemented!(); + } + pub(crate) unsafe fn unlock() { + unimplemented!(); + } + pub(crate) unsafe fn begin_write() { + unimplemented!(); + } + pub(crate) unsafe fn end_write() { + unimplemented!(); + } + pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + unimplemented!(); + } + pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> { + unimplemented!(); + } + pub(crate) unsafe fn clear_all_err() { + unimplemented!(); + } + pub(crate) fn get_sector(_address: u32) -> FlashSector { + unimplemented!(); + } +} + pub struct Flash<'d> { inner: PeripheralRef<'d, FLASH>, } @@ -34,6 +67,33 @@ pub struct FlashSector { pub size: u32, } +pub trait FlashRegion { + const SETTINGS: FlashRegionSettings; + + fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + Flash::blocking_read_inner(Self::SETTINGS.base as u32 + offset, bytes) + } + + fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { + let start_address = Self::SETTINGS.base as u32 + offset; + + // Protect agains simultaneous write/erase to multiple regions. + let _guard = take_lock_spin(); + + unsafe { Flash::blocking_write_inner(start_address, buf) } + } + + fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { + let start_address = Self::SETTINGS.base as u32 + from; + let end_address = Self::SETTINGS.base as u32 + to; + + // Protect agains simultaneous write/erase to multiple regions. + let _guard = take_lock_spin(); + + unsafe { Flash::blocking_erase_inner(start_address, end_address) } + } +} + static REGION_LOCK: Mutex = Mutex::new(()); impl<'d> Flash<'d> { @@ -151,39 +211,6 @@ impl Drop for FlashRegions<'_> { } } -pub trait FlashRegion { - const SETTINGS: FlashRegionSettings; - - fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - Flash::blocking_read_inner(Self::SETTINGS.base as u32 + offset, bytes) - } - - fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { - let start_address = Self::SETTINGS.base as u32 + offset; - - // Protect agains simultaneous write/erase to multiple regions. - let _guard = take_lock_spin(); - - unsafe { - family::clear_all_err(); - Flash::blocking_write_inner(start_address, buf) - } - } - - fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let start_address = Self::SETTINGS.base as u32 + from; - let end_address = Self::SETTINGS.base as u32 + to; - - // Protect agains simultaneous write/erase to multiple regions. - let _guard = take_lock_spin(); - - unsafe { - family::clear_all_err(); - Flash::blocking_erase_inner(start_address, end_address) - } - } -} - fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { loop { if let Ok(guard) = REGION_LOCK.try_lock() { From 15e17472207fe587c38ba6cd2c2214ae4e88ee32 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 14:10:16 +0200 Subject: [PATCH 23/43] Fix build of not implemented family --- embassy-stm32/src/flash/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index d4e74553..1186a182 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -20,7 +20,7 @@ mod family; flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f3, flash_f4, flash_f7, flash_h7 )))] mod family { - use super::{Error, FlashSector}; + use super::{Error, FlashSector, WRITE_SIZE}; pub(crate) unsafe fn lock() { unimplemented!(); From fc8c83e00ad6ec810bc73e750e8e943b3e725156 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 14:50:19 +0200 Subject: [PATCH 24/43] Fix h7 compile error --- embassy-stm32/src/flash/h7.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 28999999..82dd4b28 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -79,7 +79,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) } pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { - let bank = pac::FLASH::bank(if sector.index >= 8 { 1 } else { 0 }); + let bank = pac::FLASH.bank(if sector.index >= 8 { 1 } else { 0 }); let sector = sector.index % 8; bank.cr().modify(|w| { w.set_ser(true); From 68c260edeb8822411ac03d569c1c0d91be2b98a5 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 15:03:48 +0200 Subject: [PATCH 25/43] Use stm32-metapac v2 --- embassy-stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 1af439eb..4f660187 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -60,7 +60,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = "1" +stm32-metapac = "2" vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" From ef1890e9110c8ef3553e6a2d0979dfb52520b025 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 15:45:18 +0200 Subject: [PATCH 26/43] Remove flash operations from FlashRegion trait and move to common module --- embassy-stm32/src/flash/common.rs | 177 ++++++++++++++++++++++++++ embassy-stm32/src/flash/mod.rs | 200 ++---------------------------- 2 files changed, 186 insertions(+), 191 deletions(-) create mode 100644 embassy-stm32/src/flash/common.rs diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs new file mode 100644 index 00000000..f92236bb --- /dev/null +++ b/embassy-stm32/src/flash/common.rs @@ -0,0 +1,177 @@ +use embassy_hal_common::drop::OnDrop; +use embassy_hal_common::{into_ref, PeripheralRef}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::mutex::{Mutex, MutexGuard}; +use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; + +use super::{family, Error, FlashRegion}; +pub use crate::_generated::flash_regions::*; +pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +use crate::Peripheral; + +pub struct Flash<'d> { + inner: PeripheralRef<'d, crate::peripherals::FLASH>, +} + +impl<'d> Flash<'d> { + pub fn new(p: impl Peripheral

+ 'd) -> Self { + into_ref!(p); + Self { inner: p } + } + + pub fn into_regions(self) -> FlashRegions<'d> { + let mut flash = self; + let p = unsafe { flash.inner.clone_unchecked() }; + FlashRegions::new(p) + } + + pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + Self::blocking_read_inner(FLASH_BASE as u32 + offset, bytes) + } + + fn blocking_read_inner(start_address: u32, bytes: &mut [u8]) -> Result<(), Error> { + assert!(start_address >= FLASH_BASE as u32); + if start_address as usize + bytes.len() > FLASH_BASE + FLASH_SIZE { + return Err(Error::Size); + } + + let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) }; + bytes.copy_from_slice(flash_data); + Ok(()) + } + + pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { + let start_address = FLASH_BASE as u32 + offset; + + // No need to take lock here as we only have one mut flash reference. + + unsafe { Flash::blocking_write_inner(start_address, buf) } + } + + unsafe fn blocking_write_inner(start_address: u32, buf: &[u8]) -> Result<(), Error> { + assert!(start_address >= FLASH_BASE as u32); + if start_address as usize + buf.len() > FLASH_BASE + FLASH_SIZE { + return Err(Error::Size); + } + if (start_address as usize - FLASH_BASE) % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { + return Err(Error::Unaligned); + } + + trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address); + + family::clear_all_err(); + family::unlock(); + family::begin_write(); + + let _ = OnDrop::new(|| { + family::end_write(); + family::lock(); + }); + + let mut address = start_address; + for chunk in buf.chunks(WRITE_SIZE) { + unsafe { family::blocking_write(address, chunk.try_into().unwrap())? }; + address += WRITE_SIZE as u32; + } + Ok(()) + } + + pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { + let start_address = FLASH_BASE as u32 + from; + let end_address = FLASH_BASE as u32 + to; + + unsafe { Flash::blocking_erase_inner(start_address, end_address) } + } + + unsafe fn blocking_erase_inner(start_address: u32, end_address: u32) -> Result<(), Error> { + // Test if the address range is aligned at sector base addresses + let mut address = start_address; + while address < end_address { + let sector = family::get_sector(address); + if sector.start != address { + return Err(Error::Unaligned); + } + address += sector.size; + } + if address != end_address { + return Err(Error::Unaligned); + } + + trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); + + family::clear_all_err(); + family::unlock(); + + let _ = OnDrop::new(|| { + family::lock(); + }); + + let mut address = start_address; + while address < end_address { + let sector = family::get_sector(address); + family::blocking_erase_sector(§or)?; + address += sector.size; + } + Ok(()) + } +} + +impl Drop for Flash<'_> { + fn drop(&mut self) { + unsafe { family::lock() }; + } +} + +static REGION_LOCK: Mutex = Mutex::new(()); + +fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { + loop { + if let Ok(guard) = REGION_LOCK.try_lock() { + return guard; + } + } +} + +foreach_flash_region! { + ($name:ident) => { + impl ErrorType for crate::_generated::flash_regions::$name { + type Error = Error; + } + + impl ReadNorFlash for crate::_generated::flash_regions::$name { + const READ_SIZE: usize = 1; + + fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + Flash::blocking_read_inner(Self::SETTINGS.base as u32 + offset, bytes) + } + + fn capacity(&self) -> usize { + ::SETTINGS.size + } + } + + impl NorFlash for crate::_generated::flash_regions::$name { + const WRITE_SIZE: usize = ::SETTINGS.write_size; + const ERASE_SIZE: usize = ::SETTINGS.erase_size; + + fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + let start_address = Self::SETTINGS.base as u32 + from; + let end_address = Self::SETTINGS.base as u32 + to; + + // Protect agains simultaneous write/erase to multiple regions. + let _guard = take_lock_spin(); + + unsafe { Flash::blocking_erase_inner(start_address, end_address) } + } + + fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + let start_address = Self::SETTINGS.base as u32 + offset; + + // Protect agains simultaneous write/erase to multiple regions. + let _guard = take_lock_spin(); + + unsafe { Flash::blocking_write_inner(start_address, bytes) } + } + } + }; +} diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 1186a182..ec7c6694 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -1,13 +1,4 @@ -use embassy_hal_common::drop::OnDrop; -use embassy_hal_common::{into_ref, PeripheralRef}; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::mutex::{Mutex, MutexGuard}; -use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; - -pub use crate::_generated::flash_regions::*; -pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; -use crate::peripherals::FLASH; -use crate::Peripheral; +use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] #[cfg_attr(flash_f3, path = "f3.rs")] @@ -48,8 +39,14 @@ mod family { } } -pub struct Flash<'d> { - inner: PeripheralRef<'d, FLASH>, +#[cfg(flash)] +mod common; + +#[cfg(flash)] +pub use common::*; + +pub trait FlashRegion { + const SETTINGS: FlashRegionSettings; } pub struct FlashRegionSettings { @@ -67,158 +64,12 @@ pub struct FlashSector { pub size: u32, } -pub trait FlashRegion { - const SETTINGS: FlashRegionSettings; - - fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - Flash::blocking_read_inner(Self::SETTINGS.base as u32 + offset, bytes) - } - - fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { - let start_address = Self::SETTINGS.base as u32 + offset; - - // Protect agains simultaneous write/erase to multiple regions. - let _guard = take_lock_spin(); - - unsafe { Flash::blocking_write_inner(start_address, buf) } - } - - fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let start_address = Self::SETTINGS.base as u32 + from; - let end_address = Self::SETTINGS.base as u32 + to; - - // Protect agains simultaneous write/erase to multiple regions. - let _guard = take_lock_spin(); - - unsafe { Flash::blocking_erase_inner(start_address, end_address) } - } -} - -static REGION_LOCK: Mutex = Mutex::new(()); - -impl<'d> Flash<'d> { - pub fn new(p: impl Peripheral

+ 'd) -> Self { - into_ref!(p); - Self { inner: p } - } - - pub fn into_regions(self) -> FlashRegions<'d> { - let mut flash = self; - let p = unsafe { flash.inner.clone_unchecked() }; - FlashRegions::new(p) - } - - pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - Self::blocking_read_inner(FLASH_BASE as u32 + offset, bytes) - } - - fn blocking_read_inner(start_address: u32, bytes: &mut [u8]) -> Result<(), Error> { - assert!(start_address >= FLASH_BASE as u32); - if start_address as usize + bytes.len() > FLASH_BASE + FLASH_SIZE { - return Err(Error::Size); - } - - let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) }; - bytes.copy_from_slice(flash_data); - Ok(()) - } - - pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { - let start_address = FLASH_BASE as u32 + offset; - - // No need to take lock here as we only have one mut flash reference. - - unsafe { Flash::blocking_write_inner(start_address, buf) } - } - - unsafe fn blocking_write_inner(start_address: u32, buf: &[u8]) -> Result<(), Error> { - assert!(start_address >= FLASH_BASE as u32); - if start_address as usize + buf.len() > FLASH_BASE + FLASH_SIZE { - return Err(Error::Size); - } - if (start_address as usize - FLASH_BASE) % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { - return Err(Error::Unaligned); - } - - trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address); - - family::clear_all_err(); - family::unlock(); - family::begin_write(); - - let _ = OnDrop::new(|| { - family::end_write(); - family::lock(); - }); - - let mut address = start_address; - for chunk in buf.chunks(WRITE_SIZE) { - unsafe { family::blocking_write(address, chunk.try_into().unwrap())? }; - address += WRITE_SIZE as u32; - } - Ok(()) - } - - pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let start_address = FLASH_BASE as u32 + from; - let end_address = FLASH_BASE as u32 + to; - - unsafe { Flash::blocking_erase_inner(start_address, end_address) } - } - - unsafe fn blocking_erase_inner(start_address: u32, end_address: u32) -> Result<(), Error> { - // Test if the address range is aligned at sector base addresses - let mut address = start_address; - while address < end_address { - let sector = family::get_sector(address); - if sector.start != address { - return Err(Error::Unaligned); - } - address += sector.size; - } - if address != end_address { - return Err(Error::Unaligned); - } - - trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); - - family::clear_all_err(); - family::unlock(); - - let _ = OnDrop::new(|| { - family::lock(); - }); - - let mut address = start_address; - while address < end_address { - let sector = family::get_sector(address); - family::blocking_erase_sector(§or)?; - address += sector.size; - } - Ok(()) - } -} - -impl Drop for Flash<'_> { - fn drop(&mut self) { - unsafe { family::lock() }; - } -} - impl Drop for FlashRegions<'_> { fn drop(&mut self) { unsafe { family::lock() }; } } -fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { - loop { - if let Ok(guard) = REGION_LOCK.try_lock() { - return guard; - } - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { @@ -240,36 +91,3 @@ impl NorFlashError for Error { } } } - -foreach_flash_region! { - ($name:ident) => { - impl ErrorType for crate::_generated::flash_regions::$name { - type Error = Error; - } - - impl ReadNorFlash for crate::_generated::flash_regions::$name { - const READ_SIZE: usize = ::SETTINGS.write_size; - - fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(offset, bytes) - } - - fn capacity(&self) -> usize { - ::SETTINGS.size - } - } - - impl NorFlash for crate::_generated::flash_regions::$name { - const WRITE_SIZE: usize = ::SETTINGS.write_size; - const ERASE_SIZE: usize = ::SETTINGS.erase_size; - - fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - self.blocking_erase(from, to) - } - - fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(offset, bytes) - } - } - }; -} From def576ac4688fb2113aacca46d5bfb4001c8dc1a Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Thu, 30 Mar 2023 04:24:41 +0200 Subject: [PATCH 27/43] Remove FlashRegion trait and rename Settings to FlashRegion --- embassy-stm32/build.rs | 53 +++++++++-------- embassy-stm32/src/flash/common.rs | 98 ++++++++++++++++++++++--------- embassy-stm32/src/flash/mod.rs | 16 ++--- 3 files changed, 103 insertions(+), 64 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index d179f5e0..8f34f510 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -112,64 +112,58 @@ fn main() { .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()) .collect(); for region in flash_memory_regions.iter() { - let region_name = get_flash_region_name(region.name); - let region_type = format_ident!("{}", region_name); - let settings_name = format_ident!("{}_SETTINGS", region_name); - let base = region.address as usize; - let size = region.size as usize; + let region_name = format_ident!("{}", get_flash_region_name(region.name)); + let base = region.address; + let size = region.size; let settings = region.settings.as_ref().unwrap(); - let erase_size = settings.erase_size as usize; - let write_size = settings.write_size as usize; + let erase_size = settings.erase_size; + let write_size = settings.write_size; let erase_value = settings.erase_value; flash_regions.extend(quote! { - #[allow(non_camel_case_types)] - pub struct #region_type(()); - }); - - flash_regions.extend(quote! { - pub const #settings_name: crate::flash::FlashRegionSettings = crate::flash::FlashRegionSettings { + pub const #region_name: crate::flash::FlashRegion = crate::flash::FlashRegion { base: #base, size: #size, erase_size: #erase_size, write_size: #write_size, erase_value: #erase_value, }; + }); - impl crate::flash::FlashRegion for #region_type { - const SETTINGS: crate::flash::FlashRegionSettings = #settings_name; - } + let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); + flash_regions.extend(quote! { + pub struct #region_type(pub(crate) &'static crate::flash::FlashRegion); }); } - let (fields, (inits, settings)): (Vec, (Vec, Vec)) = flash_memory_regions + let (fields, (inits, region_names)): (Vec, (Vec, Vec)) = flash_memory_regions .iter() .map(|f| { let region_name = get_flash_region_name(f.name); let field_name = format_ident!("{}", region_name.to_lowercase()); - let field_type = format_ident!("{}", region_name); + let field_type = format_ident!("{}", get_flash_region_type_name(f.name)); let field = quote! { pub #field_name: #field_type }; + let region_name = format_ident!("{}", region_name); let init = quote! { - #field_name: #field_type(()) + #field_name: #field_type(&#region_name) }; - let settings_name = format_ident!("{}_SETTINGS", region_name); - (field, (init, settings_name)) + (field, (init, region_name)) }) .unzip(); let regions_len = flash_memory_regions.len(); flash_regions.extend(quote! { #[cfg(flash)] - pub struct FlashRegions<'d> { + pub struct FlashLayout<'d> { _inner: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, #(#fields),* } #[cfg(flash)] - impl<'d> FlashRegions<'d> { + impl<'d> FlashLayout<'d> { pub(crate) const fn new(p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self { Self { _inner: p, @@ -178,8 +172,8 @@ fn main() { } } - pub const FLASH_REGIONS: [&crate::flash::FlashRegionSettings; #regions_len] = [ - #(&#settings),* + pub const FLASH_REGIONS: [&crate::flash::FlashRegion; #regions_len] = [ + #(&#region_names),* ]; }); @@ -651,8 +645,11 @@ fn main() { .iter() .filter(|m| m.kind == MemoryRegionKind::Flash && m.settings.is_some()) { + let settings = m.settings.as_ref().unwrap(); let mut row = Vec::new(); - row.push(get_flash_region_name(m.name)); + row.push(get_flash_region_type_name(m.name)); + row.push(settings.write_size.to_string()); + row.push(settings.erase_size.to_string()); flash_regions_table.push(row); } @@ -906,6 +903,10 @@ macro_rules! {} {{ .unwrap(); } +fn get_flash_region_type_name(name: &str) -> String { + name.replace("BANK_", "Bank").replace("REGION_", "Region") +} + fn get_flash_region_name(name: &str) -> String { name.replace("BANK_", "BANK").replace("REGION_", "REGION") } diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index f92236bb..b190a5a0 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -2,7 +2,6 @@ use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::{Mutex, MutexGuard}; -use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; use super::{family, Error, FlashRegion}; pub use crate::_generated::flash_regions::*; @@ -19,10 +18,8 @@ impl<'d> Flash<'d> { Self { inner: p } } - pub fn into_regions(self) -> FlashRegions<'d> { - let mut flash = self; - let p = unsafe { flash.inner.clone_unchecked() }; - FlashRegions::new(p) + pub fn into_regions(self) -> FlashLayout<'d> { + FlashLayout::new(self.release()) } pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { @@ -114,6 +111,11 @@ impl<'d> Flash<'d> { } Ok(()) } + + pub(crate) fn release(self) -> PeripheralRef<'d, crate::peripherals::FLASH> { + let mut flash = self; + unsafe { flash.inner.clone_unchecked() } + } } impl Drop for Flash<'_> { @@ -132,45 +134,85 @@ fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { } } +impl FlashRegion { + pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + unsafe { self.blocking_read_inner(offset, bytes) } + } + + pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { + unsafe { self.blocking_write_inner(offset, bytes) } + } + + pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { + unsafe { self.blocking_erase_inner(from, to) } + } + + unsafe fn blocking_read_inner(&self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + Flash::blocking_read_inner(self.base + offset, bytes) + } + + unsafe fn blocking_write_inner(&self, offset: u32, bytes: &[u8]) -> Result<(), Error> { + let start_address = self.base + offset; + + // Protect agains simultaneous write/erase to multiple regions. + let _guard = take_lock_spin(); + + Flash::blocking_write_inner(start_address, bytes) + } + + unsafe fn blocking_erase_inner(&self, from: u32, to: u32) -> Result<(), Error> { + let start_address = self.base + from; + let end_address = self.base + to; + + // Protect agains simultaneous write/erase to multiple regions. + let _guard = take_lock_spin(); + + Flash::blocking_erase_inner(start_address, end_address) + } +} + foreach_flash_region! { - ($name:ident) => { - impl ErrorType for crate::_generated::flash_regions::$name { + ($type_name:ident, $write_size:ident, $erase_size:ident) => { + impl crate::_generated::flash_regions::$type_name { + pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + unsafe { self.0.blocking_read_inner(offset, bytes) } + } + + pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { + unsafe { self.0.blocking_write_inner(offset, bytes) } + } + + pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { + unsafe { self.0.blocking_erase_inner(from, to) } + } + } + + impl ErrorType for crate::_generated::flash_regions::$type_name { type Error = Error; } - impl ReadNorFlash for crate::_generated::flash_regions::$name { + impl ReadNorFlash for crate::_generated::flash_regions::$type_name { const READ_SIZE: usize = 1; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - Flash::blocking_read_inner(Self::SETTINGS.base as u32 + offset, bytes) + unsafe { self.0.blocking_read_inner(offset, bytes) } } fn capacity(&self) -> usize { - ::SETTINGS.size + self.0.size as usize } } - impl NorFlash for crate::_generated::flash_regions::$name { - const WRITE_SIZE: usize = ::SETTINGS.write_size; - const ERASE_SIZE: usize = ::SETTINGS.erase_size; - - fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - let start_address = Self::SETTINGS.base as u32 + from; - let end_address = Self::SETTINGS.base as u32 + to; - - // Protect agains simultaneous write/erase to multiple regions. - let _guard = take_lock_spin(); - - unsafe { Flash::blocking_erase_inner(start_address, end_address) } - } + impl NorFlash for crate::_generated::flash_regions::$type_name { + const WRITE_SIZE: usize = $write_size; + const ERASE_SIZE: usize = $erase_size; fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - let start_address = Self::SETTINGS.base as u32 + offset; + unsafe { self.0.blocking_write_inner(offset, bytes) } + } - // Protect agains simultaneous write/erase to multiple regions. - let _guard = take_lock_spin(); - - unsafe { Flash::blocking_write_inner(start_address, bytes) } + fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + unsafe { self.0.blocking_erase_inner(from, to) } } } }; diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index ec7c6694..1e7d4c65 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -45,15 +45,11 @@ mod common; #[cfg(flash)] pub use common::*; -pub trait FlashRegion { - const SETTINGS: FlashRegionSettings; -} - -pub struct FlashRegionSettings { - pub base: usize, - pub size: usize, - pub erase_size: usize, - pub write_size: usize, +pub struct FlashRegion { + pub base: u32, + pub size: u32, + pub erase_size: u32, + pub write_size: u32, pub erase_value: u8, } @@ -64,7 +60,7 @@ pub struct FlashSector { pub size: u32, } -impl Drop for FlashRegions<'_> { +impl Drop for FlashLayout<'_> { fn drop(&mut self) { unsafe { family::lock() }; } From 91d8afd371c20d21765713a45625f62ce25d97b6 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Thu, 30 Mar 2023 05:27:57 +0200 Subject: [PATCH 28/43] Add AltFlashLayout for supported F4 chips --- embassy-stm32/build.rs | 16 +++++-- embassy-stm32/src/flash/common.rs | 4 +- embassy-stm32/src/flash/f4.rs | 75 +++++++++++++++++++++++++++++++ embassy-stm32/src/flash/mod.rs | 58 +++++++++++++----------- 4 files changed, 120 insertions(+), 33 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ec9b6dc0..6b203a3f 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -910,10 +910,18 @@ macro_rules! {} {{ .unwrap(); } -fn get_flash_region_type_name(name: &str) -> String { - name.replace("BANK_", "Bank").replace("REGION_", "Region") +fn get_flash_region_name(name: &str) -> String { + let name = name.replace("BANK_", "BANK").replace("REGION_", "REGION"); + if name.contains("REGION") { + name + } else { + name + "_REGION" + } } -fn get_flash_region_name(name: &str) -> String { - name.replace("BANK_", "BANK").replace("REGION_", "REGION") +fn get_flash_region_type_name(name: &str) -> String { + get_flash_region_name(name) + .replace("BANK", "Bank") + .replace("REGION", "Region") + .replace("_", "") } diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index b190a5a0..c239d967 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -3,9 +3,7 @@ use embassy_hal_common::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::{Mutex, MutexGuard}; -use super::{family, Error, FlashRegion}; -pub use crate::_generated::flash_regions::*; -pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +use super::{family, Error, FlashLayout, FlashRegion, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; use crate::Peripheral; pub struct Flash<'d> { diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index cb420c69..257aae2d 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -11,7 +11,82 @@ const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; const LARGE_SECTOR_SIZE: u32 = 128 * 1024; const SECOND_BANK_SECTOR_OFFSET: u8 = 12; +#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] +mod alt_regions { + use embassy_hal_common::PeripheralRef; + use stm32_metapac::FLASH_SIZE; + + use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3}; + use crate::flash::{Bank1Region1, Bank1Region2, Flash, FlashRegion}; + use crate::peripherals::FLASH; + + pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion { + size: 3 * BANK1_REGION3.erase_size, + ..BANK1_REGION3 + }; + pub const ALT_BANK2_REGION1: FlashRegion = FlashRegion { + base: BANK1_REGION1.base + FLASH_SIZE as u32 / 2, + ..BANK1_REGION1 + }; + pub const ALT_BANK2_REGION2: FlashRegion = FlashRegion { + base: BANK1_REGION2.base + FLASH_SIZE as u32 / 2, + ..BANK1_REGION2 + }; + pub const ALT_BANK2_REGION3: FlashRegion = FlashRegion { + base: BANK1_REGION3.base + FLASH_SIZE as u32 / 2, + size: 3 * BANK1_REGION3.erase_size, + ..BANK1_REGION3 + }; + + pub type AltBank1Region1 = Bank1Region1; + pub type AltBank1Region2 = Bank1Region2; + pub struct AltBank1Region3(&'static FlashRegion); + pub struct AltBank2Region1(&'static FlashRegion); + pub struct AltBank2Region2(&'static FlashRegion); + pub struct AltBank2Region3(&'static FlashRegion); + + pub struct AltFlashLayout<'d> { + _inner: PeripheralRef<'d, FLASH>, + pub bank1_region1: AltBank1Region1, + pub bank1_region2: AltBank1Region2, + pub bank1_region3: AltBank1Region3, + pub bank2_region1: AltBank2Region1, + pub bank2_region2: AltBank2Region2, + pub bank2_region3: AltBank2Region3, + } + + impl<'d> Flash<'d> { + pub fn into_alt_regions(self) -> AltFlashLayout<'d> { + unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) }; + AltFlashLayout { + _inner: self.release(), + bank1_region1: Bank1Region1(&BANK1_REGION1), + bank1_region2: Bank1Region2(&BANK1_REGION2), + bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3), + bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1), + bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2), + bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3), + } + } + } + + impl Drop for AltFlashLayout<'_> { + fn drop(&mut self) { + unsafe { + super::lock(); + crate::pac::FLASH.optcr().modify(|r| r.set_db1m(false)) + }; + } + } +} + +#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] +pub use alt_regions::AltFlashLayout; + fn is_dual_bank() -> bool { + // let asd: super::Bank1Region1; + // let sad = &super::BANK_1_REGION_1; + match FLASH_SIZE / 1024 { // 1 MB devices depend on configuration 1024 => { diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 1e7d4c65..7dc71471 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -1,5 +1,35 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; +#[cfg(flash)] +mod common; + +#[cfg(flash)] +pub use common::*; + +pub use crate::_generated::flash_regions::*; +pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; + +pub struct FlashRegion { + pub base: u32, + pub size: u32, + pub erase_size: u32, + pub write_size: u32, + pub erase_value: u8, +} + +#[derive(Debug, PartialEq)] +pub struct FlashSector { + pub index: u8, + pub start: u32, + pub size: u32, +} + +impl Drop for FlashLayout<'_> { + fn drop(&mut self) { + unsafe { family::lock() }; + } +} + #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] #[cfg_attr(flash_f3, path = "f3.rs")] #[cfg_attr(flash_f4, path = "f4.rs")] @@ -39,32 +69,8 @@ mod family { } } -#[cfg(flash)] -mod common; - -#[cfg(flash)] -pub use common::*; - -pub struct FlashRegion { - pub base: u32, - pub size: u32, - pub erase_size: u32, - pub write_size: u32, - pub erase_value: u8, -} - -#[derive(Debug, PartialEq)] -pub struct FlashSector { - pub index: u8, - pub start: u32, - pub size: u32, -} - -impl Drop for FlashLayout<'_> { - fn drop(&mut self) { - unsafe { family::lock() }; - } -} +#[allow(unused_imports)] +pub use family::*; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] From e3c4e00be0469030f163568efa2902d73e2b8a4c Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Thu, 30 Mar 2023 06:01:56 +0200 Subject: [PATCH 29/43] Align families --- embassy-stm32/src/flash/common.rs | 6 +++++ embassy-stm32/src/flash/f3.rs | 10 +++---- embassy-stm32/src/flash/f4.rs | 3 --- embassy-stm32/src/flash/h7.rs | 14 ++++------ embassy-stm32/src/flash/l.rs | 8 +++--- embassy-stm32/src/flash/mod.rs | 44 +++++++------------------------ embassy-stm32/src/flash/other.rs | 27 +++++++++++++++++++ embassy-stm32/src/lib.rs | 1 - 8 files changed, 55 insertions(+), 58 deletions(-) create mode 100644 embassy-stm32/src/flash/other.rs diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index c239d967..6534e1b8 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -122,6 +122,12 @@ impl Drop for Flash<'_> { } } +impl Drop for FlashLayout<'_> { + fn drop(&mut self) { + unsafe { family::lock() }; + } +} + static REGION_LOCK: Mutex = Mutex::new(()); fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 7b339ccc..5ac1d8fd 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -3,12 +3,10 @@ use core::ptr::write_volatile; use atomic_polyfill::{fence, Ordering}; -use super::{FlashRegion, FlashSector, BANK1, WRITE_SIZE}; +use super::{FlashSector, BANK1_REGION, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -const ERASE_SIZE: usize = BANK1::SETTINGS.erase_size; - pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -46,7 +44,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E w.set_per(true); }); - pac::FLASH.ar().write(|w| w.set_far(sector.first)); + pac::FLASH.ar().write(|w| w.set_far(sector.start)); pac::FLASH.cr().modify(|w| { w.set_strt(true); @@ -103,11 +101,11 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } pub(crate) fn get_sector(address: u32) -> FlashSector { - let sector_size = BANK1::SETTINGS.erase_size as u32; + let sector_size = BANK1_REGION.erase_size; let index = address / sector_size; FlashSector { index: index as u8, - start: BANK1::SETTINGS.base as u32 + index * sector_size, + start: BANK1_REGION.base + index * sector_size, size: sector_size, } } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 257aae2d..52ef7ad5 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -84,9 +84,6 @@ mod alt_regions { pub use alt_regions::AltFlashLayout; fn is_dual_bank() -> bool { - // let asd: super::Bank1Region1; - // let sad = &super::BANK_1_REGION_1; - match FLASH_SIZE / 1024 { // 1 MB devices depend on configuration 1024 => { diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 82dd4b28..360ad77d 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -3,15 +3,12 @@ use core::ptr::write_volatile; use atomic_polyfill::{fence, Ordering}; -use super::{FlashRegion, FlashSector, BANK1, FLASH_SIZE, WRITE_SIZE}; +use super::{FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -const ERASE_SIZE: usize = BANK1::SETTINGS.erase_size; -const SECOND_BANK_OFFSET: usize = 0x0010_0000; - const fn is_dual_bank() -> bool { - FLASH_SIZE / 2 > ERASE_SIZE + FLASH_REGIONS.len() == 2 } pub(crate) unsafe fn lock() { @@ -24,7 +21,6 @@ pub(crate) unsafe fn lock() { pub(crate) unsafe fn unlock() { pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123)); pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); - if is_dual_bank() { pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123)); pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); @@ -39,7 +35,7 @@ pub(crate) unsafe fn end_write() {} pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { // We cannot have the write setup sequence in begin_write as it depends on the address - let bank = if !is_dual_bank() || (start_address - super::FLASH_BASE as u32) < SECOND_BANK_OFFSET as u32 { + let bank = if start_address < BANK1_REGION.end() { pac::FLASH.bank(0) } else { pac::FLASH.bank(1) @@ -181,11 +177,11 @@ unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { } pub(crate) fn get_sector(address: u32) -> FlashSector { - let sector_size = BANK1::SETTINGS.erase_size as u32; + let sector_size = BANK1_REGION.erase_size; let index = address / sector_size; FlashSector { index: index as u8, - start: BANK1::SETTINGS.base as u32 + index * sector_size, + start: BANK1_REGION.base + index * sector_size, size: sector_size, } } diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index edcf2b2f..f4b11011 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -2,7 +2,7 @@ use core::ptr::write_volatile; use atomic_polyfill::{fence, Ordering}; -use super::{FlashRegion, FlashSector, BANK1, WRITE_SIZE}; +use super::{FlashSector, BANK1_REGION, WRITE_SIZE}; use crate::flash::Error; use crate::pac; @@ -73,7 +73,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(any(flash_wl, flash_wb, flash_l4))] { - let idx = (sector.start - super::FLASH_BASE as u32) / BANK1::SETTINGS.erase_size as u32; + let idx = (sector.start - super::FLASH_BASE as u32) / BANK1_REGION.erase_size as u32; #[cfg(flash_l4)] let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; @@ -182,11 +182,11 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } pub(crate) fn get_sector(address: u32) -> FlashSector { - let sector_size = BANK1::SETTINGS.erase_size as u32; + let sector_size = BANK1_REGION.erase_size; let index = address / sector_size; FlashSector { index: index as u8, - start: BANK1::SETTINGS.base as u32 + index * sector_size, + start: BANK1_REGION.base + index * sector_size, size: sector_size, } } diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 7dc71471..110b8149 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -24,9 +24,9 @@ pub struct FlashSector { pub size: u32, } -impl Drop for FlashLayout<'_> { - fn drop(&mut self) { - unsafe { family::lock() }; +impl FlashRegion { + pub const fn end(&self) -> u32 { + self.base + self.size } } @@ -35,40 +35,14 @@ impl Drop for FlashLayout<'_> { #[cfg_attr(flash_f4, path = "f4.rs")] #[cfg_attr(flash_f7, path = "f7.rs")] #[cfg_attr(flash_h7, path = "h7.rs")] +#[cfg_attr( + not(any( + flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f3, flash_f4, flash_f7, flash_h7 + )), + path = "other.rs" +)] mod family; -#[cfg(not(any( - flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f3, flash_f4, flash_f7, flash_h7 -)))] -mod family { - use super::{Error, FlashSector, WRITE_SIZE}; - - pub(crate) unsafe fn lock() { - unimplemented!(); - } - pub(crate) unsafe fn unlock() { - unimplemented!(); - } - pub(crate) unsafe fn begin_write() { - unimplemented!(); - } - pub(crate) unsafe fn end_write() { - unimplemented!(); - } - pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { - unimplemented!(); - } - pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> { - unimplemented!(); - } - pub(crate) unsafe fn clear_all_err() { - unimplemented!(); - } - pub(crate) fn get_sector(_address: u32) -> FlashSector { - unimplemented!(); - } -} - #[allow(unused_imports)] pub use family::*; diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs new file mode 100644 index 00000000..fd355122 --- /dev/null +++ b/embassy-stm32/src/flash/other.rs @@ -0,0 +1,27 @@ +#[allow(unused)] +use super::{Error, FlashSector, WRITE_SIZE}; + +pub(crate) unsafe fn lock() { + unimplemented!(); +} +pub(crate) unsafe fn unlock() { + unimplemented!(); +} +pub(crate) unsafe fn begin_write() { + unimplemented!(); +} +pub(crate) unsafe fn end_write() { + unimplemented!(); +} +pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + unimplemented!(); +} +pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> { + unimplemented!(); +} +pub(crate) unsafe fn clear_all_err() { + unimplemented!(); +} +pub(crate) fn get_sector(_address: u32) -> FlashSector { + unimplemented!(); +} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 75ff2d75..3f2d078f 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -43,7 +43,6 @@ pub mod i2c; #[cfg(crc)] pub mod crc; -#[cfg(flash)] pub mod flash; pub mod pwm; #[cfg(quadspi)] From e7129371d0d543394c070671490a796ddbb10e3f Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Thu, 30 Mar 2023 08:32:36 +0200 Subject: [PATCH 30/43] Let sector computation be shared across families --- ci.sh | 1 + embassy-stm32/build.rs | 13 +++ embassy-stm32/src/flash/common.rs | 35 +++++- embassy-stm32/src/flash/f3.rs | 16 +-- embassy-stm32/src/flash/f4.rs | 181 ++++++++++++------------------ embassy-stm32/src/flash/f7.rs | 95 +++++++++------- embassy-stm32/src/flash/h7.rs | 21 ++-- embassy-stm32/src/flash/l.rs | 18 +-- embassy-stm32/src/flash/mod.rs | 15 ++- embassy-stm32/src/flash/other.rs | 12 +- 10 files changed, 208 insertions(+), 199 deletions(-) diff --git a/ci.sh b/ci.sh index d86c9352..b9dddad3 100755 --- a/ci.sh +++ b/ci.sh @@ -49,6 +49,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \ --- 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/build.rs b/embassy-stm32/build.rs index 6b203a3f..00740924 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -113,6 +113,18 @@ fn main() { .collect(); for region in flash_memory_regions.iter() { let region_name = format_ident!("{}", get_flash_region_name(region.name)); + let bank = format_ident!( + "{}", + if region.name.starts_with("BANK_1") { + "Bank1" + } else if region.name.starts_with("BANK_2") { + "Bank2" + } else if region.name == "OTP" { + "Otp" + } else { + unimplemented!() + } + ); let base = region.address; let size = region.size; let settings = region.settings.as_ref().unwrap(); @@ -122,6 +134,7 @@ fn main() { flash_regions.extend(quote! { pub const #region_name: crate::flash::FlashRegion = crate::flash::FlashRegion { + bank: crate::flash::FlashBank::#bank, base: #base, size: #size, erase_size: #erase_size, diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 6534e1b8..31dd1136 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -3,7 +3,8 @@ use embassy_hal_common::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::{Mutex, MutexGuard}; -use super::{family, Error, FlashLayout, FlashRegion, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +use super::{family, Error, FlashLayout, FlashRegion, FlashSector, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +use crate::flash::FlashBank; use crate::Peripheral; pub struct Flash<'d> { @@ -79,10 +80,12 @@ impl<'d> Flash<'d> { } unsafe fn blocking_erase_inner(start_address: u32, end_address: u32) -> Result<(), Error> { + let regions = family::get_flash_regions(); + // Test if the address range is aligned at sector base addresses let mut address = start_address; while address < end_address { - let sector = family::get_sector(address); + let sector = get_sector(address, regions); if sector.start != address { return Err(Error::Unaligned); } @@ -103,7 +106,8 @@ impl<'d> Flash<'d> { let mut address = start_address; while address < end_address { - let sector = family::get_sector(address); + let sector = get_sector(address, regions); + trace!("Erasing sector: {}", sector); family::blocking_erase_sector(§or)?; address += sector.size; } @@ -138,6 +142,31 @@ fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { } } +pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { + let mut current_bank = FlashBank::Bank1; + let mut bank_offset = 0; + for region in regions { + if region.bank != current_bank { + current_bank = region.bank; + bank_offset = 0; + } + + if address < region.end() { + let index_in_region = (address - region.base) / region.erase_size; + return FlashSector { + bank: region.bank, + index_in_bank: bank_offset + index_in_region as u8, + start: region.base + index_in_region * region.erase_size, + size: region.erase_size, + }; + } + + bank_offset += region.sectors(); + } + + panic!("Flash sector not found"); +} + impl FlashRegion { pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { unsafe { self.blocking_read_inner(offset, bytes) } diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 5ac1d8fd..c1ed33f9 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -3,10 +3,14 @@ use core::ptr::write_volatile; use atomic_polyfill::{fence, Ordering}; -use super::{FlashSector, BANK1_REGION, WRITE_SIZE}; +use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} + pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -99,13 +103,3 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } } } - -pub(crate) fn get_sector(address: u32) -> FlashSector { - let sector_size = BANK1_REGION.erase_size; - let index = address / sector_size; - FlashSector { - index: index as u8, - start: BANK1_REGION.base + index * sector_size, - size: sector_size, - } -} diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 52ef7ad5..61ac8afd 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -2,22 +2,17 @@ use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashSector, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -const SMALL_SECTOR_SIZE: u32 = 16 * 1024; -const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; -const LARGE_SECTOR_SIZE: u32 = 128 * 1024; -const SECOND_BANK_SECTOR_OFFSET: u8 = 12; - #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] mod alt_regions { use embassy_hal_common::PeripheralRef; use stm32_metapac::FLASH_SIZE; use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3}; - use crate::flash::{Bank1Region1, Bank1Region2, Flash, FlashRegion}; + use crate::flash::{Bank1Region1, Bank1Region2, Flash, FlashBank, FlashRegion}; use crate::peripherals::FLASH; pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion { @@ -25,19 +20,31 @@ mod alt_regions { ..BANK1_REGION3 }; pub const ALT_BANK2_REGION1: FlashRegion = FlashRegion { + bank: FlashBank::Bank2, base: BANK1_REGION1.base + FLASH_SIZE as u32 / 2, ..BANK1_REGION1 }; pub const ALT_BANK2_REGION2: FlashRegion = FlashRegion { + bank: FlashBank::Bank2, base: BANK1_REGION2.base + FLASH_SIZE as u32 / 2, ..BANK1_REGION2 }; pub const ALT_BANK2_REGION3: FlashRegion = FlashRegion { + bank: FlashBank::Bank2, base: BANK1_REGION3.base + FLASH_SIZE as u32 / 2, size: 3 * BANK1_REGION3.erase_size, ..BANK1_REGION3 }; + pub const ALT_FLASH_REGIONS: [&FlashRegion; 6] = [ + &BANK1_REGION1, + &BANK1_REGION2, + &ALT_BANK1_REGION3, + &ALT_BANK2_REGION1, + &ALT_BANK2_REGION2, + &ALT_BANK2_REGION3, + ]; + pub type AltBank1Region1 = Bank1Region1; pub type AltBank1Region2 = Bank1Region2; pub struct AltBank1Region3(&'static FlashRegion); @@ -81,25 +88,22 @@ mod alt_regions { } #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] -pub use alt_regions::AltFlashLayout; +pub use alt_regions::{AltFlashLayout, ALT_FLASH_REGIONS}; -fn is_dual_bank() -> bool { - match FLASH_SIZE / 1024 { - // 1 MB devices depend on configuration - 1024 => { - if cfg!(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)) { - unsafe { pac::FLASH.optcr().read().db1m() } - } else { - false - } - } - // 2 MB devices are always dual bank - 2048 => true, - // All other devices are single bank - _ => false, +#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] +pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { + if unsafe { pac::FLASH.optcr().read().db1m() } { + &ALT_FLASH_REGIONS + } else { + &FLASH_REGIONS } } +#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))] +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} + pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -136,11 +140,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) } pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { - let sector = sector.index; - let bank = sector / SECOND_BANK_SECTOR_OFFSET as u8; - let snb = (bank << 4) + (sector % SECOND_BANK_SECTOR_OFFSET as u8); - - trace!("Erasing sector: {}", sector); + let snb = ((sector.bank as u8) << 4) + sector.index_in_bank; pac::FLASH.cr().modify(|w| { w.set_ser(true); @@ -194,72 +194,27 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } } -pub(crate) fn get_sector(address: u32) -> FlashSector { - get_sector_inner(address, is_dual_bank(), FLASH_SIZE as u32) -} - -fn get_sector_inner(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector { - let offset = address - FLASH_BASE as u32; - if !dual_bank { - get_single_bank_sector(offset) - } else { - let bank_size = flash_size / 2; - if offset < bank_size { - get_single_bank_sector(offset) - } else { - let sector = get_single_bank_sector(offset - bank_size); - FlashSector { - index: SECOND_BANK_SECTOR_OFFSET + sector.index, - start: sector.start + bank_size, - size: sector.size, - } - } - } -} - -fn get_single_bank_sector(offset: u32) -> FlashSector { - // First 4 sectors are 16KB, then one 64KB, and rest are 128KB - match offset / LARGE_SECTOR_SIZE { - 0 => { - if offset < 4 * SMALL_SECTOR_SIZE { - let small_sector_index = offset / SMALL_SECTOR_SIZE; - FlashSector { - index: small_sector_index as u8, - start: FLASH_BASE as u32 + small_sector_index * SMALL_SECTOR_SIZE, - size: SMALL_SECTOR_SIZE, - } - } else { - FlashSector { - index: 4, - start: FLASH_BASE as u32 + 4 * SMALL_SECTOR_SIZE, - size: MEDIUM_SECTOR_SIZE, - } - } - } - i => { - let large_sector_index = i - 1; - FlashSector { - index: (5 + large_sector_index) as u8, - start: FLASH_BASE as u32 - + 4 * SMALL_SECTOR_SIZE - + MEDIUM_SECTOR_SIZE - + large_sector_index * LARGE_SECTOR_SIZE, - size: LARGE_SECTOR_SIZE, - } - } - } -} - #[cfg(test)] mod tests { use super::*; + use crate::flash::{get_sector, FlashBank}; #[test] + #[cfg(stm32f429)] fn can_get_sector_single_bank() { - let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { + const SMALL_SECTOR_SIZE: u32 = 16 * 1024; + const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; + const LARGE_SECTOR_SIZE: u32 = 128 * 1024; + + let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32| { assert_eq!( - FlashSector { index, start, size }, - get_sector_inner(addr, false, 1024 * 1024) + FlashSector { + bank: FlashBank::Bank1, + index_in_bank, + start, + size + }, + get_sector(address, &FLASH_REGIONS) ) }; @@ -275,41 +230,43 @@ mod tests { assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); - } - #[test] - fn can_get_sector_dual_bank() { - let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { + let assert_sector = |bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| { assert_eq!( - FlashSector { index, start, size }, - get_sector_inner(addr, true, 1024 * 1024) + FlashSector { + bank, + index_in_bank, + start, + size + }, + get_sector(address, &ALT_FLASH_REGIONS) ) }; - assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); - assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); - assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); + assert_sector(FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); - assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); - assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + assert_sector(FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); - assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); - assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); - assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); - assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); + assert_sector(FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); + assert_sector(FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); - assert_sector(12, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); - assert_sector(12, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); - assert_sector(15, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); - assert_sector(15, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); + assert_sector(FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); + assert_sector(FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); + assert_sector(FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); + assert_sector(FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); - assert_sector(16, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); - assert_sector(16, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); + assert_sector(FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); + assert_sector(FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); - assert_sector(17, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); - assert_sector(17, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); - assert_sector(19, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); - assert_sector(19, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); + assert_sector(FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); + assert_sector(FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); + assert_sector(FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); } } diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index eba7df46..7111f5cc 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -2,13 +2,13 @@ use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashSector, FLASH_BASE, WRITE_SIZE}; +use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -const SMALL_SECTOR_SIZE: u32 = 32 * 1024; -const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024; -const LARGE_SECTOR_SIZE: u32 = 256 * 1024; +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); @@ -48,7 +48,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { pac::FLASH.cr().modify(|w| { w.set_ser(true); - w.set_snb(sector.index) + w.set_snb(sector.index_in_bank) }); pac::FLASH.cr().modify(|w| { @@ -110,48 +110,61 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } } -pub(crate) fn get_sector(address: u32) -> FlashSector { - // First 4 sectors are 32KB, then one 128KB, and rest are 256KB - let offset = address - FLASH_BASE as u32; - match offset / LARGE_SECTOR_SIZE { - 0 => { - if offset < 4 * SMALL_SECTOR_SIZE { - let small_sector_index = offset / SMALL_SECTOR_SIZE; - FlashSector { - index: small_sector_index as u8, - start: FLASH_BASE as u32 + small_sector_index * SMALL_SECTOR_SIZE, - size: SMALL_SECTOR_SIZE, - } - } else { - FlashSector { - index: 4, - start: FLASH_BASE as u32 + 4 * SMALL_SECTOR_SIZE, - size: MEDIUM_SECTOR_SIZE, - } - } - } - i => { - let large_sector_index = i - 1; - FlashSector { - index: (5 + large_sector_index) as u8, - start: FLASH_BASE as u32 - + 4 * SMALL_SECTOR_SIZE - + MEDIUM_SECTOR_SIZE - + large_sector_index * LARGE_SECTOR_SIZE, - size: LARGE_SECTOR_SIZE, - } - } - } -} - #[cfg(test)] mod tests { use super::*; + use crate::flash::{get_sector, FlashBank}; #[test] + #[cfg(stm32f732)] fn can_get_sector() { - let assert_sector = |index: u8, start: u32, size: u32, addr: u32| { - assert_eq!(FlashSector { index, start, size }, get_sector(addr)) + const SMALL_SECTOR_SIZE: u32 = 16 * 1024; + const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; + const LARGE_SECTOR_SIZE: u32 = 128 * 1024; + + let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32| { + assert_eq!( + FlashSector { + bank: FlashBank::Bank1, + index_in_bank, + start, + size + }, + get_sector(address, &FLASH_REGIONS) + ) + }; + + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); + + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); + assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); + } + + #[test] + #[cfg(stm32f769)] + fn can_get_sector() { + const SMALL_SECTOR_SIZE: u32 = 32 * 1024; + const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024; + const LARGE_SECTOR_SIZE: u32 = 256 * 1024; + + let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32| { + assert_eq!( + FlashSector { + bank: FlashBank::Bank1, + index_in_bank, + start, + size + }, + get_sector(address, &FLASH_REGIONS) + ) }; assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 360ad77d..5ea57ccd 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -3,7 +3,7 @@ use core::ptr::write_volatile; use atomic_polyfill::{fence, Ordering}; -use super::{FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; @@ -11,6 +11,10 @@ const fn is_dual_bank() -> bool { FLASH_REGIONS.len() == 2 } +pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} + pub(crate) unsafe fn lock() { pac::FLASH.bank(0).cr().modify(|w| w.set_lock(true)); if is_dual_bank() { @@ -75,11 +79,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) } pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { - let bank = pac::FLASH.bank(if sector.index >= 8 { 1 } else { 0 }); - let sector = sector.index % 8; + let bank = pac::FLASH.bank(sector.bank as usize); bank.cr().modify(|w| { w.set_ser(true); - w.set_snb(sector) + w.set_snb(sector.index_in_bank) }); bank.cr().modify(|w| { @@ -175,13 +178,3 @@ unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { } } } - -pub(crate) fn get_sector(address: u32) -> FlashSector { - let sector_size = BANK1_REGION.erase_size; - let index = address / sector_size; - FlashSector { - index: index as u8, - start: BANK1_REGION.base + index * sector_size, - size: sector_size, - } -} diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index f4b11011..f5ebc0a5 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -2,10 +2,14 @@ use core::ptr::write_volatile; use atomic_polyfill::{fence, Ordering}; -use super::{FlashSector, BANK1_REGION, WRITE_SIZE}; +use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} + pub(crate) unsafe fn lock() { #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().modify(|w| w.set_lock(true)); @@ -73,7 +77,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(any(flash_wl, flash_wb, flash_l4))] { - let idx = (sector.start - super::FLASH_BASE as u32) / BANK1_REGION.erase_size as u32; + let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; #[cfg(flash_l4)] let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; @@ -180,13 +184,3 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { } } } - -pub(crate) fn get_sector(address: u32) -> FlashSector { - let sector_size = BANK1_REGION.erase_size; - let index = address / sector_size; - FlashSector { - index: index as u8, - start: BANK1_REGION.base + index * sector_size, - size: sector_size, - } -} diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 110b8149..794d32cc 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -10,6 +10,7 @@ pub use crate::_generated::flash_regions::*; pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; pub struct FlashRegion { + pub bank: FlashBank, pub base: u32, pub size: u32, pub erase_size: u32, @@ -19,15 +20,27 @@ pub struct FlashRegion { #[derive(Debug, PartialEq)] pub struct FlashSector { - pub index: u8, + pub bank: FlashBank, + pub index_in_bank: u8, pub start: u32, pub size: u32, } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FlashBank { + Bank1 = 0, + Bank2 = 1, + Otp, +} + impl FlashRegion { pub const fn end(&self) -> u32 { self.base + self.size } + + pub const fn sectors(&self) -> u8 { + (self.size / self.erase_size) as u8 + } } #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs index fd355122..d329dcab 100644 --- a/embassy-stm32/src/flash/other.rs +++ b/embassy-stm32/src/flash/other.rs @@ -1,5 +1,10 @@ -#[allow(unused)] -use super::{Error, FlashSector, WRITE_SIZE}; +#![allow(unused)] + +use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; + +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} pub(crate) unsafe fn lock() { unimplemented!(); @@ -22,6 +27,3 @@ pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), pub(crate) unsafe fn clear_all_err() { unimplemented!(); } -pub(crate) fn get_sector(_address: u32) -> FlashSector { - unimplemented!(); -} From 760d4a72cbb8d008646e751e70fa212f65f26068 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Thu, 30 Mar 2023 09:05:13 +0200 Subject: [PATCH 31/43] Ensure that embedded_storage traits are actually implemented --- embassy-stm32/src/flash/common.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 31dd1136..47e94f75 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -205,7 +205,7 @@ impl FlashRegion { } foreach_flash_region! { - ($type_name:ident, $write_size:ident, $erase_size:ident) => { + ($type_name:ident, $write_size:literal, $erase_size:literal) => { impl crate::_generated::flash_regions::$type_name { pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { unsafe { self.0.blocking_read_inner(offset, bytes) } @@ -220,11 +220,11 @@ foreach_flash_region! { } } - impl ErrorType for crate::_generated::flash_regions::$type_name { + impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name { type Error = Error; } - impl ReadNorFlash for crate::_generated::flash_regions::$type_name { + impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name { const READ_SIZE: usize = 1; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { @@ -236,7 +236,7 @@ foreach_flash_region! { } } - impl NorFlash for crate::_generated::flash_regions::$type_name { + impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name { const WRITE_SIZE: usize = $write_size; const ERASE_SIZE: usize = $erase_size; From 02caec9482cbd8ce62c17ebc3fcaa13c3f47c1ee Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Thu, 30 Mar 2023 09:07:23 +0200 Subject: [PATCH 32/43] Skip unknown banks --- embassy-stm32/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 00740924..4ca3ef3f 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -113,7 +113,7 @@ fn main() { .collect(); for region in flash_memory_regions.iter() { let region_name = format_ident!("{}", get_flash_region_name(region.name)); - let bank = format_ident!( + let bank_variant = format_ident!( "{}", if region.name.starts_with("BANK_1") { "Bank1" @@ -122,7 +122,7 @@ fn main() { } else if region.name == "OTP" { "Otp" } else { - unimplemented!() + continue; } ); let base = region.address; @@ -134,7 +134,7 @@ fn main() { flash_regions.extend(quote! { pub const #region_name: crate::flash::FlashRegion = crate::flash::FlashRegion { - bank: crate::flash::FlashBank::#bank, + bank: crate::flash::FlashBank::#bank_variant, base: #base, size: #size, erase_size: #erase_size, From a78e10e00362bf0f5649e200fa62c75d6f3808d0 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Thu, 30 Mar 2023 09:17:14 +0200 Subject: [PATCH 33/43] Add defmt support to new flash types --- embassy-stm32/src/flash/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 794d32cc..231ff1f9 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -9,6 +9,8 @@ pub use common::*; pub use crate::_generated::flash_regions::*; pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FlashRegion { pub bank: FlashBank, pub base: u32, @@ -19,6 +21,7 @@ pub struct FlashRegion { } #[derive(Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FlashSector { pub bank: FlashBank, pub index_in_bank: u8, @@ -27,6 +30,7 @@ pub struct FlashSector { } #[derive(Clone, Copy, Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum FlashBank { Bank1 = 0, Bank2 = 1, From f3dcb5eb22dfac21024e77023d1967b4eaa0b176 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Thu, 30 Mar 2023 15:13:44 +0200 Subject: [PATCH 34/43] Wrap write/erase operations in cs --- embassy-stm32/src/flash/common.rs | 209 +++++++++++++----------------- 1 file changed, 91 insertions(+), 118 deletions(-) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 47e94f75..59429e34 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -1,7 +1,5 @@ use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::mutex::{Mutex, MutexGuard}; use super::{family, Error, FlashLayout, FlashRegion, FlashSector, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; use crate::flash::FlashBank; @@ -22,96 +20,21 @@ impl<'d> Flash<'d> { } pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - Self::blocking_read_inner(FLASH_BASE as u32 + offset, bytes) - } - - fn blocking_read_inner(start_address: u32, bytes: &mut [u8]) -> Result<(), Error> { - assert!(start_address >= FLASH_BASE as u32); - if start_address as usize + bytes.len() > FLASH_BASE + FLASH_SIZE { - return Err(Error::Size); - } - - let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) }; - bytes.copy_from_slice(flash_data); - Ok(()) + let start_address = FLASH_BASE as u32 + offset; + blocking_read(start_address, bytes) } pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { let start_address = FLASH_BASE as u32 + offset; - // No need to take lock here as we only have one mut flash reference. - - unsafe { Flash::blocking_write_inner(start_address, buf) } - } - - unsafe fn blocking_write_inner(start_address: u32, buf: &[u8]) -> Result<(), Error> { - assert!(start_address >= FLASH_BASE as u32); - if start_address as usize + buf.len() > FLASH_BASE + FLASH_SIZE { - return Err(Error::Size); - } - if (start_address as usize - FLASH_BASE) % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { - return Err(Error::Unaligned); - } - - trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address); - - family::clear_all_err(); - family::unlock(); - family::begin_write(); - - let _ = OnDrop::new(|| { - family::end_write(); - family::lock(); - }); - - let mut address = start_address; - for chunk in buf.chunks(WRITE_SIZE) { - unsafe { family::blocking_write(address, chunk.try_into().unwrap())? }; - address += WRITE_SIZE as u32; - } - Ok(()) + unsafe { blocking_write(start_address, buf) } } pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { let start_address = FLASH_BASE as u32 + from; let end_address = FLASH_BASE as u32 + to; - unsafe { Flash::blocking_erase_inner(start_address, end_address) } - } - - unsafe fn blocking_erase_inner(start_address: u32, end_address: u32) -> Result<(), Error> { - let regions = family::get_flash_regions(); - - // Test if the address range is aligned at sector base addresses - let mut address = start_address; - while address < end_address { - let sector = get_sector(address, regions); - if sector.start != address { - return Err(Error::Unaligned); - } - address += sector.size; - } - if address != end_address { - return Err(Error::Unaligned); - } - - trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); - - family::clear_all_err(); - family::unlock(); - - let _ = OnDrop::new(|| { - family::lock(); - }); - - let mut address = start_address; - while address < end_address { - let sector = get_sector(address, regions); - trace!("Erasing sector: {}", sector); - family::blocking_erase_sector(§or)?; - address += sector.size; - } - Ok(()) + unsafe { blocking_erase(start_address, end_address) } } pub(crate) fn release(self) -> PeripheralRef<'d, crate::peripherals::FLASH> { @@ -132,14 +55,79 @@ impl Drop for FlashLayout<'_> { } } -static REGION_LOCK: Mutex = Mutex::new(()); - -fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { - loop { - if let Ok(guard) = REGION_LOCK.try_lock() { - return guard; - } +fn blocking_read(start_address: u32, bytes: &mut [u8]) -> Result<(), Error> { + assert!(start_address >= FLASH_BASE as u32); + if start_address as usize + bytes.len() > FLASH_BASE + FLASH_SIZE { + return Err(Error::Size); } + + let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) }; + bytes.copy_from_slice(flash_data); + Ok(()) +} + +unsafe fn blocking_write(start_address: u32, buf: &[u8]) -> Result<(), Error> { + assert!(start_address >= FLASH_BASE as u32); + if start_address as usize + buf.len() > FLASH_BASE + FLASH_SIZE { + return Err(Error::Size); + } + if (start_address as usize - FLASH_BASE) % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { + return Err(Error::Unaligned); + } + + trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address); + + let mut address = start_address; + for chunk in buf.chunks(WRITE_SIZE) { + critical_section::with(|_| { + family::clear_all_err(); + family::unlock(); + family::begin_write(); + let _ = OnDrop::new(|| { + family::end_write(); + family::lock(); + }); + family::blocking_write(address, chunk.try_into().unwrap()) + })?; + address += WRITE_SIZE as u32; + } + Ok(()) +} + +unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { + let regions = family::get_flash_regions(); + + // Test if the address range is aligned at sector base addresses + let mut address = start_address; + while address < end_address { + let sector = get_sector(address, regions); + if sector.start != address { + return Err(Error::Unaligned); + } + address += sector.size; + } + if address != end_address { + return Err(Error::Unaligned); + } + + trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); + + let mut address = start_address; + while address < end_address { + let sector = get_sector(address, regions); + trace!("Erasing sector: {}", sector); + + critical_section::with(|_| { + family::clear_all_err(); + family::unlock(); + let _ = OnDrop::new(|| { + family::lock(); + }); + family::blocking_erase_sector(§or) + })?; + address += sector.size; + } + Ok(()) } pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { @@ -169,38 +157,19 @@ pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector impl FlashRegion { pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - unsafe { self.blocking_read_inner(offset, bytes) } + let start_address = self.base + offset; + blocking_read(start_address, bytes) } pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - unsafe { self.blocking_write_inner(offset, bytes) } + let start_address = self.base + offset; + unsafe { blocking_write(start_address, bytes) } } pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - unsafe { self.blocking_erase_inner(from, to) } - } - - unsafe fn blocking_read_inner(&self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - Flash::blocking_read_inner(self.base + offset, bytes) - } - - unsafe fn blocking_write_inner(&self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - let start_address = self.base + offset; - - // Protect agains simultaneous write/erase to multiple regions. - let _guard = take_lock_spin(); - - Flash::blocking_write_inner(start_address, bytes) - } - - unsafe fn blocking_erase_inner(&self, from: u32, to: u32) -> Result<(), Error> { let start_address = self.base + from; let end_address = self.base + to; - - // Protect agains simultaneous write/erase to multiple regions. - let _guard = take_lock_spin(); - - Flash::blocking_erase_inner(start_address, end_address) + unsafe { blocking_erase(start_address, end_address) } } } @@ -208,15 +177,19 @@ foreach_flash_region! { ($type_name:ident, $write_size:literal, $erase_size:literal) => { impl crate::_generated::flash_regions::$type_name { pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - unsafe { self.0.blocking_read_inner(offset, bytes) } + let start_address = self.0.base + offset; + blocking_read(start_address, bytes) } pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - unsafe { self.0.blocking_write_inner(offset, bytes) } + let start_address = self.0.base + offset; + unsafe { blocking_write(start_address, bytes) } } pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - unsafe { self.0.blocking_erase_inner(from, to) } + let start_address = self.0.base + from; + let end_address = self.0.base + to; + unsafe { blocking_erase(start_address, end_address) } } } @@ -228,7 +201,7 @@ foreach_flash_region! { const READ_SIZE: usize = 1; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - unsafe { self.0.blocking_read_inner(offset, bytes) } + self.blocking_read(offset, bytes) } fn capacity(&self) -> usize { @@ -241,11 +214,11 @@ foreach_flash_region! { const ERASE_SIZE: usize = $erase_size; fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - unsafe { self.0.blocking_write_inner(offset, bytes) } + self.blocking_write(offset, bytes) } fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - unsafe { self.0.blocking_erase_inner(from, to) } + self.blocking_erase(from, to) } } }; From 50b0fb1a376dbc650db785228b181cc3939ac87f Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Fri, 31 Mar 2023 15:47:45 +0200 Subject: [PATCH 35/43] Let get_flash_regions be public --- embassy-stm32/src/flash/f3.rs | 2 +- embassy-stm32/src/flash/f4.rs | 4 ++-- embassy-stm32/src/flash/f7.rs | 2 +- embassy-stm32/src/flash/h7.rs | 2 +- embassy-stm32/src/flash/l.rs | 2 +- embassy-stm32/src/flash/other.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index c1ed33f9..10a09c42 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -7,7 +7,7 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 61ac8afd..2f5b417c 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -91,7 +91,7 @@ mod alt_regions { pub use alt_regions::{AltFlashLayout, ALT_FLASH_REGIONS}; #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] -pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub fn get_flash_regions() -> &'static [&'static FlashRegion] { if unsafe { pac::FLASH.optcr().read().db1m() } { &ALT_FLASH_REGIONS } else { @@ -100,7 +100,7 @@ pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { } #[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))] -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 7111f5cc..6427d5a0 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -6,7 +6,7 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 5ea57ccd..4f38d50c 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -11,7 +11,7 @@ const fn is_dual_bank() -> bool { FLASH_REGIONS.len() == 2 } -pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index f5ebc0a5..7d9cc6ea 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -6,7 +6,7 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs index d329dcab..c151cb82 100644 --- a/embassy-stm32/src/flash/other.rs +++ b/embassy-stm32/src/flash/other.rs @@ -2,7 +2,7 @@ use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } From 268e29b153c9c8a6e3a798a01757669ee31e5409 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 1 Apr 2023 16:59:21 +0200 Subject: [PATCH 36/43] Let the FlashRegion for region types be public --- embassy-stm32/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 4ca3ef3f..67b081fe 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -145,7 +145,7 @@ fn main() { let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); flash_regions.extend(quote! { - pub struct #region_type(pub(crate) &'static crate::flash::FlashRegion); + pub struct #region_type(pub &'static crate::flash::FlashRegion); }); } From e11eebfa577b143b8a19fcf6d9d5398c3058c3eb Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 1 Apr 2023 17:26:32 +0200 Subject: [PATCH 37/43] Ensure that ranges are validated with the region size --- embassy-stm32/src/flash/common.rs | 57 ++++++++++++------------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 59429e34..287c54f5 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -20,21 +20,15 @@ impl<'d> Flash<'d> { } pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - let start_address = FLASH_BASE as u32 + offset; - blocking_read(start_address, bytes) + blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) } - pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { - let start_address = FLASH_BASE as u32 + offset; - - unsafe { blocking_write(start_address, buf) } + pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { + unsafe { blocking_write(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) } } pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let start_address = FLASH_BASE as u32 + from; - let end_address = FLASH_BASE as u32 + to; - - unsafe { blocking_erase(start_address, end_address) } + unsafe { blocking_erase(FLASH_BASE as u32, from, to) } } pub(crate) fn release(self) -> PeripheralRef<'d, crate::peripherals::FLASH> { @@ -55,30 +49,29 @@ impl Drop for FlashLayout<'_> { } } -fn blocking_read(start_address: u32, bytes: &mut [u8]) -> Result<(), Error> { - assert!(start_address >= FLASH_BASE as u32); - if start_address as usize + bytes.len() > FLASH_BASE + FLASH_SIZE { +fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + if offset + bytes.len() as u32 > size { return Err(Error::Size); } + let start_address = base + offset; let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) }; bytes.copy_from_slice(flash_data); Ok(()) } -unsafe fn blocking_write(start_address: u32, buf: &[u8]) -> Result<(), Error> { - assert!(start_address >= FLASH_BASE as u32); - if start_address as usize + buf.len() > FLASH_BASE + FLASH_SIZE { +unsafe fn blocking_write(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { + if offset + bytes.len() as u32 > size { return Err(Error::Size); } - if (start_address as usize - FLASH_BASE) % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { + if offset % WRITE_SIZE as u32 != 0 || bytes.len() % WRITE_SIZE != 0 { return Err(Error::Unaligned); } - trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address); + let mut address = base + offset; + trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); - let mut address = start_address; - for chunk in buf.chunks(WRITE_SIZE) { + for chunk in bytes.chunks(WRITE_SIZE) { critical_section::with(|_| { family::clear_all_err(); family::unlock(); @@ -94,7 +87,9 @@ unsafe fn blocking_write(start_address: u32, buf: &[u8]) -> Result<(), Error> { Ok(()) } -unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { +unsafe fn blocking_erase(base: u32, from: u32, to: u32) -> Result<(), Error> { + let start_address = base + from; + let end_address = base + to; let regions = family::get_flash_regions(); // Test if the address range is aligned at sector base addresses @@ -157,19 +152,15 @@ pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector impl FlashRegion { pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - let start_address = self.base + offset; - blocking_read(start_address, bytes) + blocking_read(self.base, self.size, offset, bytes) } pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - let start_address = self.base + offset; - unsafe { blocking_write(start_address, bytes) } + unsafe { blocking_write(self.base, self.size, offset, bytes) } } pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let start_address = self.base + from; - let end_address = self.base + to; - unsafe { blocking_erase(start_address, end_address) } + unsafe { blocking_erase(self.base, from, to) } } } @@ -177,19 +168,15 @@ foreach_flash_region! { ($type_name:ident, $write_size:literal, $erase_size:literal) => { impl crate::_generated::flash_regions::$type_name { pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - let start_address = self.0.base + offset; - blocking_read(start_address, bytes) + blocking_read(self.0.base, self.0.size, offset, bytes) } pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - let start_address = self.0.base + offset; - unsafe { blocking_write(start_address, bytes) } + unsafe { blocking_write(self.0.base, self.0.size, offset, bytes) } } pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let start_address = self.0.base + from; - let end_address = self.0.base + to; - unsafe { blocking_erase(start_address, end_address) } + unsafe { blocking_erase(self.0.base, from, to) } } } From dd88775871d2946df6e7e06bf2b536e94973dbaa Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 1 Apr 2023 18:10:20 +0200 Subject: [PATCH 38/43] Ensure that flash locking is defered to after write --- embassy-stm32/src/flash/common.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 287c54f5..41c28c56 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -1,3 +1,4 @@ +use atomic_polyfill::{fence, Ordering}; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; @@ -74,12 +75,18 @@ unsafe fn blocking_write(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Res for chunk in bytes.chunks(WRITE_SIZE) { critical_section::with(|_| { family::clear_all_err(); + fence(Ordering::SeqCst); family::unlock(); + fence(Ordering::SeqCst); family::begin_write(); - let _ = OnDrop::new(|| { + fence(Ordering::SeqCst); + + let _on_drop = OnDrop::new(|| { family::end_write(); + fence(Ordering::SeqCst); family::lock(); }); + family::blocking_write(address, chunk.try_into().unwrap()) })?; address += WRITE_SIZE as u32; @@ -114,10 +121,14 @@ unsafe fn blocking_erase(base: u32, from: u32, to: u32) -> Result<(), Error> { critical_section::with(|_| { family::clear_all_err(); + fence(Ordering::SeqCst); family::unlock(); - let _ = OnDrop::new(|| { + fence(Ordering::SeqCst); + + let _on_drop = OnDrop::new(|| { family::lock(); }); + family::blocking_erase_sector(§or) })?; address += sector.size; From 94890e544e07eabbc806dd5c05419e4336b5bf32 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 3 Apr 2023 02:01:06 +0200 Subject: [PATCH 39/43] Update stm32-metapac. --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4f660187..504caacb 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -60,7 +60,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = "2" +stm32-metapac = "3" vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { version = "2", default-features = false, features = ["metadata"]} +stm32-metapac = { version = "3", default-features = false, features = ["metadata"]} [features] default = ["stm32-metapac/rt"] From bfebf7a43648e06b313234a2ddc7496eb526bc69 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Mon, 3 Apr 2023 08:02:43 +0200 Subject: [PATCH 40/43] Fix formatting of sector erase log --- embassy-stm32/src/flash/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 41c28c56..c48b2f2e 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -117,7 +117,7 @@ unsafe fn blocking_erase(base: u32, from: u32, to: u32) -> Result<(), Error> { let mut address = start_address; while address < end_address { let sector = get_sector(address, regions); - trace!("Erasing sector: {}", sector); + trace!("Erasing sector: {:?}", sector); critical_section::with(|_| { family::clear_all_err(); From 95b31cf2db647b8d1779cc3f7439d5c7df98f379 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 5 Apr 2023 10:27:13 +0200 Subject: [PATCH 41/43] Remove Drop on Flash and FlashLayout and propage lifetime to region types This allows the user to "split" the FlashRegions struct into each region --- embassy-stm32/build.rs | 11 ++++---- embassy-stm32/src/flash/common.rs | 20 +++------------ embassy-stm32/src/flash/f4.rs | 42 ++++++++++++++++--------------- 3 files changed, 31 insertions(+), 42 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 9df5a58d..61aceed9 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -148,7 +148,8 @@ fn main() { let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); flash_regions.extend(quote! { - pub struct #region_type(pub &'static crate::flash::FlashRegion); + #[cfg(flash)] + pub struct #region_type<'d>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>,); }); } @@ -159,11 +160,11 @@ fn main() { let field_name = format_ident!("{}", region_name.to_lowercase()); let field_type = format_ident!("{}", get_flash_region_type_name(f.name)); let field = quote! { - pub #field_name: #field_type + pub #field_name: #field_type<'d> }; let region_name = format_ident!("{}", region_name); let init = quote! { - #field_name: #field_type(&#region_name) + #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()}) }; (field, (init, region_name)) @@ -174,15 +175,13 @@ fn main() { flash_regions.extend(quote! { #[cfg(flash)] pub struct FlashLayout<'d> { - _inner: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, #(#fields),* } #[cfg(flash)] impl<'d> FlashLayout<'d> { - pub(crate) const fn new(p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self { + pub(crate) fn new(mut p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self { Self { - _inner: p, #(#inits),* } } diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index c48b2f2e..8235d6f0 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -38,18 +38,6 @@ impl<'d> Flash<'d> { } } -impl Drop for Flash<'_> { - fn drop(&mut self) { - unsafe { family::lock() }; - } -} - -impl Drop for FlashLayout<'_> { - fn drop(&mut self) { - unsafe { family::lock() }; - } -} - fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { if offset + bytes.len() as u32 > size { return Err(Error::Size); @@ -177,7 +165,7 @@ impl FlashRegion { foreach_flash_region! { ($type_name:ident, $write_size:literal, $erase_size:literal) => { - impl crate::_generated::flash_regions::$type_name { + impl crate::_generated::flash_regions::$type_name<'_> { pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { blocking_read(self.0.base, self.0.size, offset, bytes) } @@ -191,11 +179,11 @@ foreach_flash_region! { } } - impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name { + impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_> { type Error = Error; } - impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name { + impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { const READ_SIZE: usize = 1; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { @@ -207,7 +195,7 @@ foreach_flash_region! { } } - impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name { + impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> { const WRITE_SIZE: usize = $write_size; const ERASE_SIZE: usize = $erase_size; diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 2f5b417c..2ce9df69 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -45,34 +45,36 @@ mod alt_regions { &ALT_BANK2_REGION3, ]; - pub type AltBank1Region1 = Bank1Region1; - pub type AltBank1Region2 = Bank1Region2; - pub struct AltBank1Region3(&'static FlashRegion); - pub struct AltBank2Region1(&'static FlashRegion); - pub struct AltBank2Region2(&'static FlashRegion); - pub struct AltBank2Region3(&'static FlashRegion); + pub type AltBank1Region1<'d> = Bank1Region1<'d>; + pub type AltBank1Region2<'d> = Bank1Region2<'d>; + pub struct AltBank1Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); + pub struct AltBank2Region1<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); + pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); + pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); pub struct AltFlashLayout<'d> { - _inner: PeripheralRef<'d, FLASH>, - pub bank1_region1: AltBank1Region1, - pub bank1_region2: AltBank1Region2, - pub bank1_region3: AltBank1Region3, - pub bank2_region1: AltBank2Region1, - pub bank2_region2: AltBank2Region2, - pub bank2_region3: AltBank2Region3, + pub bank1_region1: AltBank1Region1<'d>, + pub bank1_region2: AltBank1Region2<'d>, + pub bank1_region3: AltBank1Region3<'d>, + pub bank2_region1: AltBank2Region1<'d>, + pub bank2_region2: AltBank2Region2<'d>, + pub bank2_region3: AltBank2Region3<'d>, } impl<'d> Flash<'d> { pub fn into_alt_regions(self) -> AltFlashLayout<'d> { unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) }; + + // SAFETY: We never expose the cloned peripheral references, and their instance is not public. + // Also, all flash region operations are protected with a cs. + let mut p = self.release(); AltFlashLayout { - _inner: self.release(), - bank1_region1: Bank1Region1(&BANK1_REGION1), - bank1_region2: Bank1Region2(&BANK1_REGION2), - bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3), - bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1), - bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2), - bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3), + bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }), + bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }), + bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }), + bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }), + bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }), + bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }), } } } From 57d3d4d58148fefbd6db4770918b52f31ded0124 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 5 Apr 2023 10:29:45 +0200 Subject: [PATCH 42/43] Align stm32 bootloader example --- examples/boot/bootloader/stm32/src/main.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs index b8027d19..49c21920 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}; #[cfg(feature = "defmt")] use defmt_rtt as _; use embassy_boot_stm32::*; -use embassy_stm32::flash::{Flash, ERASE_SIZE}; +use embassy_stm32::flash::Flash; #[entry] fn main() -> ! { @@ -19,9 +19,10 @@ fn main() -> ! { } */ - let mut bl: BootLoader = BootLoader::default(); + let mut bl: BootLoader<2048> = BootLoader::default(); let flash = Flash::new(p.FLASH); - let mut flash = BootFlash::new(flash); + let layout = flash.into_regions(); + let mut flash = BootFlash::new(layout.bank1_region); let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash)); core::mem::drop(flash); unsafe { bl.load(start) } From 2a49e11cb0ffd3e0d9a0cc94444f293de523b47f Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 5 Apr 2023 10:55:31 +0200 Subject: [PATCH 43/43] Align flash examples --- examples/stm32f3/src/bin/flash.rs | 2 +- examples/stm32f4/src/bin/flash.rs | 13 +++++++------ examples/stm32f7/src/bin/flash.rs | 4 ++-- examples/stm32h7/src/bin/flash.rs | 4 ++-- examples/stm32l0/src/bin/flash.rs | 2 +- examples/stm32l1/src/bin/flash.rs | 2 +- examples/stm32wl/src/bin/flash.rs | 2 +- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs index baa7484d..e40ad4fc 100644 --- a/examples/stm32f3/src/bin/flash.rs +++ b/examples/stm32f3/src/bin/flash.rs @@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH); + let mut f = Flash::new(p.FLASH).into_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs index 7ea068a4..bd3a7c95 100644 --- a/examples/stm32f4/src/bin/flash.rs +++ b/examples/stm32f4/src/bin/flash.rs @@ -5,7 +5,6 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_stm32::flash::Flash; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -13,6 +12,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello Flash!"); + // Once can also call `into_regions()` to get access to NorFlash implementations + // for each of the unique characteristics. let mut f = Flash::new(p.FLASH); // Sector 5 @@ -30,19 +31,19 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(offset, offset + size)); + unwrap!(f.blocking_erase(offset, offset + size)); info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.write( + unwrap!(f.blocking_write( offset, &[ 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) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!( &buf[..], diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs index 4a7bca1f..aabfe855 100644 --- a/examples/stm32f7/src/bin/flash.rs +++ b/examples/stm32f7/src/bin/flash.rs @@ -14,12 +14,12 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello Flash!"); - const ADDR: u32 = 0x8_0000; + const ADDR: u32 = 0x8_0000; // This is the offset into the third region, the absolute address is 4x32K + 128K + 0x8_0000. // wait a bit before accessing the flash Timer::after(Duration::from_millis(300)).await; - let mut f = Flash::new(p.FLASH); + let mut f = Flash::new(p.FLASH).into_regions().bank1_region3; info!("Reading..."); let mut buf = [0u8; 32]; diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs index ee86bdbf..7ee9838c 100644 --- a/examples/stm32h7/src/bin/flash.rs +++ b/examples/stm32h7/src/bin/flash.rs @@ -14,12 +14,12 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello Flash!"); - const ADDR: u32 = 0x08_0000; + const ADDR: u32 = 0; // This is the offset into bank 2, the absolute address is 0x8_0000 // wait a bit before accessing the flash Timer::after(Duration::from_millis(300)).await; - let mut f = Flash::new(p.FLASH); + let mut f = Flash::new(p.FLASH).into_regions().bank2_region; info!("Reading..."); let mut buf = [0u8; 32]; diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs index ffe4fb10..33742502 100644 --- a/examples/stm32l0/src/bin/flash.rs +++ b/examples/stm32l0/src/bin/flash.rs @@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH); + let mut f = Flash::new(p.FLASH).into_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs index 476ed51a..38feb0d7 100644 --- a/examples/stm32l1/src/bin/flash.rs +++ b/examples/stm32l1/src/bin/flash.rs @@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH); + let mut f = Flash::new(p.FLASH).into_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs index 2a888062..e6bc2865 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x36000; - let mut f = Flash::new(p.FLASH); + let mut f = Flash::new(p.FLASH).into_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8];