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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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/78] 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 8aaffe82e71dfb2b3845c95bbf59ef4a34c7096c Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Mon, 3 Apr 2023 14:59:55 +0200 Subject: [PATCH 41/78] Add incremental hash to FirmwareUpdater This adds support for computing any hash over the update in the dtu area by providing a closure to the hash update function. --- embassy-boot/boot/src/firmware_updater.rs | 67 ++++++++++++++--------- embassy-boot/boot/src/lib.rs | 2 +- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs index af1ba114..90157036 100644 --- a/embassy-boot/boot/src/firmware_updater.rs +++ b/embassy-boot/boot/src/firmware_updater.rs @@ -118,13 +118,13 @@ impl FirmwareUpdater { _state_and_dfu_flash: &mut F, _public_key: &[u8], _signature: &[u8], - _update_len: usize, + _update_len: u32, _aligned: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { let _read_size = _aligned.len(); assert_eq!(_aligned.len(), F::WRITE_SIZE); - assert!(_update_len <= self.dfu.len()); + assert!(_update_len <= self.dfu.len() as u32); #[cfg(feature = "ed25519-dalek")] { @@ -136,11 +136,8 @@ impl FirmwareUpdater { let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; let mut digest = Sha512::new(); - for offset in (0.._update_len).step_by(_aligned.len()) { - self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; - let len = core::cmp::min(_update_len - offset, _aligned.len()); - digest.update(&_aligned[..len]); - } + self.incremental_hash(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x)) + .await?; public_key .verify(&digest.finalize(), &signature) @@ -161,11 +158,8 @@ impl FirmwareUpdater { let signature = Signature::try_from(&signature).map_err(into_signature_error)?; let mut digest = Sha512::new(); - for offset in (0.._update_len).step_by(_aligned.len()) { - self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; - let len = core::cmp::min(_update_len - offset, _aligned.len()); - digest.update(&_aligned[..len]); - } + self.incremental_hash(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x)) + .await?; let message = digest.finalize(); let r = public_key.verify(&message, &signature); @@ -182,6 +176,22 @@ impl FirmwareUpdater { self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await } + /// Iterate through the DFU and process all bytes with the provided closure. + pub async fn incremental_hash( + &mut self, + dfu_flash: &mut F, + update_len: u32, + aligned: &mut [u8], + mut update: impl FnMut(&[u8]), + ) -> Result<(), FirmwareUpdaterError> { + for offset in (0..update_len).step_by(aligned.len()) { + self.dfu.read(dfu_flash, offset, aligned).await?; + let len = core::cmp::min((update_len - offset) as usize, aligned.len()); + update(&aligned[..len]); + } + Ok(()) + } + /// Mark to trigger firmware swap on next boot. /// /// # Safety @@ -317,14 +327,13 @@ impl FirmwareUpdater { _state_and_dfu_flash: &mut F, _public_key: &[u8], _signature: &[u8], - _update_len: usize, + _update_len: u32, _aligned: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { - let _end = self.dfu.from + _update_len; let _read_size = _aligned.len(); assert_eq!(_aligned.len(), F::WRITE_SIZE); - assert!(_end <= self.dfu.to); + assert!(_update_len <= self.dfu.len() as u32); #[cfg(feature = "ed25519-dalek")] { @@ -336,11 +345,7 @@ impl FirmwareUpdater { let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; let mut digest = Sha512::new(); - for offset in (0.._update_len).step_by(_aligned.len()) { - self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?; - let len = core::cmp::min(_update_len - offset, _aligned.len()); - digest.update(&_aligned[..len]); - } + self.incremental_hash_blocking(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x))?; public_key .verify(&digest.finalize(), &signature) @@ -361,11 +366,7 @@ impl FirmwareUpdater { let signature = Signature::try_from(&signature).map_err(into_signature_error)?; let mut digest = Sha512::new(); - for offset in (0.._update_len).step_by(_aligned.len()) { - self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?; - let len = core::cmp::min(_update_len - offset, _aligned.len()); - digest.update(&_aligned[..len]); - } + self.incremental_hash_blocking(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x))?; let message = digest.finalize(); let r = public_key.verify(&message, &signature); @@ -382,6 +383,22 @@ impl FirmwareUpdater { self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) } + /// Iterate through the DFU and process all bytes with the provided closure. + pub fn incremental_hash_blocking( + &mut self, + dfu_flash: &mut F, + update_len: u32, + aligned: &mut [u8], + mut update: impl FnMut(&[u8]), + ) -> Result<(), FirmwareUpdaterError> { + for offset in (0..update_len).step_by(aligned.len()) { + self.dfu.read_blocking(dfu_flash, offset, aligned)?; + let len = core::cmp::min((update_len - offset) as usize, aligned.len()); + update(&aligned[..len]); + } + Ok(()) + } + /// Mark to trigger firmware swap on next boot. /// /// # Safety diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 4c28d7aa..6d0e2d8c 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs @@ -308,7 +308,7 @@ mod tests { &mut flash, &public_key.to_bytes(), &signature.to_bytes(), - firmware_len, + firmware_len as u32, &mut aligned, )) .is_ok()); From 7c6936a2e398e43ea3dc89736dc385402822933f Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Tue, 4 Apr 2023 12:24:30 +0200 Subject: [PATCH 42/78] Let hash functions take a digest::Digest trait ... and add adapters for current Sha512 implementations that does not inplement the Digest trait --- embassy-boot/boot/Cargo.toml | 4 +- .../boot/src/digest_adapters/ed25519_dalek.rs | 30 +++++ embassy-boot/boot/src/digest_adapters/mod.rs | 5 + .../boot/src/digest_adapters/salty.rs | 29 +++++ embassy-boot/boot/src/firmware_updater.rs | 108 ++++++++++++------ embassy-boot/boot/src/lib.rs | 1 + 6 files changed, 140 insertions(+), 37 deletions(-) create mode 100644 embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs create mode 100644 embassy-boot/boot/src/digest_adapters/mod.rs create mode 100644 embassy-boot/boot/src/digest_adapters/salty.rs diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml index 3312c2f9..c4ebdaff 100644 --- a/embassy-boot/boot/Cargo.toml +++ b/embassy-boot/boot/Cargo.toml @@ -24,6 +24,7 @@ features = ["defmt"] [dependencies] defmt = { version = "0.3", optional = true } +digest = "0.10" log = { version = "0.4", optional = true } ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true } embassy-sync = { version = "0.1.0", path = "../../embassy-sync" } @@ -37,6 +38,7 @@ log = "0.4" env_logger = "0.9" rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version futures = { version = "0.3", features = ["executor"] } +sha1 = "0.10.5" [dev-dependencies.ed25519-dalek] default_features = false @@ -47,4 +49,4 @@ ed25519-dalek = ["dep:ed25519-dalek", "_verify"] ed25519-salty = ["dep:salty", "_verify"] #Internal features -_verify = [] \ No newline at end of file +_verify = [] diff --git a/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs b/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs new file mode 100644 index 00000000..a184d1c5 --- /dev/null +++ b/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs @@ -0,0 +1,30 @@ +use digest::typenum::U64; +use digest::{FixedOutput, HashMarker, OutputSizeUser, Update}; +use ed25519_dalek::Digest as _; + +pub struct Sha512(ed25519_dalek::Sha512); + +impl Default for Sha512 { + fn default() -> Self { + Self(ed25519_dalek::Sha512::new()) + } +} + +impl Update for Sha512 { + fn update(&mut self, data: &[u8]) { + self.0.update(data) + } +} + +impl FixedOutput for Sha512 { + fn finalize_into(self, out: &mut digest::Output) { + let result = self.0.finalize(); + out.as_mut_slice().copy_from_slice(result.as_slice()) + } +} + +impl OutputSizeUser for Sha512 { + type OutputSize = U64; +} + +impl HashMarker for Sha512 {} diff --git a/embassy-boot/boot/src/digest_adapters/mod.rs b/embassy-boot/boot/src/digest_adapters/mod.rs new file mode 100644 index 00000000..9b4b4b60 --- /dev/null +++ b/embassy-boot/boot/src/digest_adapters/mod.rs @@ -0,0 +1,5 @@ +#[cfg(feature = "ed25519-dalek")] +pub(crate) mod ed25519_dalek; + +#[cfg(feature = "ed25519-salty")] +pub(crate) mod salty; diff --git a/embassy-boot/boot/src/digest_adapters/salty.rs b/embassy-boot/boot/src/digest_adapters/salty.rs new file mode 100644 index 00000000..2b5dcf3a --- /dev/null +++ b/embassy-boot/boot/src/digest_adapters/salty.rs @@ -0,0 +1,29 @@ +use digest::typenum::U64; +use digest::{FixedOutput, HashMarker, OutputSizeUser, Update}; + +pub struct Sha512(salty::Sha512); + +impl Default for Sha512 { + fn default() -> Self { + Self(salty::Sha512::new()) + } +} + +impl Update for Sha512 { + fn update(&mut self, data: &[u8]) { + self.0.update(data) + } +} + +impl FixedOutput for Sha512 { + fn finalize_into(self, out: &mut digest::Output) { + let result = self.0.finalize(); + out.as_mut_slice().copy_from_slice(result.as_slice()) + } +} + +impl OutputSizeUser for Sha512 { + type OutputSize = U64; +} + +impl HashMarker for Sha512 {} diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs index 22e3e6b0..2d1b2698 100644 --- a/embassy-boot/boot/src/firmware_updater.rs +++ b/embassy-boot/boot/src/firmware_updater.rs @@ -1,3 +1,4 @@ +use digest::Digest; use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash; @@ -128,25 +129,27 @@ impl FirmwareUpdater { #[cfg(feature = "ed25519-dalek")] { - use ed25519_dalek::{Digest, PublicKey, Sha512, Signature, SignatureError, Verifier}; + use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; + + use crate::digest_adapters::ed25519_dalek::Sha512; let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; - let mut digest = Sha512::new(); - self.incremental_hash(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x)) + let mut message = [0; 64]; + self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message) .await?; - public_key - .verify(&digest.finalize(), &signature) - .map_err(into_signature_error)? + public_key.verify(&message, &signature).map_err(into_signature_error)? } #[cfg(feature = "ed25519-salty")] { use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; - use salty::{PublicKey, Sha512, Signature}; + use salty::{PublicKey, Signature}; + + use crate::digest_adapters::salty::Sha512; fn into_signature_error(_: E) -> FirmwareUpdaterError { FirmwareUpdaterError::Signature(signature::Error::default()) @@ -157,11 +160,10 @@ impl FirmwareUpdater { let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; let signature = Signature::try_from(&signature).map_err(into_signature_error)?; - let mut digest = Sha512::new(); - self.incremental_hash(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x)) + let mut message = [0; 64]; + self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message) .await?; - let message = digest.finalize(); let r = public_key.verify(&message, &signature); trace!( "Verifying with public key {}, signature {} and message {} yields ok: {}", @@ -176,19 +178,21 @@ impl FirmwareUpdater { self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await } - /// Iterate through the DFU and process all bytes with the provided closure. - pub async fn incremental_hash( + /// Verify the update in DFU with any digest. + pub async fn hash( &mut self, dfu_flash: &mut F, update_len: u32, - aligned: &mut [u8], - mut update: impl FnMut(&[u8]), + chunk_buf: &mut [u8], + output: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { - for offset in (0..update_len).step_by(aligned.len()) { - self.dfu.read(dfu_flash, offset, aligned).await?; - let len = core::cmp::min((update_len - offset) as usize, aligned.len()); - update(&aligned[..len]); + let mut digest = D::new(); + for offset in (0..update_len).step_by(chunk_buf.len()) { + self.dfu.read(dfu_flash, offset, chunk_buf).await?; + let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len()); + digest.update(&chunk_buf[..len]); } + output.copy_from_slice(digest.finalize().as_slice()); Ok(()) } @@ -334,24 +338,26 @@ impl FirmwareUpdater { #[cfg(feature = "ed25519-dalek")] { - use ed25519_dalek::{Digest, PublicKey, Sha512, Signature, SignatureError, Verifier}; + use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; + + use crate::digest_adapters::ed25519_dalek::Sha512; let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; - let mut digest = Sha512::new(); - self.incremental_hash_blocking(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x))?; + let mut message = [0; 64]; + self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?; - public_key - .verify(&digest.finalize(), &signature) - .map_err(into_signature_error)? + public_key.verify(&message, &signature).map_err(into_signature_error)? } #[cfg(feature = "ed25519-salty")] { use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; - use salty::{PublicKey, Sha512, Signature}; + use salty::{PublicKey, Signature}; + + use crate::digest_adapters::salty::Sha512; fn into_signature_error(_: E) -> FirmwareUpdaterError { FirmwareUpdaterError::Signature(signature::Error::default()) @@ -362,10 +368,9 @@ impl FirmwareUpdater { let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; let signature = Signature::try_from(&signature).map_err(into_signature_error)?; - let mut digest = Sha512::new(); - self.incremental_hash_blocking(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x))?; + let mut message = [0; 64]; + self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?; - let message = digest.finalize(); let r = public_key.verify(&message, &signature); trace!( "Verifying with public key {}, signature {} and message {} yields ok: {}", @@ -380,19 +385,21 @@ impl FirmwareUpdater { self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) } - /// Iterate through the DFU and process all bytes with the provided closure. - pub fn incremental_hash_blocking( + /// Verify the update in DFU with any digest. + pub fn hash_blocking( &mut self, dfu_flash: &mut F, update_len: u32, - aligned: &mut [u8], - mut update: impl FnMut(&[u8]), + chunk_buf: &mut [u8], + output: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { - for offset in (0..update_len).step_by(aligned.len()) { - self.dfu.read_blocking(dfu_flash, offset, aligned)?; - let len = core::cmp::min((update_len - offset) as usize, aligned.len()); - update(&aligned[..len]); + let mut digest = D::new(); + for offset in (0..update_len).step_by(chunk_buf.len()) { + self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?; + let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len()); + digest.update(&chunk_buf[..len]); } + output.copy_from_slice(digest.finalize().as_slice()); Ok(()) } @@ -479,3 +486,32 @@ impl FirmwareUpdater { Ok(self.dfu) } } + +#[cfg(test)] +mod tests { + use futures::executor::block_on; + use sha1::{Digest, Sha1}; + + use super::*; + use crate::tests::MemFlash; + + #[test] + fn can_verify() { + const STATE: Partition = Partition::new(0, 4096); + const DFU: Partition = Partition::new(65536, 131072); + + let mut flash = MemFlash::<131072, 4096, 8>([0xFF; 131072]); + + let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; + let mut to_write = [0; 4096]; + to_write[..7].copy_from_slice(update.as_slice()); + + let mut updater = FirmwareUpdater::new(DFU, STATE); + block_on(updater.write_firmware(0, to_write.as_slice(), &mut flash)).unwrap(); + let mut chunk_buf = [0; 2]; + let mut hash = [0; 20]; + block_on(updater.hash::<_, Sha1>(&mut flash, update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); + + assert_eq!(Sha1::digest(update).as_slice(), hash); + } +} diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 6888a805..da905547 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs @@ -6,6 +6,7 @@ mod fmt; mod boot_loader; +mod digest_adapters; mod firmware_updater; mod partition; From 8256ac104405400a15aa9a6a2d9afe38a552a98b Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Tue, 4 Apr 2023 19:07:45 +0200 Subject: [PATCH 43/78] Use MemFlash::default() in sha1 verify test --- embassy-boot/boot/src/firmware_updater.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs index 819e2020..fffb9a50 100644 --- a/embassy-boot/boot/src/firmware_updater.rs +++ b/embassy-boot/boot/src/firmware_updater.rs @@ -519,14 +519,14 @@ mod tests { use sha1::{Digest, Sha1}; use super::*; - use crate::tests::MemFlash; + use crate::mem_flash::MemFlash; #[test] - fn can_verify() { + fn can_verify_sha1() { const STATE: Partition = Partition::new(0, 4096); const DFU: Partition = Partition::new(65536, 131072); - let mut flash = MemFlash::<131072, 4096, 8>([0xFF; 131072]); + let mut flash = MemFlash::<131072, 4096, 8>::default(); let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; let mut to_write = [0; 4096]; From 991b22b6a1e845dc15eca72bf9881e60f1803840 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 4 Apr 2023 19:35:25 -0500 Subject: [PATCH 44/78] stm32/pwm: add complementary pwm --- embassy-stm32/src/pwm/complementary_pwm.rs | 145 +++++++++++++++++++++ embassy-stm32/src/pwm/mod.rs | 22 ++++ 2 files changed, 167 insertions(+) create mode 100644 embassy-stm32/src/pwm/complementary_pwm.rs diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs new file mode 100644 index 00000000..b8761724 --- /dev/null +++ b/embassy-stm32/src/pwm/complementary_pwm.rs @@ -0,0 +1,145 @@ +use core::marker::PhantomData; + +use embassy_hal_common::{into_ref, PeripheralRef}; + +use super::*; +#[allow(unused_imports)] +use crate::gpio::sealed::{AFType, Pin}; +use crate::gpio::AnyPin; +use crate::time::Hertz; +use crate::Peripheral; + +pub struct Ch1; +pub struct Ch2; +pub struct Ch3; +pub struct Ch4; + +pub struct PwmPin<'d, Perip, Channel> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(Perip, Channel)>, +} + +pub struct ComplementaryPwmPin<'d, Perip, Channel> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(Perip, Channel)>, +} + +macro_rules! channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => { + impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| unsafe { + pin.set_low(); + pin.set_as_af(pin.af_num(), AFType::OutputPushPull); + #[cfg(gpio_v2)] + pin.set_speed(crate::gpio::Speed::VeryHigh); + }); + PwmPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } + } + + impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| unsafe { + pin.set_low(); + pin.set_as_af(pin.af_num(), AFType::OutputPushPull); + #[cfg(gpio_v2)] + pin.set_speed(crate::gpio::Speed::VeryHigh); + }); + ComplementaryPwmPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } + } + }; +} + +channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin); +channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin); +channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin); +channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin); + +pub struct ComplementaryPwm<'d, T> { + inner: PeripheralRef<'d, T>, +} + +impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { + pub fn new( + tim: impl Peripheral

+ 'd, + _ch1: Option>, + _ch1n: Option>, + _ch2: Option>, + _ch2n: Option>, + _ch3: Option>, + _ch3n: Option>, + _ch4: Option>, + _ch4n: Option>, + freq: Hertz, + ) -> Self { + Self::new_inner(tim, freq) + } + + fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz) -> Self { + into_ref!(tim); + + T::enable(); + ::reset(); + + let mut this = Self { inner: tim }; + + this.inner.set_frequency(freq); + this.inner.start(); + + unsafe { + this.inner.enable_outputs(true); + + this.inner + .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); + this.inner + .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); + this.inner + .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); + this.inner + .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); + } + this + } + + pub fn enable(&mut self, channel: Channel) { + unsafe { + self.inner.enable_channel(channel, true); + } + } + + pub fn disable(&mut self, channel: Channel) { + unsafe { + self.inner.enable_channel(channel, false); + } + } + + pub fn set_freq(&mut self, freq: Hertz) { + self.inner.set_frequency(freq); + } + + pub fn get_max_duty(&self) -> u16 { + unsafe { self.inner.get_max_compare_value() } + } + + pub fn set_duty(&mut self, channel: Channel, duty: u16) { + assert!(duty < self.get_max_duty()); + unsafe { self.inner.set_compare_value(channel, duty) } + } + + /* + set the value of the dead-time register + */ + pub fn set_dead_time_value(&mut self, value: u8) { + unsafe { self.inner.set_dead_time_value(value) } + } +} diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index d3713391..6f3c1266 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -1,3 +1,4 @@ +pub mod complementary_pwm; pub mod simple_pwm; #[cfg(feature = "unstable-pac")] @@ -67,6 +68,10 @@ pub(crate) mod sealed { unsafe fn get_max_compare_value(&self) -> u16; } + pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { + unsafe fn set_dead_time_value(&mut self, value: u8); + } + pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); @@ -82,6 +87,12 @@ pub trait CaptureCompare16bitInstance: sealed::CaptureCompare16bitInstance + crate::timer::GeneralPurpose16bitInstance + 'static { } + +pub trait ComplementaryCaptureCompare16bitInstance: + sealed::ComplementaryCaptureCompare16bitInstance + crate::timer::AdvancedControlInstance + 'static +{ +} + pub trait CaptureCompare32bitInstance: sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + crate::timer::GeneralPurpose32bitInstance + 'static { @@ -209,6 +220,17 @@ foreach_interrupt! { impl CaptureCompare16bitInstance for crate::peripherals::$inst { } + + impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { + unsafe fn set_dead_time_value(&mut self, value: u8) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); + } + } + + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { + + } }; } From d8e2f82569e1182e2a3a7ebe43af64f91d1e57e0 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 5 Apr 2023 06:57:56 +0200 Subject: [PATCH 45/78] Let update_len be usize for now --- embassy-boot/boot/src/firmware_updater.rs | 20 +++++++++----------- embassy-boot/boot/src/lib.rs | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs index fffb9a50..48e15024 100644 --- a/embassy-boot/boot/src/firmware_updater.rs +++ b/embassy-boot/boot/src/firmware_updater.rs @@ -119,13 +119,11 @@ impl FirmwareUpdater { _state_and_dfu_flash: &mut F, _public_key: &[u8], _signature: &[u8], - _update_len: u32, + _update_len: usize, _aligned: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { - let _read_size = _aligned.len(); - assert_eq!(_aligned.len(), F::WRITE_SIZE); - assert!(_update_len <= self.dfu.len() as u32); + assert!(_update_len <= self.dfu.len()); #[cfg(feature = "ed25519-dalek")] { @@ -182,10 +180,11 @@ impl FirmwareUpdater { pub async fn hash( &mut self, dfu_flash: &mut F, - update_len: u32, + update_len: usize, chunk_buf: &mut [u8], output: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { + let update_len = update_len as u32; let mut digest = D::new(); for offset in (0..update_len).step_by(chunk_buf.len()) { self.dfu.read(dfu_flash, offset, chunk_buf).await?; @@ -341,13 +340,11 @@ impl FirmwareUpdater { _state_and_dfu_flash: &mut F, _public_key: &[u8], _signature: &[u8], - _update_len: u32, + _update_len: usize, _aligned: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { - let _read_size = _aligned.len(); - assert_eq!(_aligned.len(), F::WRITE_SIZE); - assert!(_update_len <= self.dfu.len() as u32); + assert!(_update_len <= self.dfu.len()); #[cfg(feature = "ed25519-dalek")] { @@ -402,10 +399,11 @@ impl FirmwareUpdater { pub fn hash_blocking( &mut self, dfu_flash: &mut F, - update_len: u32, + update_len: usize, chunk_buf: &mut [u8], output: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { + let update_len = update_len as u32; let mut digest = D::new(); for offset in (0..update_len).step_by(chunk_buf.len()) { self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?; @@ -536,7 +534,7 @@ mod tests { block_on(updater.write_firmware(0, to_write.as_slice(), &mut flash)).unwrap(); let mut chunk_buf = [0; 2]; let mut hash = [0; 20]; - block_on(updater.hash::<_, Sha1>(&mut flash, update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); + block_on(updater.hash::<_, Sha1>(&mut flash, update.len(), &mut chunk_buf, &mut hash)).unwrap(); assert_eq!(Sha1::digest(update).as_slice(), hash); } diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 605e5253..acd90996 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs @@ -281,7 +281,7 @@ mod tests { &mut flash, &public_key.to_bytes(), &signature.to_bytes(), - firmware_len as u32, + firmware_len, &mut aligned, )) .is_ok()); From 95b31cf2db647b8d1779cc3f7439d5c7df98f379 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 5 Apr 2023 10:27:13 +0200 Subject: [PATCH 46/78] 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 47/78] 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 48/78] 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]; From 8290236ed64435453a9c028c95246a86371bd4ce Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Sun, 2 Apr 2023 14:11:31 -0500 Subject: [PATCH 49/78] executor: Replace unsound critical sections with atomics --- embassy-executor/src/raw/mod.rs | 28 +++++++++++++-------------- embassy-executor/src/raw/run_queue.rs | 18 +++++++++++------ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index f6c66da5..bd0cff26 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -22,7 +22,6 @@ use core::ptr::NonNull; use core::task::{Context, Poll}; use atomic_polyfill::{AtomicU32, Ordering}; -use critical_section::CriticalSection; #[cfg(feature = "integrated-timers")] use embassy_time::driver::{self, AlarmHandle}; #[cfg(feature = "integrated-timers")] @@ -373,11 +372,11 @@ impl SyncExecutor { /// - `task` must be set up to run in this executor. /// - `task` must NOT be already enqueued (in this executor or another one). #[inline(always)] - unsafe fn enqueue(&self, cs: CriticalSection, task: TaskRef) { + unsafe fn enqueue(&self, task: TaskRef) { #[cfg(feature = "rtos-trace")] trace::task_ready_begin(task.as_ptr() as u32); - if self.run_queue.enqueue(cs, task) { + if self.run_queue.enqueue(task) { self.pender.pend(); } } @@ -394,9 +393,7 @@ impl SyncExecutor { #[cfg(feature = "rtos-trace")] trace::task_new(task.as_ptr() as u32); - critical_section::with(|cs| { - self.enqueue(cs, task); - }) + self.enqueue(task); } /// # Safety @@ -552,24 +549,25 @@ impl Executor { /// /// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`]. pub fn wake_task(task: TaskRef) { - critical_section::with(|cs| { - let header = task.header(); - let state = header.state.load(Ordering::Relaxed); + let header = task.header(); + let res = header.state.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| { // If already scheduled, or if not started, if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { - return; + None + } else { + // Mark it as scheduled + Some(state | STATE_RUN_QUEUED) } + }); - // Mark it as scheduled - header.state.store(state | STATE_RUN_QUEUED, Ordering::Relaxed); - + if res.is_ok() { // We have just marked the task as scheduled, so enqueue it. unsafe { let executor = header.executor.get().unwrap_unchecked(); - executor.enqueue(cs, task); + executor.enqueue(task); } - }) + } } #[cfg(feature = "integrated-timers")] diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs index 36215753..a88174a0 100644 --- a/embassy-executor/src/raw/run_queue.rs +++ b/embassy-executor/src/raw/run_queue.rs @@ -2,7 +2,6 @@ use core::ptr; use core::ptr::NonNull; use atomic_polyfill::{AtomicPtr, Ordering}; -use critical_section::CriticalSection; use super::{TaskHeader, TaskRef}; @@ -46,11 +45,18 @@ impl RunQueue { /// /// `item` must NOT be already enqueued in any queue. #[inline(always)] - pub(crate) unsafe fn enqueue(&self, _cs: CriticalSection, task: TaskRef) -> bool { - let prev = self.head.load(Ordering::Relaxed); - task.header().run_queue_item.next.store(prev, Ordering::Relaxed); - self.head.store(task.as_ptr() as _, Ordering::Relaxed); - prev.is_null() + pub(crate) unsafe fn enqueue(&self, task: TaskRef) -> bool { + let mut was_empty = false; + + self.head + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| { + was_empty = prev.is_null(); + task.header().run_queue_item.next.store(prev, Ordering::Relaxed); + Some(task.as_ptr() as *mut _) + }) + .ok(); + + was_empty } /// Empty the queue, then call `on_task` for each task that was in the queue. From 5d9ae3dbdbfe8ba6e1008cd2eadc09743cfc6284 Mon Sep 17 00:00:00 2001 From: "Matthew W. Samsonoff" Date: Tue, 13 Sep 2022 23:08:03 -0400 Subject: [PATCH 50/78] Add implementation of STM32 v1 ADC --- embassy-stm32/src/adc/v1.rs | 277 ++++++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 8b137891..923a1d97 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -1 +1,278 @@ +use core::marker::PhantomData; +use embassy_hal_common::into_ref; +use embedded_hal_02::blocking::delay::DelayUs; + +use crate::adc::{AdcPin, Instance}; +use crate::{pac, Peripheral}; + +pub const VDDA_CALIB_MV: u32 = 3300; +pub const VREF_INT: u32 = 1230; + +fn enable() { + critical_section::with(|_| unsafe { + crate::pac::RCC.apb2enr().modify(|reg| reg.set_adcen(true)); + }); +} + +pub enum Resolution { + TwelveBit, + TenBit, + EightBit, + SixBit, +} + +impl Default for Resolution { + fn default() -> Self { + Self::TwelveBit + } +} + +impl Resolution { + fn res(&self) -> pac::adc::vals::Res { + match self { + Resolution::TwelveBit => pac::adc::vals::Res::TWELVEBIT, + Resolution::TenBit => pac::adc::vals::Res::TENBIT, + Resolution::EightBit => pac::adc::vals::Res::EIGHTBIT, + Resolution::SixBit => pac::adc::vals::Res::SIXBIT, + } + } + + pub fn to_max_count(&self) -> u32 { + match self { + Resolution::TwelveBit => (1 << 12) - 1, + Resolution::TenBit => (1 << 10) - 1, + Resolution::EightBit => (1 << 8) - 1, + Resolution::SixBit => (1 << 6) - 1, + } + } +} + +pub struct Vbat; +impl AdcPin for Vbat {} +impl super::sealed::AdcPin for Vbat { + fn channel(&self) -> u8 { + 18 + } +} + +pub struct Vref; +impl AdcPin for Vref {} +impl super::sealed::AdcPin for Vref { + fn channel(&self) -> u8 { + 17 + } +} + +pub struct Temperature; +impl AdcPin for Temperature {} +impl super::sealed::AdcPin for Temperature { + fn channel(&self) -> u8 { + 16 + } +} + +mod sample_time { + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] + pub enum SampleTime { + /// 1.5 ADC clock cycles + Cycles1_5 = 0b000, + + /// 7.5 ADC clock cycles + Cycles7_5 = 0b001, + + /// 13.5 ADC clock cycles + Cycles13_5 = 0b010, + + /// 28.5 ADC clock cycles + Cycles28_5 = 0b011, + + /// 41.5 ADC clock cycles + Cycles41_5 = 0b100, + + /// 55.5 ADC clock cycles + Cycles55_5 = 0b101, + + /// 71.5 ADC clock cycles + Cycles71_5 = 0b110, + + /// 239.5 ADC clock cycles + Cycles239_5 = 0b111, + } + + impl SampleTime { + pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::Smp { + match self { + SampleTime::Cycles1_5 => crate::pac::adc::vals::Smp::CYCLES1_5, + SampleTime::Cycles7_5 => crate::pac::adc::vals::Smp::CYCLES7_5, + SampleTime::Cycles13_5 => crate::pac::adc::vals::Smp::CYCLES13_5, + SampleTime::Cycles28_5 => crate::pac::adc::vals::Smp::CYCLES28_5, + SampleTime::Cycles41_5 => crate::pac::adc::vals::Smp::CYCLES41_5, + SampleTime::Cycles55_5 => crate::pac::adc::vals::Smp::CYCLES55_5, + SampleTime::Cycles71_5 => crate::pac::adc::vals::Smp::CYCLES71_5, + SampleTime::Cycles239_5 => crate::pac::adc::vals::Smp::CYCLES239_5, + } + } + } + + impl Default for SampleTime { + fn default() -> Self { + Self::Cycles1_5 + } + } +} + +pub use sample_time::SampleTime; + +pub struct Adc<'d, T: Instance> { + sample_time: SampleTime, + vref_mv: u32, + resolution: Resolution, + phantom: PhantomData<&'d mut T>, +} + +impl<'d, T: Instance> Adc<'d, T> { + pub fn new(_peri: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + into_ref!(_peri); + enable(); + + // Delay 1μs when using HSI14 as the ADC clock. + // + // Table 57. ADC characteristics + // tstab = 14 * 1/fadc + delay.delay_us(1); + + let s = Self { + sample_time: Default::default(), + vref_mv: VDDA_CALIB_MV, + resolution: Resolution::default(), + phantom: PhantomData, + }; + s.calibrate(); + s + } + + pub fn enable_vbat(&self, _delay: &mut impl DelayUs) -> Vbat { + // SMP must be ≥ 56 ADC clock cycles when using HSI14. + // + // 6.3.20 Vbat monitoring characteristics + // ts_vbat ≥ 4μs + unsafe { + T::regs().ccr().modify(|reg| reg.set_vbaten(true)); + } + Vbat + } + + pub fn enable_vref(&self, delay: &mut impl DelayUs) -> Vref { + // Table 28. Embedded internal reference voltage + // tstart = 10μs + unsafe { + T::regs().ccr().modify(|reg| reg.set_vrefen(true)); + } + delay.delay_us(10); + Vref + } + + pub fn enable_temperature(&self, delay: &mut impl DelayUs) -> Temperature { + // SMP must be ≥ 56 ADC clock cycles when using HSI14. + // + // 6.3.19 Temperature sensor characteristics + // tstart ≤ 10μs + // ts_temp ≥ 4μs + unsafe { + T::regs().ccr().modify(|reg| reg.set_tsen(true)); + } + delay.delay_us(10); + Temperature + } + + fn calibrate(&self) { + unsafe { + // A.7.1 ADC calibration code example + if T::regs().cr().read().aden() { + T::regs().cr().modify(|reg| reg.set_addis(true)); + } + while T::regs().cr().read().aden() { + // spin + } + T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); + T::regs().cr().modify(|reg| reg.set_adcal(true)); + while T::regs().cr().read().adcal() { + // spin + } + } + } + + pub fn set_sample_time(&mut self, sample_time: SampleTime) { + self.sample_time = sample_time; + } + + pub fn set_vref_mv(&mut self, vref_mv: u32) { + self.vref_mv = vref_mv; + } + + pub fn set_resolution(&mut self, resolution: Resolution) { + self.resolution = resolution; + } + + pub fn to_millivolts(&self, sample: u16) -> u16 { + ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16 + } + + fn convert(&mut self) -> u16 { + unsafe { + T::regs().isr().modify(|reg| { + reg.set_eoc(true); + reg.set_eosmp(true); + }); + + // A.7.5 Single conversion sequence code example - Software trigger + T::regs().cr().modify(|reg| reg.set_adstart(true)); + while !T::regs().isr().read().eoc() { + // spin + } + + T::regs().dr().read().0 as u16 + } + } + + pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { + unsafe { + // A.7.2 ADC enable sequence code example + if T::regs().isr().read().adrdy() { + T::regs().isr().modify(|reg| reg.set_adrdy(true)); + } + T::regs().cr().modify(|reg| reg.set_aden(true)); + while !T::regs().isr().read().adrdy() { + // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration + // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the + // ADEN bit until the ADRDY flag goes high. + T::regs().cr().modify(|reg| reg.set_aden(true)); + } + + T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res())); + Self::set_channel_sample_time(pin.channel(), self.sample_time); + T::regs() + .chselr() + .write(|reg| reg.set_chselx(pin.channel() as usize, true)); + + let value = self.convert(); + + // A.7.3 ADC disable code example + T::regs().cr().modify(|reg| reg.set_adstp(true)); + while T::regs().cr().read().adstp() { + // spin + } + T::regs().cr().modify(|reg| reg.set_addis(true)); + while T::regs().cr().read().aden() { + // spin + } + + value + } + } + + unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { + T::regs().smpr().modify(|reg| reg.set_smp(sample_time.sample_time())); + } +} From 7e9e628eb9e63598a7d15ecae21af5a94ee93be4 Mon Sep 17 00:00:00 2001 From: "Matthew W. Samsonoff" Date: Tue, 13 Sep 2022 23:10:29 -0400 Subject: [PATCH 51/78] Add ADC example for STM32F0 --- examples/stm32f0/src/bin/adc.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 examples/stm32f0/src/bin/adc.rs diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs new file mode 100644 index 00000000..b69bc3c3 --- /dev/null +++ b/examples/stm32f0/src/bin/adc.rs @@ -0,0 +1,24 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::Adc; +use embassy_time::{Delay, Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut adc = Adc::new(p.ADC, &mut Delay); + let mut pin = p.PA1; + + loop { + let v = adc.read(&mut pin); + info!("--> {} - {} mV", v, adc.to_millivolts(v)); + Timer::after(Duration::from_millis(100)).await; + } +} From a0b60966106f96e2915d429319a347e239eb1a5f Mon Sep 17 00:00:00 2001 From: "Matthew W. Samsonoff" Date: Mon, 3 Oct 2022 13:03:42 -0400 Subject: [PATCH 52/78] Put ADC input pin into analog mode --- embassy-stm32/src/adc/v1.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 923a1d97..224d1717 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -236,7 +236,10 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { + pub fn read

(&mut self, pin: &mut P) -> u16 + where + P: AdcPin + crate::gpio::sealed::Pin, + { unsafe { // A.7.2 ADC enable sequence code example if T::regs().isr().read().adrdy() { @@ -252,6 +255,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res())); Self::set_channel_sample_time(pin.channel(), self.sample_time); + pin.set_as_analog(); T::regs() .chselr() .write(|reg| reg.set_chselx(pin.channel() as usize, true)); From 511a95124690be253dc9b789abeae1bdea3aa83a Mon Sep 17 00:00:00 2001 From: "Matthew W. Samsonoff" Date: Mon, 3 Oct 2022 14:18:37 -0400 Subject: [PATCH 53/78] Differentiate between `read` and `read_internal` for STM32F0 ADC The internal channels (vbat, vref, and temperature) are not real pins and do not have the `set_as_analog` method. They must be read using the `read_internal` method. --- embassy-stm32/src/adc/v1.rs | 120 +++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 56 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 224d1717..f787f72a 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -48,25 +48,33 @@ impl Resolution { } } +pub trait InternalChannel: sealed::InternalChannel {} + +mod sealed { + pub trait InternalChannel { + fn channel(&self) -> u8; + } +} + pub struct Vbat; -impl AdcPin for Vbat {} -impl super::sealed::AdcPin for Vbat { +impl InternalChannel for Vbat {} +impl sealed::InternalChannel for Vbat { fn channel(&self) -> u8 { 18 } } pub struct Vref; -impl AdcPin for Vref {} -impl super::sealed::AdcPin for Vref { +impl InternalChannel for Vref {} +impl sealed::InternalChannel for Vref { fn channel(&self) -> u8 { 17 } } pub struct Temperature; -impl AdcPin for Temperature {} -impl super::sealed::AdcPin for Temperature { +impl InternalChannel for Temperature {} +impl sealed::InternalChannel for Temperature { fn channel(&self) -> u8 { 16 } @@ -219,64 +227,64 @@ impl<'d, T: Instance> Adc<'d, T> { ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16 } - fn convert(&mut self) -> u16 { - unsafe { - T::regs().isr().modify(|reg| { - reg.set_eoc(true); - reg.set_eosmp(true); - }); - - // A.7.5 Single conversion sequence code example - Software trigger - T::regs().cr().modify(|reg| reg.set_adstart(true)); - while !T::regs().isr().read().eoc() { - // spin - } - - T::regs().dr().read().0 as u16 - } - } - pub fn read

(&mut self, pin: &mut P) -> u16 where P: AdcPin + crate::gpio::sealed::Pin, { + let channel = pin.channel(); unsafe { - // A.7.2 ADC enable sequence code example - if T::regs().isr().read().adrdy() { - T::regs().isr().modify(|reg| reg.set_adrdy(true)); - } - T::regs().cr().modify(|reg| reg.set_aden(true)); - while !T::regs().isr().read().adrdy() { - // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration - // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the - // ADEN bit until the ADRDY flag goes high. - T::regs().cr().modify(|reg| reg.set_aden(true)); - } - - T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res())); - Self::set_channel_sample_time(pin.channel(), self.sample_time); pin.set_as_analog(); - T::regs() - .chselr() - .write(|reg| reg.set_chselx(pin.channel() as usize, true)); - - let value = self.convert(); - - // A.7.3 ADC disable code example - T::regs().cr().modify(|reg| reg.set_adstp(true)); - while T::regs().cr().read().adstp() { - // spin - } - T::regs().cr().modify(|reg| reg.set_addis(true)); - while T::regs().cr().read().aden() { - // spin - } - - value + self.read_channel(channel) } } - unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { - T::regs().smpr().modify(|reg| reg.set_smp(sample_time.sample_time())); + pub fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { + let channel = channel.channel(); + unsafe { + self.read_channel(channel) + } + } + + unsafe fn read_channel(&mut self, channel: u8) -> u16 { + // A.7.2 ADC enable sequence code example + if T::regs().isr().read().adrdy() { + T::regs().isr().modify(|reg| reg.set_adrdy(true)); + } + T::regs().cr().modify(|reg| reg.set_aden(true)); + while !T::regs().isr().read().adrdy() { + // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration + // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the + // ADEN bit until the ADRDY flag goes high. + T::regs().cr().modify(|reg| reg.set_aden(true)); + } + + T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res())); + T::regs().isr().modify(|reg| { + reg.set_eoc(true); + reg.set_eosmp(true); + }); + + // A.7.5 Single conversion sequence code example - Software trigger + T::regs() + .chselr() + .write(|reg| reg.set_chselx(channel as usize, true)); + T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.sample_time())); + T::regs().cr().modify(|reg| reg.set_adstart(true)); + while !T::regs().isr().read().eoc() { + // spin + } + let value = T::regs().dr().read().0 as u16; + + // A.7.3 ADC disable code example + T::regs().cr().modify(|reg| reg.set_adstp(true)); + while T::regs().cr().read().adstp() { + // spin + } + T::regs().cr().modify(|reg| reg.set_addis(true)); + while T::regs().cr().read().aden() { + // spin + } + + value } } From 28b8ac4b62d952918ddfe143cf6925e1402fc2ce Mon Sep 17 00:00:00 2001 From: "Matthew W. Samsonoff" Date: Mon, 3 Oct 2022 14:23:31 -0400 Subject: [PATCH 54/78] Update STM32F0 ADC example to use `read_internal` --- examples/stm32f0/src/bin/adc.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index b69bc3c3..6205596f 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::Adc; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_time::{Delay, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -14,11 +14,14 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC, &mut Delay); + adc.set_sample_time(SampleTime::Cycles71_5); let mut pin = p.PA1; + let mut vref = adc.enable_temperature(&mut Delay); loop { let v = adc.read(&mut pin); - info!("--> {} - {} mV", v, adc.to_millivolts(v)); + let r = adc.read_internal(&mut vref); + info!("--> {} - {} mV / vref = {} - {} mV", v, adc.to_millivolts(v), r, adc.to_millivolts(r)); Timer::after(Duration::from_millis(100)).await; } } From f5881054297713f6224d5d81f407f8a6cf591ef4 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Wed, 5 Apr 2023 14:31:32 -0500 Subject: [PATCH 55/78] wip --- embassy-stm32/src/adc/mod.rs | 11 +-- embassy-stm32/src/adc/resolution.rs | 8 +- embassy-stm32/src/adc/sample_time.rs | 2 +- embassy-stm32/src/adc/v1.rs | 129 +++------------------------ 4 files changed, 20 insertions(+), 130 deletions(-) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index ec49dace..56ecd63c 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -7,21 +7,18 @@ #[cfg_attr(adc_v4, path = "v4.rs")] mod _version; -#[cfg(not(any(adc_f1, adc_v1)))] +#[cfg(not(adc_f1))] mod resolution; -#[cfg(not(adc_v1))] mod sample_time; #[allow(unused)] pub use _version::*; -#[cfg(not(any(adc_f1, adc_v1)))] +#[cfg(not(adc_f1))] pub use resolution::Resolution; -#[cfg(not(adc_v1))] pub use sample_time::SampleTime; use crate::peripherals; -#[cfg(not(adc_v1))] pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::PeripheralRef<'d, T>, @@ -44,9 +41,9 @@ pub(crate) mod sealed { } } -#[cfg(not(any(adc_f1, adc_v2, adc_v4)))] +#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4)))] pub trait Instance: sealed::Instance + crate::Peripheral

{} -#[cfg(any(adc_f1, adc_v2, adc_v4))] +#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4))] pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc::RccPeripheral {} pub trait AdcPin: sealed::AdcPin {} diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 62b52a46..67fb9b8c 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs @@ -1,4 +1,4 @@ -#[cfg(any(adc_v2, adc_v3, adc_g0))] +#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Resolution { TwelveBit, @@ -19,7 +19,7 @@ pub enum Resolution { impl Default for Resolution { fn default() -> Self { - #[cfg(any(adc_v2, adc_v3, adc_g0))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] { Self::TwelveBit } @@ -40,7 +40,7 @@ impl From for crate::pac::adc::vals::Res { Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, - #[cfg(any(adc_v2, adc_v3, adc_g0))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, } } @@ -56,7 +56,7 @@ impl Resolution { Resolution::TwelveBit => (1 << 12) - 1, Resolution::TenBit => (1 << 10) - 1, Resolution::EightBit => (1 << 8) - 1, - #[cfg(any(adc_v2, adc_v3, adc_g0))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] Resolution::SixBit => (1 << 6) - 1, } } diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs index bc5fb1d6..0faa1e3c 100644 --- a/embassy-stm32/src/adc/sample_time.rs +++ b/embassy-stm32/src/adc/sample_time.rs @@ -25,7 +25,7 @@ macro_rules! impl_sample_time { }; } -#[cfg(adc_f1)] +#[cfg(any(adc_f1, adc_v1))] impl_sample_time!( "1.5", Cycles1_5, diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index f787f72a..0fdb9556 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -1,10 +1,8 @@ -use core::marker::PhantomData; - use embassy_hal_common::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use crate::adc::{AdcPin, Instance}; -use crate::{pac, Peripheral}; +use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; +use crate::Peripheral; pub const VDDA_CALIB_MV: u32 = 3300; pub const VREF_INT: u32 = 1230; @@ -15,39 +13,6 @@ fn enable() { }); } -pub enum Resolution { - TwelveBit, - TenBit, - EightBit, - SixBit, -} - -impl Default for Resolution { - fn default() -> Self { - Self::TwelveBit - } -} - -impl Resolution { - fn res(&self) -> pac::adc::vals::Res { - match self { - Resolution::TwelveBit => pac::adc::vals::Res::TWELVEBIT, - Resolution::TenBit => pac::adc::vals::Res::TENBIT, - Resolution::EightBit => pac::adc::vals::Res::EIGHTBIT, - Resolution::SixBit => pac::adc::vals::Res::SIXBIT, - } - } - - pub fn to_max_count(&self) -> u32 { - match self { - Resolution::TwelveBit => (1 << 12) - 1, - Resolution::TenBit => (1 << 10) - 1, - Resolution::EightBit => (1 << 8) - 1, - Resolution::SixBit => (1 << 6) - 1, - } - } -} - pub trait InternalChannel: sealed::InternalChannel {} mod sealed { @@ -80,68 +45,9 @@ impl sealed::InternalChannel for Temperature { } } -mod sample_time { - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] - pub enum SampleTime { - /// 1.5 ADC clock cycles - Cycles1_5 = 0b000, - - /// 7.5 ADC clock cycles - Cycles7_5 = 0b001, - - /// 13.5 ADC clock cycles - Cycles13_5 = 0b010, - - /// 28.5 ADC clock cycles - Cycles28_5 = 0b011, - - /// 41.5 ADC clock cycles - Cycles41_5 = 0b100, - - /// 55.5 ADC clock cycles - Cycles55_5 = 0b101, - - /// 71.5 ADC clock cycles - Cycles71_5 = 0b110, - - /// 239.5 ADC clock cycles - Cycles239_5 = 0b111, - } - - impl SampleTime { - pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::Smp { - match self { - SampleTime::Cycles1_5 => crate::pac::adc::vals::Smp::CYCLES1_5, - SampleTime::Cycles7_5 => crate::pac::adc::vals::Smp::CYCLES7_5, - SampleTime::Cycles13_5 => crate::pac::adc::vals::Smp::CYCLES13_5, - SampleTime::Cycles28_5 => crate::pac::adc::vals::Smp::CYCLES28_5, - SampleTime::Cycles41_5 => crate::pac::adc::vals::Smp::CYCLES41_5, - SampleTime::Cycles55_5 => crate::pac::adc::vals::Smp::CYCLES55_5, - SampleTime::Cycles71_5 => crate::pac::adc::vals::Smp::CYCLES71_5, - SampleTime::Cycles239_5 => crate::pac::adc::vals::Smp::CYCLES239_5, - } - } - } - - impl Default for SampleTime { - fn default() -> Self { - Self::Cycles1_5 - } - } -} - -pub use sample_time::SampleTime; - -pub struct Adc<'d, T: Instance> { - sample_time: SampleTime, - vref_mv: u32, - resolution: Resolution, - phantom: PhantomData<&'d mut T>, -} - impl<'d, T: Instance> Adc<'d, T> { - pub fn new(_peri: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { - into_ref!(_peri); + pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + into_ref!(adc); enable(); // Delay 1μs when using HSI14 as the ADC clock. @@ -151,10 +57,8 @@ impl<'d, T: Instance> Adc<'d, T> { delay.delay_us(1); let s = Self { + adc, sample_time: Default::default(), - vref_mv: VDDA_CALIB_MV, - resolution: Resolution::default(), - phantom: PhantomData, }; s.calibrate(); s @@ -215,16 +119,10 @@ impl<'d, T: Instance> Adc<'d, T> { self.sample_time = sample_time; } - pub fn set_vref_mv(&mut self, vref_mv: u32) { - self.vref_mv = vref_mv; - } - pub fn set_resolution(&mut self, resolution: Resolution) { - self.resolution = resolution; - } - - pub fn to_millivolts(&self, sample: u16) -> u16 { - ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16 + unsafe { + T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); + } } pub fn read

(&mut self, pin: &mut P) -> u16 @@ -240,9 +138,7 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { let channel = channel.channel(); - unsafe { - self.read_channel(channel) - } + unsafe { self.read_channel(channel) } } unsafe fn read_channel(&mut self, channel: u8) -> u16 { @@ -258,17 +154,14 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cr().modify(|reg| reg.set_aden(true)); } - T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res())); T::regs().isr().modify(|reg| { reg.set_eoc(true); reg.set_eosmp(true); }); // A.7.5 Single conversion sequence code example - Software trigger - T::regs() - .chselr() - .write(|reg| reg.set_chselx(channel as usize, true)); - T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.sample_time())); + T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); + T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); T::regs().cr().modify(|reg| reg.set_adstart(true)); while !T::regs().isr().read().eoc() { // spin From efd9e18321c258a188fa675804d59346a4c11cc2 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Wed, 5 Apr 2023 15:12:27 -0500 Subject: [PATCH 56/78] Fix example --- examples/stm32f0/src/bin/adc.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index 6205596f..c639299d 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -16,12 +16,21 @@ async fn main(_spawner: Spawner) { let mut adc = Adc::new(p.ADC, &mut Delay); adc.set_sample_time(SampleTime::Cycles71_5); let mut pin = p.PA1; - let mut vref = adc.enable_temperature(&mut Delay); + + let mut vrefint = adc.enable_vref(&mut Delay); + let vrefint_sample = adc.read_internal(&mut vrefint); + let convert_to_millivolts = |sample| { + // FIXME: use proper datasheet and value + // From http://www.st.com/resource/en/datasheet/CD00161566.pdf + // 5.3.4 Embedded reference voltage + const VREFINT_MV: u32 = 1200; // mV + + (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16 + }; loop { let v = adc.read(&mut pin); - let r = adc.read_internal(&mut vref); - info!("--> {} - {} mV / vref = {} - {} mV", v, adc.to_millivolts(v), r, adc.to_millivolts(r)); + info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after(Duration::from_millis(100)).await; } } From 37d8f2e51256403cc4839c3b45e5c2253e3a09f1 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Wed, 5 Apr 2023 15:28:42 -0500 Subject: [PATCH 57/78] Properly enable and reset adc --- embassy-stm32/src/adc/v1.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 0fdb9556..a699d8f7 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -7,12 +7,6 @@ use crate::Peripheral; pub const VDDA_CALIB_MV: u32 = 3300; pub const VREF_INT: u32 = 1230; -fn enable() { - critical_section::with(|_| unsafe { - crate::pac::RCC.apb2enr().modify(|reg| reg.set_adcen(true)); - }); -} - pub trait InternalChannel: sealed::InternalChannel {} mod sealed { @@ -48,7 +42,8 @@ impl sealed::InternalChannel for Temperature { impl<'d, T: Instance> Adc<'d, T> { pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { into_ref!(adc); - enable(); + T::enable(); + T::reset(); // Delay 1μs when using HSI14 as the ADC clock. // From 20e7b5e2965f718aa1a0ece6009356ba50d2d780 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Wed, 5 Apr 2023 16:11:21 -0500 Subject: [PATCH 58/78] InternalChannel --- embassy-stm32/src/adc/v1.rs | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index a699d8f7..5f0f8c14 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -1,39 +1,32 @@ use embassy_hal_common::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; +use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; use crate::Peripheral; +use crate::peripherals::ADC1; pub const VDDA_CALIB_MV: u32 = 3300; pub const VREF_INT: u32 = 1230; -pub trait InternalChannel: sealed::InternalChannel {} - -mod sealed { - pub trait InternalChannel { - fn channel(&self) -> u8; - } -} - pub struct Vbat; -impl InternalChannel for Vbat {} -impl sealed::InternalChannel for Vbat { +impl InternalChannel for Vbat {} +impl super::sealed::InternalChannel for Vbat { fn channel(&self) -> u8 { 18 } } pub struct Vref; -impl InternalChannel for Vref {} -impl sealed::InternalChannel for Vref { +impl InternalChannel for Vref {} +impl super::sealed::::InternalChannel for Vref { fn channel(&self) -> u8 { 17 } } pub struct Temperature; -impl InternalChannel for Temperature {} -impl sealed::InternalChannel for Temperature { +impl InternalChannel for Temperature {} +impl super::sealed::InternalChannel for Temperature { fn channel(&self) -> u8 { 16 } From 7c53ebd5766fc75dbb5ddd1953b5bff13f1cd853 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Wed, 5 Apr 2023 16:28:28 -0500 Subject: [PATCH 59/78] Fix example reference voltage --- examples/stm32f0/src/bin/adc.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index c639299d..8ed9f98f 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -20,10 +20,9 @@ async fn main(_spawner: Spawner) { let mut vrefint = adc.enable_vref(&mut Delay); let vrefint_sample = adc.read_internal(&mut vrefint); let convert_to_millivolts = |sample| { - // FIXME: use proper datasheet and value - // From http://www.st.com/resource/en/datasheet/CD00161566.pdf - // 5.3.4 Embedded reference voltage - const VREFINT_MV: u32 = 1200; // mV + // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf + // 6.3.4 Embedded reference voltage + const VREFINT_MV: u32 = 1230; // mV (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16 }; From 92e96bd601e8e663114b1efccc4a1e8d309332d9 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Wed, 5 Apr 2023 16:38:06 -0500 Subject: [PATCH 60/78] Fix typo --- embassy-stm32/src/adc/v1.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 5f0f8c14..17114732 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -2,8 +2,8 @@ use embassy_hal_common::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; -use crate::Peripheral; use crate::peripherals::ADC1; +use crate::Peripheral; pub const VDDA_CALIB_MV: u32 = 3300; pub const VREF_INT: u32 = 1230; @@ -18,7 +18,7 @@ impl super::sealed::InternalChannel for Vbat { pub struct Vref; impl InternalChannel for Vref {} -impl super::sealed::::InternalChannel for Vref { +impl super::sealed::InternalChannel for Vref { fn channel(&self) -> u8 { 17 } From 0ef419bee4afc5a984cab3d5f16e1f1382fa6bbf Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Wed, 5 Apr 2023 16:52:32 -0500 Subject: [PATCH 61/78] Change ADC1 to ADC --- embassy-stm32/src/adc/v1.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 17114732..82a8c3ef 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -2,31 +2,31 @@ use embassy_hal_common::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; -use crate::peripherals::ADC1; +use crate::peripherals::ADC; use crate::Peripheral; pub const VDDA_CALIB_MV: u32 = 3300; pub const VREF_INT: u32 = 1230; pub struct Vbat; -impl InternalChannel for Vbat {} -impl super::sealed::InternalChannel for Vbat { +impl InternalChannel for Vbat {} +impl super::sealed::InternalChannel for Vbat { fn channel(&self) -> u8 { 18 } } pub struct Vref; -impl InternalChannel for Vref {} -impl super::sealed::InternalChannel for Vref { +impl InternalChannel for Vref {} +impl super::sealed::InternalChannel for Vref { fn channel(&self) -> u8 { 17 } } pub struct Temperature; -impl InternalChannel for Temperature {} -impl super::sealed::InternalChannel for Temperature { +impl InternalChannel for Temperature {} +impl super::sealed::InternalChannel for Temperature { fn channel(&self) -> u8 { 16 } From 76772683191be15d32604ec5dd46fb5eb3949de8 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 5 Apr 2023 17:50:23 -0500 Subject: [PATCH 62/78] stm32/pwm: cleanup and fix complementary pwm --- embassy-stm32/src/pwm/complementary_pwm.rs | 47 ++++++---------------- embassy-stm32/src/pwm/mod.rs | 18 +++++++++ 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs index b8761724..e4de1fb7 100644 --- a/embassy-stm32/src/pwm/complementary_pwm.rs +++ b/embassy-stm32/src/pwm/complementary_pwm.rs @@ -1,7 +1,9 @@ use core::marker::PhantomData; use embassy_hal_common::{into_ref, PeripheralRef}; +use stm32_metapac::timer::vals::Ckd; +use super::simple_pwm::*; use super::*; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; @@ -9,39 +11,13 @@ use crate::gpio::AnyPin; use crate::time::Hertz; use crate::Peripheral; -pub struct Ch1; -pub struct Ch2; -pub struct Ch3; -pub struct Ch4; - -pub struct PwmPin<'d, Perip, Channel> { - _pin: PeripheralRef<'d, AnyPin>, - phantom: PhantomData<(Perip, Channel)>, -} - pub struct ComplementaryPwmPin<'d, Perip, Channel> { _pin: PeripheralRef<'d, AnyPin>, phantom: PhantomData<(Perip, Channel)>, } -macro_rules! channel_impl { +macro_rules! complementary_channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => { - impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { - into_ref!(pin); - critical_section::with(|_| unsafe { - pin.set_low(); - pin.set_as_af(pin.af_num(), AFType::OutputPushPull); - #[cfg(gpio_v2)] - pin.set_speed(crate::gpio::Speed::VeryHigh); - }); - PwmPin { - _pin: pin.map_into(), - phantom: PhantomData, - } - } - } - impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); @@ -60,10 +36,10 @@ macro_rules! channel_impl { }; } -channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin); -channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin); -channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin); -channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin); +complementary_channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin); +complementary_channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin); +complementary_channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin); +complementary_channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin); pub struct ComplementaryPwm<'d, T> { inner: PeripheralRef<'d, T>, @@ -114,11 +90,13 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { pub fn enable(&mut self, channel: Channel) { unsafe { self.inner.enable_channel(channel, true); + self.inner.enable_complementary_channel(channel, true); } } pub fn disable(&mut self, channel: Channel) { unsafe { + self.inner.enable_complementary_channel(channel, false); self.inner.enable_channel(channel, false); } } @@ -136,9 +114,10 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { unsafe { self.inner.set_compare_value(channel, duty) } } - /* - set the value of the dead-time register - */ + pub fn set_dead_time_clock_division(&mut self, value: Ckd) { + unsafe { self.inner.set_dead_time_clock_division(value) } + } + pub fn set_dead_time_value(&mut self, value: u8) { unsafe { self.inner.set_dead_time_value(value) } } diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index 6f3c1266..0bef0708 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -1,6 +1,8 @@ pub mod complementary_pwm; pub mod simple_pwm; +use stm32_metapac::timer::vals::Ckd; + #[cfg(feature = "unstable-pac")] pub mod low_level { pub use super::sealed::*; @@ -69,7 +71,11 @@ pub(crate) mod sealed { } pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { + unsafe fn set_dead_time_clock_division(&mut self, value: Ckd); + unsafe fn set_dead_time_value(&mut self, value: u8); + + unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); } pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { @@ -222,10 +228,22 @@ foreach_interrupt! { } impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { + unsafe fn set_dead_time_clock_division(&mut self, value: Ckd) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); + } + unsafe fn set_dead_time_value(&mut self, value: u8) { use crate::timer::sealed::AdvancedControlInstance; Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); } + + unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced() + .ccer() + .modify(|w| w.set_ccne(channel.raw(), enable)); + } } impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { From 9f1dac3f5daf61a2d56679d00e018e5e3557c7e5 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 5 Apr 2023 18:07:07 -0500 Subject: [PATCH 63/78] stm32/pwm: add complementary pwm example --- embassy-stm32/src/pwm/complementary_pwm.rs | 2 +- examples/stm32f4/src/bin/pwm_complementary.rs | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 examples/stm32f4/src/bin/pwm_complementary.rs diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs index e4de1fb7..13edfbaa 100644 --- a/embassy-stm32/src/pwm/complementary_pwm.rs +++ b/embassy-stm32/src/pwm/complementary_pwm.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use embassy_hal_common::{into_ref, PeripheralRef}; -use stm32_metapac::timer::vals::Ckd; +pub use stm32_metapac::timer::vals::Ckd; use super::simple_pwm::*; use super::*; diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs new file mode 100644 index 00000000..795c38e4 --- /dev/null +++ b/examples/stm32f4/src/bin/pwm_complementary.rs @@ -0,0 +1,77 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::pwm::complementary_pwm::{Ckd, ComplementaryPwm, ComplementaryPwmPin}; +use embassy_stm32::pwm::simple_pwm::{PwmPin, SimplePwm}; +use embassy_stm32::pwm::Channel; +use embassy_stm32::time::khz; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let ch1 = PwmPin::new_ch1(p.PE9); + let ch1n = ComplementaryPwmPin::new_ch1(p.PA7); + let mut pwm = ComplementaryPwm::new( + p.TIM1, + Some(ch1), + Some(ch1n), + None, + None, + None, + None, + None, + None, + khz(10), + ); + + /* + Dead-time = T_clk * T_dts * T_dtg + + T_dts: + This bit-field indicates the division ratio between the timer clock (CK_INT) frequency and the + dead-time and sampling clock (tDTS)used by the dead-time generators and the digital filters + (ETR, TIx), + 00: tDTS=tCK_INT + 01: tDTS=2*tCK_INT + 10: tDTS=4*tCK_INT + + T_dtg: + This bit-field defines the duration of the dead-time inserted between the complementary + outputs. DT correspond to this duration. + DTG[7:5]=0xx => DT=DTG[7:0]x tdtg with tdtg=tDTS. + DTG[7:5]=10x => DT=(64+DTG[5:0])xtdtg with Tdtg=2xtDTS. + DTG[7:5]=110 => DT=(32+DTG[4:0])xtdtg with Tdtg=8xtDTS. + DTG[7:5]=111 => DT=(32+DTG[4:0])xtdtg with Tdtg=16xtDTS. + Example if TDTS=125ns (8MHz), dead-time possible values are: + 0 to 15875 ns by 125 ns steps, + 16 us to 31750 ns by 250 ns steps, + 32 us to 63us by 1 us steps, + 64 us to 126 us by 2 us steps + */ + pwm.set_dead_time_clock_division(Ckd::DIV1); + pwm.set_dead_time_value(0); + + let max = pwm.get_max_duty(); + pwm.enable(Channel::Ch1); + + info!("PWM initialized"); + info!("PWM max duty {}", max); + + loop { + pwm.set_duty(Channel::Ch1, 0); + Timer::after(Duration::from_millis(300)).await; + pwm.set_duty(Channel::Ch1, max / 4); + Timer::after(Duration::from_millis(300)).await; + pwm.set_duty(Channel::Ch1, max / 2); + Timer::after(Duration::from_millis(300)).await; + pwm.set_duty(Channel::Ch1, max - 1); + Timer::after(Duration::from_millis(300)).await; + } +} From 31ef783ac1add908c4c4506d3ce4e5f6ad9bea56 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 5 Apr 2023 18:18:05 -0500 Subject: [PATCH 64/78] stm32/pwm: fix unused import --- examples/stm32f4/src/bin/pwm_complementary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs index 795c38e4..6e17f3fd 100644 --- a/examples/stm32f4/src/bin/pwm_complementary.rs +++ b/examples/stm32f4/src/bin/pwm_complementary.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::pwm::complementary_pwm::{Ckd, ComplementaryPwm, ComplementaryPwmPin}; -use embassy_stm32::pwm::simple_pwm::{PwmPin, SimplePwm}; +use embassy_stm32::pwm::simple_pwm::PwmPin; use embassy_stm32::pwm::Channel; use embassy_stm32::time::khz; use embassy_time::{Duration, Timer}; From 9f28d8097704f51fb7d7dcc8d459ce86aaf07eff Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 6 Apr 2023 18:50:53 +0200 Subject: [PATCH 65/78] stm32/usb: add support for 32bit usbram. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/usb/usb.rs | 131 +++++++++++++++++++++++------------ 2 files changed, 87 insertions(+), 48 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 504caacb..da1dc24b 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 = "3" +stm32-metapac = "4" 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 = "3", default-features = false, features = ["metadata"]} +stm32-metapac = { version = "4", default-features = false, features = ["metadata"]} [features] default = ["stm32-metapac/rt"] diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 0355c5f1..e6ee3954 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -12,22 +12,29 @@ use embassy_usb_driver as driver; use embassy_usb_driver::{ Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, }; -use pac::common::{Reg, RW}; -use pac::usb::vals::{EpType, Stat}; use super::{DmPin, DpPin, Instance}; use crate::gpio::sealed::AFType; use crate::interrupt::InterruptExt; use crate::pac::usb::regs; +use crate::pac::usb::vals::{EpType, Stat}; +use crate::pac::USBRAM; use crate::rcc::sealed::RccPeripheral; -use crate::{pac, Peripheral}; +use crate::Peripheral; const EP_COUNT: usize = 8; -#[cfg(any(usb_v1_x1, usb_v1_x2))] -const EP_MEMORY_SIZE: usize = 512; -#[cfg(not(any(usb_v1_x1, usb_v1_x2)))] -const EP_MEMORY_SIZE: usize = 1024; +#[cfg(any(usbram_16x1_512, usbram_16x2_512))] +const USBRAM_SIZE: usize = 512; +#[cfg(usbram_16x2_1024)] +const USBRAM_SIZE: usize = 1024; +#[cfg(usbram_32_2048)] +const USBRAM_SIZE: usize = 2048; + +#[cfg(not(usbram_32_2048))] +const USBRAM_ALIGN: usize = 2; +#[cfg(usbram_32_2048)] +const USBRAM_ALIGN: usize = 4; const NEW_AW: AtomicWaker = AtomicWaker::new(); static BUS_WAKER: AtomicWaker = NEW_AW; @@ -57,25 +64,60 @@ fn invariant(mut r: regs::Epr) -> regs::Epr { r } +fn align_len_up(len: u16) -> u16 { + ((len as usize + USBRAM_ALIGN - 1) / USBRAM_ALIGN * USBRAM_ALIGN) as u16 +} + // Returns (actual_len, len_bits) fn calc_out_len(len: u16) -> (u16, u16) { match len { - 2..=62 => ((len + 1) / 2 * 2, ((len + 1) / 2) << 10), - 63..=480 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000), + // NOTE: this could be 2..=62 with 16bit USBRAM, but not with 32bit. Limit it to 60 for simplicity. + 2..=60 => (align_len_up(len), align_len_up(len) / 2 << 10), + 61..=1024 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000), _ => panic!("invalid OUT length {}", len), } } -fn ep_in_addr(index: usize) -> Reg { - T::regs().ep_mem(index * 4 + 0) + +#[cfg(not(usbram_32_2048))] +mod btable { + use super::*; + + pub(super) unsafe fn write_in(index: usize, addr: u16) { + USBRAM.mem(index * 4 + 0).write_value(addr); + } + + pub(super) unsafe fn write_in_len(index: usize, _addr: u16, len: u16) { + USBRAM.mem(index * 4 + 1).write_value(len); + } + + pub(super) unsafe fn write_out(index: usize, addr: u16, max_len_bits: u16) { + USBRAM.mem(index * 4 + 2).write_value(addr); + USBRAM.mem(index * 4 + 3).write_value(max_len_bits); + } + + pub(super) unsafe fn read_out_len(index: usize) -> u16 { + USBRAM.mem(index * 4 + 3).read() + } } -fn ep_in_len(index: usize) -> Reg { - T::regs().ep_mem(index * 4 + 1) -} -fn ep_out_addr(index: usize) -> Reg { - T::regs().ep_mem(index * 4 + 2) -} -fn ep_out_len(index: usize) -> Reg { - T::regs().ep_mem(index * 4 + 3) +#[cfg(usbram_32_2048)] +mod btable { + use super::*; + + pub(super) unsafe fn write_in(_index: usize, _addr: u16) {} + + pub(super) unsafe fn write_in_len(index: usize, addr: u16, len: u16) { + USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); + } + + pub(super) unsafe fn write_out(index: usize, addr: u16, max_len_bits: u16) { + USBRAM + .mem(index * 2 + 1) + .write_value((addr as u32) | ((max_len_bits as u32) << 16)); + } + + pub(super) unsafe fn read_out_len(index: usize) -> u16 { + (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 + } } struct EndpointBuffer { @@ -87,23 +129,25 @@ struct EndpointBuffer { impl EndpointBuffer { fn read(&mut self, buf: &mut [u8]) { assert!(buf.len() <= self.len as usize); - for i in 0..((buf.len() + 1) / 2) { - let val = unsafe { T::regs().ep_mem(self.addr as usize / 2 + i).read() }; - buf[i * 2] = val as u8; - if i * 2 + 1 < buf.len() { - buf[i * 2 + 1] = (val >> 8) as u8; - } + for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { + let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() }; + let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); + buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]); } } fn write(&mut self, buf: &[u8]) { assert!(buf.len() <= self.len as usize); - for i in 0..((buf.len() + 1) / 2) { - let mut val = buf[i * 2] as u16; - if i * 2 + 1 < buf.len() { - val |= (buf[i * 2 + 1] as u16) << 8; - } - unsafe { T::regs().ep_mem(self.addr as usize / 2 + i).write_value(val) }; + for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { + let mut val = [0u8; USBRAM_ALIGN]; + let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); + val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]); + + #[cfg(not(usbram_32_2048))] + let val = u16::from_le_bytes(val); + #[cfg(usbram_32_2048)] + let val = u32::from_le_bytes(val); + unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) }; } } } @@ -139,8 +183,7 @@ impl<'d, T: Instance> Driver<'d, T> { #[cfg(stm32l5)] unsafe { crate::peripherals::PWR::enable(); - - pac::PWR.cr2().modify(|w| w.set_usv(true)); + crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); } unsafe { @@ -256,8 +299,9 @@ impl<'d, T: Instance> Driver<'d, T> { } fn alloc_ep_mem(&mut self, len: u16) -> u16 { + assert!(len as usize % USBRAM_ALIGN == 0); let addr = self.ep_mem_free; - if addr + len > EP_MEMORY_SIZE as _ { + if addr + len > USBRAM_SIZE as _ { panic!("Endpoint memory full"); } self.ep_mem_free += len; @@ -306,10 +350,7 @@ impl<'d, T: Instance> Driver<'d, T> { let addr = self.alloc_ep_mem(len); trace!(" len_bits = {:04x}", len_bits); - unsafe { - ep_out_addr::(index).write_value(addr); - ep_out_len::(index).write_value(len_bits); - } + unsafe { btable::write_out::(index, addr, len_bits) } EndpointBuffer { addr, @@ -321,13 +362,11 @@ impl<'d, T: Instance> Driver<'d, T> { assert!(!ep.used_in); ep.used_in = true; - let len = (max_packet_size + 1) / 2 * 2; + let len = align_len_up(max_packet_size); let addr = self.alloc_ep_mem(len); - unsafe { - ep_in_addr::(index).write_value(addr); - // ep_in_len is written when actually TXing packets. - } + // ep_in_len is written when actually TXing packets. + unsafe { btable::write_in::(index, addr) } EndpointBuffer { addr, @@ -398,7 +437,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { w.set_ctrm(true); }); - #[cfg(usb_v3)] + #[cfg(any(usb_v3, usb_v4))] regs.bcdr().write(|w| w.set_dppu(true)) } @@ -633,12 +672,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> { fn write_data(&mut self, buf: &[u8]) { let index = self.info.addr.index(); self.buf.write(buf); - unsafe { ep_in_len::(index).write_value(buf.len() as _) }; + unsafe { btable::write_in_len::(index, self.buf.addr, buf.len() as _) } } fn read_data(&mut self, buf: &mut [u8]) -> Result { let index = self.info.addr.index(); - let rx_len = unsafe { ep_out_len::(index).read() as usize } & 0x3FF; + let rx_len = unsafe { btable::read_out_len::(index) as usize } & 0x3FF; trace!("READ DONE, rx_len = {}", rx_len); if rx_len > buf.len() { return Err(EndpointError::BufferOverflow); From 611d0238290c9f7b3b23d05ec07adf5b48ea3479 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 6 Apr 2023 18:53:51 +0200 Subject: [PATCH 66/78] stm32: add H5 support. --- ci.sh | 3 + embassy-stm32/Cargo.toml | 73 +++ embassy-stm32/build.rs | 7 +- embassy-stm32/src/eth/v2/mod.rs | 25 +- embassy-stm32/src/exti.rs | 18 +- embassy-stm32/src/rcc/h5.rs | 606 ++++++++++++++++++++++++ embassy-stm32/src/rcc/mod.rs | 13 +- embassy-stm32/src/time.rs | 46 +- embassy-stm32/src/usb/usb.rs | 5 + examples/stm32h5/.cargo/config.toml | 8 + examples/stm32h5/Cargo.toml | 71 +++ examples/stm32h5/build.rs | 5 + examples/stm32h5/memory.x | 5 + examples/stm32h5/src/bin/blinky.rs | 27 ++ examples/stm32h5/src/bin/button_exti.rs | 27 ++ examples/stm32h5/src/bin/eth.rs | 133 ++++++ examples/stm32h5/src/bin/i2c.rs | 44 ++ examples/stm32h5/src/bin/rng.rs | 20 + examples/stm32h5/src/bin/usart.rs | 43 ++ examples/stm32h5/src/bin/usart_dma.rs | 46 ++ examples/stm32h5/src/bin/usart_split.rs | 58 +++ examples/stm32h5/src/bin/usb_serial.rs | 128 +++++ 22 files changed, 1390 insertions(+), 21 deletions(-) create mode 100644 embassy-stm32/src/rcc/h5.rs create mode 100644 examples/stm32h5/.cargo/config.toml create mode 100644 examples/stm32h5/Cargo.toml create mode 100644 examples/stm32h5/build.rs create mode 100644 examples/stm32h5/memory.x create mode 100644 examples/stm32h5/src/bin/blinky.rs create mode 100644 examples/stm32h5/src/bin/button_exti.rs create mode 100644 examples/stm32h5/src/bin/eth.rs create mode 100644 examples/stm32h5/src/bin/i2c.rs create mode 100644 examples/stm32h5/src/bin/rng.rs create mode 100644 examples/stm32h5/src/bin/usart.rs create mode 100644 examples/stm32h5/src/bin/usart_dma.rs create mode 100644 examples/stm32h5/src/bin/usart_split.rs create mode 100644 examples/stm32h5/src/bin/usb_serial.rs diff --git a/ci.sh b/ci.sh index b9dddad3..82b72ae3 100755 --- a/ci.sh +++ b/ci.sh @@ -66,6 +66,8 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi \ @@ -87,6 +89,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \ --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \ --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \ + --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h5 \ --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \ --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \ --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index da1dc24b..3fd1e4b4 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -834,6 +834,37 @@ stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke" ] stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ] stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ] stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ] +stm32h503cb = [ "stm32-metapac/stm32h503cb" ] +stm32h503eb = [ "stm32-metapac/stm32h503eb" ] +stm32h503kb = [ "stm32-metapac/stm32h503kb" ] +stm32h503rb = [ "stm32-metapac/stm32h503rb" ] +stm32h562ag = [ "stm32-metapac/stm32h562ag" ] +stm32h562ai = [ "stm32-metapac/stm32h562ai" ] +stm32h562ig = [ "stm32-metapac/stm32h562ig" ] +stm32h562ii = [ "stm32-metapac/stm32h562ii" ] +stm32h562rg = [ "stm32-metapac/stm32h562rg" ] +stm32h562ri = [ "stm32-metapac/stm32h562ri" ] +stm32h562vg = [ "stm32-metapac/stm32h562vg" ] +stm32h562vi = [ "stm32-metapac/stm32h562vi" ] +stm32h562zg = [ "stm32-metapac/stm32h562zg" ] +stm32h562zi = [ "stm32-metapac/stm32h562zi" ] +stm32h563ag = [ "stm32-metapac/stm32h563ag" ] +stm32h563ai = [ "stm32-metapac/stm32h563ai" ] +stm32h563ig = [ "stm32-metapac/stm32h563ig" ] +stm32h563ii = [ "stm32-metapac/stm32h563ii" ] +stm32h563mi = [ "stm32-metapac/stm32h563mi" ] +stm32h563rg = [ "stm32-metapac/stm32h563rg" ] +stm32h563ri = [ "stm32-metapac/stm32h563ri" ] +stm32h563vg = [ "stm32-metapac/stm32h563vg" ] +stm32h563vi = [ "stm32-metapac/stm32h563vi" ] +stm32h563zg = [ "stm32-metapac/stm32h563zg" ] +stm32h563zi = [ "stm32-metapac/stm32h563zi" ] +stm32h573ai = [ "stm32-metapac/stm32h573ai" ] +stm32h573ii = [ "stm32-metapac/stm32h573ii" ] +stm32h573mi = [ "stm32-metapac/stm32h573mi" ] +stm32h573ri = [ "stm32-metapac/stm32h573ri" ] +stm32h573vi = [ "stm32-metapac/stm32h573vi" ] +stm32h573zi = [ "stm32-metapac/stm32h573zi" ] stm32h723ve = [ "stm32-metapac/stm32h723ve" ] stm32h723vg = [ "stm32-metapac/stm32h723vg" ] stm32h723ze = [ "stm32-metapac/stm32h723ze" ] @@ -1316,6 +1347,22 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ] stm32l562re = [ "stm32-metapac/stm32l562re" ] stm32l562ve = [ "stm32-metapac/stm32l562ve" ] stm32l562ze = [ "stm32-metapac/stm32l562ze" ] +stm32u535cb = [ "stm32-metapac/stm32u535cb" ] +stm32u535cc = [ "stm32-metapac/stm32u535cc" ] +stm32u535ce = [ "stm32-metapac/stm32u535ce" ] +stm32u535je = [ "stm32-metapac/stm32u535je" ] +stm32u535nc = [ "stm32-metapac/stm32u535nc" ] +stm32u535ne = [ "stm32-metapac/stm32u535ne" ] +stm32u535rb = [ "stm32-metapac/stm32u535rb" ] +stm32u535rc = [ "stm32-metapac/stm32u535rc" ] +stm32u535re = [ "stm32-metapac/stm32u535re" ] +stm32u535vc = [ "stm32-metapac/stm32u535vc" ] +stm32u535ve = [ "stm32-metapac/stm32u535ve" ] +stm32u545ce = [ "stm32-metapac/stm32u545ce" ] +stm32u545je = [ "stm32-metapac/stm32u545je" ] +stm32u545ne = [ "stm32-metapac/stm32u545ne" ] +stm32u545re = [ "stm32-metapac/stm32u545re" ] +stm32u545ve = [ "stm32-metapac/stm32u545ve" ] stm32u575ag = [ "stm32-metapac/stm32u575ag" ] stm32u575ai = [ "stm32-metapac/stm32u575ai" ] stm32u575cg = [ "stm32-metapac/stm32u575cg" ] @@ -1337,6 +1384,32 @@ stm32u585qi = [ "stm32-metapac/stm32u585qi" ] stm32u585ri = [ "stm32-metapac/stm32u585ri" ] stm32u585vi = [ "stm32-metapac/stm32u585vi" ] stm32u585zi = [ "stm32-metapac/stm32u585zi" ] +stm32u595ai = [ "stm32-metapac/stm32u595ai" ] +stm32u595aj = [ "stm32-metapac/stm32u595aj" ] +stm32u595qi = [ "stm32-metapac/stm32u595qi" ] +stm32u595qj = [ "stm32-metapac/stm32u595qj" ] +stm32u595ri = [ "stm32-metapac/stm32u595ri" ] +stm32u595rj = [ "stm32-metapac/stm32u595rj" ] +stm32u595vi = [ "stm32-metapac/stm32u595vi" ] +stm32u595vj = [ "stm32-metapac/stm32u595vj" ] +stm32u595zi = [ "stm32-metapac/stm32u595zi" ] +stm32u595zj = [ "stm32-metapac/stm32u595zj" ] +stm32u599bj = [ "stm32-metapac/stm32u599bj" ] +stm32u599ni = [ "stm32-metapac/stm32u599ni" ] +stm32u599nj = [ "stm32-metapac/stm32u599nj" ] +stm32u599vi = [ "stm32-metapac/stm32u599vi" ] +stm32u599vj = [ "stm32-metapac/stm32u599vj" ] +stm32u599zi = [ "stm32-metapac/stm32u599zi" ] +stm32u599zj = [ "stm32-metapac/stm32u599zj" ] +stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ] +stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ] +stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ] +stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ] +stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ] +stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ] +stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ] +stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ] +stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ] stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 61aceed9..b01e8ba4 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -50,7 +50,7 @@ fn main() { // We *shouldn't* have singletons for these, but the HAL currently requires // singletons, for using with RccPeripheral to enable/disable clocks to them. "rcc" => { - if r.version.starts_with("h7") || r.version.starts_with("f4") { + if r.version.starts_with("h5") || r.version.starts_with("h7") || r.version.starts_with("f4") { singletons.push("MCO1".to_string()); singletons.push("MCO2".to_string()); } @@ -539,7 +539,10 @@ fn main() { // MCO is special if pin.signal.starts_with("MCO_") { // Supported in H7 only for now - if regs.version.starts_with("h7") || regs.version.starts_with("f4") { + if regs.version.starts_with("h5") + || regs.version.starts_with("h7") + || regs.version.starts_with("f4") + { peri = format_ident!("{}", pin.signal.replace("_", "")); } else { continue; diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index fcb4a296..d49b1f76 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -9,7 +9,7 @@ pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; use super::*; use crate::gpio::sealed::{AFType, Pin as _}; use crate::gpio::{AnyPin, Speed}; -use crate::pac::{ETH, RCC, SYSCFG}; +use crate::pac::ETH; use crate::Peripheral; const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet @@ -60,16 +60,33 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { unsafe { // Enable the necessary Clocks // NOTE(unsafe) We have exclusive access to the registers + #[cfg(not(rcc_h5))] critical_section::with(|_| { - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - RCC.ahb1enr().modify(|w| { + crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true)); + crate::pac::RCC.ahb1enr().modify(|w| { w.set_eth1macen(true); w.set_eth1txen(true); w.set_eth1rxen(true); }); // RMII - SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); + crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); + }); + + #[cfg(rcc_h5)] + critical_section::with(|_| { + crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true)); + + crate::pac::RCC.ahb1enr().modify(|w| { + w.set_ethen(true); + w.set_ethtxen(true); + w.set_ethrxen(true); + }); + + // RMII + crate::pac::SBS + .pmcr() + .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4)); }); config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index e1ce09a4..10109e56 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -25,11 +25,11 @@ fn cpu_regs() -> pac::exti::Exti { EXTI } -#[cfg(not(any(exti_c0, exti_g0, exti_l5, gpio_v1, exti_u5)))] +#[cfg(not(any(exti_c0, exti_g0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))] fn exticr_regs() -> pac::syscfg::Syscfg { pac::SYSCFG } -#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))] +#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] fn exticr_regs() -> pac::exti::Exti { EXTI } @@ -39,9 +39,9 @@ fn exticr_regs() -> pac::afio::Afio { } pub unsafe fn on_irq() { - #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5)))] + #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] let bits = EXTI.pr(0).read().0; - #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))] + #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0; // Mask all the channels that fired. @@ -53,9 +53,9 @@ pub unsafe fn on_irq() { } // Clear pending - #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5)))] + #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] EXTI.pr(0).write_value(Lines(bits)); - #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))] + #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] { EXTI.rpr(0).write_value(Lines(bits)); EXTI.fpr(0).write_value(Lines(bits)); @@ -213,9 +213,9 @@ impl<'a> ExtiInputFuture<'a> { EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); // clear pending bit - #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5)))] + #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] EXTI.pr(0).write(|w| w.set_line(pin, true)); - #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))] + #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] { EXTI.rpr(0).write(|w| w.set_line(pin, true)); EXTI.fpr(0).write(|w| w.set_line(pin, true)); @@ -364,7 +364,7 @@ pub(crate) unsafe fn init() { foreach_exti_irq!(enable_irq); - #[cfg(not(any(rcc_wb, rcc_wl5, rcc_wle, stm32f1)))] + #[cfg(not(any(rcc_wb, rcc_wl5, rcc_wle, stm32f1, exti_h5, exti_h50)))] ::enable(); #[cfg(stm32f1)] ::enable(); diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs new file mode 100644 index 00000000..17fbc605 --- /dev/null +++ b/embassy-stm32/src/rcc/h5.rs @@ -0,0 +1,606 @@ +use core::marker::PhantomData; + +use stm32_metapac::rcc::vals::{Hpre, Ppre, Timpre}; + +use crate::pac::pwr::vals::Vos; +use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw}; +use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::{set_freqs, Clocks}; +use crate::time::Hertz; +use crate::{peripherals, Peripheral}; + +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(64_000_000); + +/// CSI speed +pub const CSI_FREQ: Hertz = Hertz(4_000_000); + +/// HSI48 speed +pub const HSI48_FREQ: Hertz = Hertz(48_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); + +const VCO_MIN: u32 = 150_000_000; +const VCO_MAX: u32 = 420_000_000; +const VCO_WIDE_MIN: u32 = 128_000_000; +const VCO_WIDE_MAX: u32 = 560_000_000; + +/// Voltage Scale +/// +/// Represents the voltage range feeding the CPU core. The maximum core +/// clock frequency depends on this value. +#[derive(Copy, Clone, PartialEq)] +pub enum VoltageScale { + /// VOS 0 range VCORE 1.30V - 1.40V + Scale0, + /// VOS 1 range VCORE 1.15V - 1.26V + Scale1, + /// VOS 2 range VCORE 1.05V - 1.15V + Scale2, + /// VOS 3 range VCORE 0.95V - 1.05V + Scale3, +} + +pub enum HseMode { + /// crystal/ceramic oscillator (HSEBYP=0) + Oscillator, + /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) + BypassAnalog, + /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) + BypassDigital, +} + +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, +} + +pub enum Hsi { + /// 64Mhz + Mhz64, + /// 32Mhz (divided by 2) + Mhz32, + /// 16Mhz (divided by 4) + Mhz16, + /// 8Mhz (divided by 8) + Mhz8, +} + +pub enum Sysclk { + /// HSI selected as sysclk + HSI, + /// HSE selected as sysclk + HSE, + /// CSI selected as sysclk + CSI, + /// PLL1_P selected as sysclk + Pll1P, +} + +pub enum PllSource { + Hsi, + Csi, + Hse, +} + +pub struct Pll { + /// Source clock selection. + pub source: PllSource, + + /// PLL pre-divider (DIVM). Must be between 1 and 63. + pub prediv: u8, + + /// PLL multiplication factor. Must be between 4 and 512. + pub mul: u16, + + /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. + /// On PLL1, it must be even (in particular, it cannot be 1.) + pub divp: Option, + /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. + pub divq: Option, + /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. + pub divr: Option, +} + +/// AHB prescaler +#[derive(Clone, Copy, PartialEq)] +pub enum AHBPrescaler { + NotDivided, + Div2, + Div4, + Div8, + Div16, + Div64, + Div128, + Div256, + Div512, +} + +impl AHBPrescaler { + fn div(&self, clk: Hertz) -> Hertz { + match self { + Self::NotDivided => clk, + Self::Div2 => clk / 2u32, + Self::Div4 => clk / 4u32, + Self::Div8 => clk / 8u32, + Self::Div16 => clk / 16u32, + Self::Div64 => clk / 64u32, + Self::Div128 => clk / 128u32, + Self::Div256 => clk / 256u32, + Self::Div512 => clk / 512u32, + } + } +} + +/// APB prescaler +#[derive(Clone, Copy)] +pub enum APBPrescaler { + NotDivided, + Div2, + Div4, + Div8, + Div16, +} + +impl APBPrescaler { + fn div(&self, clk: Hertz) -> Hertz { + match self { + Self::NotDivided => clk, + Self::Div2 => clk / 2u32, + Self::Div4 => clk / 4u32, + Self::Div8 => clk / 8u32, + Self::Div16 => clk / 16u32, + } + } + + fn div_tim(&self, clk: Hertz, tim: TimerPrescaler) -> Hertz { + match (tim, self) { + // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a + // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 + (TimerPrescaler::DefaultX2, Self::NotDivided) => clk, + (TimerPrescaler::DefaultX2, Self::Div2) => clk, + (TimerPrescaler::DefaultX2, Self::Div4) => clk / 2u32, + (TimerPrescaler::DefaultX2, Self::Div8) => clk / 4u32, + (TimerPrescaler::DefaultX2, Self::Div16) => clk / 8u32, + // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2 + // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2 + // this makes NO SENSE and is different than in the H7. Mistake in the RM?? + (TimerPrescaler::DefaultX4, Self::NotDivided) => clk * 2u32, + (TimerPrescaler::DefaultX4, Self::Div2) => clk, + (TimerPrescaler::DefaultX4, Self::Div4) => clk / 2u32, + (TimerPrescaler::DefaultX4, Self::Div8) => clk / 2u32, + (TimerPrescaler::DefaultX4, Self::Div16) => clk / 4u32, + } + } +} + +/// APB prescaler +#[derive(Clone, Copy)] +pub enum TimerPrescaler { + DefaultX2, + DefaultX4, +} + +impl From for Timpre { + fn from(value: TimerPrescaler) -> Self { + match value { + TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2, + TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4, + } + } +} + +impl From for Ppre { + fn from(val: APBPrescaler) -> Ppre { + match val { + APBPrescaler::NotDivided => Ppre::DIV1, + APBPrescaler::Div2 => Ppre::DIV2, + APBPrescaler::Div4 => Ppre::DIV4, + APBPrescaler::Div8 => Ppre::DIV8, + APBPrescaler::Div16 => Ppre::DIV16, + } + } +} + +impl From for Hpre { + fn from(val: AHBPrescaler) -> Hpre { + match val { + AHBPrescaler::NotDivided => Hpre::DIV1, + AHBPrescaler::Div2 => Hpre::DIV2, + AHBPrescaler::Div4 => Hpre::DIV4, + AHBPrescaler::Div8 => Hpre::DIV8, + AHBPrescaler::Div16 => Hpre::DIV16, + AHBPrescaler::Div64 => Hpre::DIV64, + AHBPrescaler::Div128 => Hpre::DIV128, + AHBPrescaler::Div256 => Hpre::DIV256, + AHBPrescaler::Div512 => Hpre::DIV512, + } + } +} + +/// Configuration of the core clocks +#[non_exhaustive] +pub struct Config { + pub hsi: Option, + pub hse: Option, + pub csi: bool, + pub hsi48: bool, + pub sys: Sysclk, + + pub pll1: Option, + pub pll2: Option, + #[cfg(rcc_h5)] + pub pll3: Option, + + pub ahb_pre: AHBPrescaler, + pub apb1_pre: APBPrescaler, + pub apb2_pre: APBPrescaler, + pub apb3_pre: APBPrescaler, + pub timer_prescaler: TimerPrescaler, + + pub voltage_scale: VoltageScale, +} + +impl Default for Config { + fn default() -> Self { + Self { + hsi: Some(Hsi::Mhz64), + hse: None, + csi: false, + hsi48: false, + sys: Sysclk::HSI, + pll1: None, + pll2: None, + #[cfg(rcc_h5)] + pll3: None, + + ahb_pre: AHBPrescaler::NotDivided, + apb1_pre: APBPrescaler::NotDivided, + apb2_pre: APBPrescaler::NotDivided, + apb3_pre: APBPrescaler::NotDivided, + timer_prescaler: TimerPrescaler::DefaultX2, + + voltage_scale: VoltageScale::Scale3, + } + } +} + +pub(crate) mod sealed { + pub trait McoInstance { + type Source; + unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); + } +} + +pub trait McoInstance: sealed::McoInstance + 'static {} + +pin_trait!(McoPin, McoInstance); + +macro_rules! impl_peri { + ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { + impl sealed::McoInstance for peripherals::$peri { + type Source = $source; + + unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { + RCC.cfgr().modify(|w| { + w.$set_source(source); + w.$set_prescaler(prescaler); + }); + } + } + + impl McoInstance for peripherals::$peri {} + }; +} + +impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre); +impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre); + +pub struct Mco<'d, T: McoInstance> { + phantom: PhantomData<&'d mut T>, +} + +impl<'d, T: McoInstance> Mco<'d, T> { + pub fn new( + _peri: impl Peripheral

+ 'd, + _pin: impl Peripheral

> + 'd, + _source: T::Source, + ) -> Self { + todo!(); + } +} + +pub(crate) unsafe fn init(config: Config) { + let (vos, max_clk) = match config.voltage_scale { + VoltageScale::Scale0 => (Vos::SCALE0, Hertz(250_000_000)), + VoltageScale::Scale1 => (Vos::SCALE1, Hertz(200_000_000)), + VoltageScale::Scale2 => (Vos::SCALE2, Hertz(150_000_000)), + VoltageScale::Scale3 => (Vos::SCALE3, Hertz(100_000_000)), + }; + + // Configure voltage scale. + PWR.voscr().modify(|w| w.set_vos(vos)); + while !PWR.vossr().read().vosrdy() {} + + // Configure HSI + let hsi = match config.hsi { + None => { + RCC.cr().modify(|w| w.set_hsion(false)); + None + } + Some(hsi) => { + let (freq, hsidiv) = match hsi { + Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1), + Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2), + Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4), + Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8), + }; + RCC.cr().modify(|w| { + w.set_hsidiv(hsidiv); + w.set_hsion(true); + }); + while !RCC.cr().read().hsirdy() {} + Some(freq) + } + }; + + // Configure HSE + let hse = match config.hse { + None => { + RCC.cr().modify(|w| w.set_hseon(false)); + None + } + Some(hse) => { + let (byp, ext) = match hse.mode { + HseMode::Oscillator => (false, Hseext::ANALOG), + HseMode::BypassAnalog => (true, Hseext::ANALOG), + HseMode::BypassDigital => (true, Hseext::DIGITAL), + }; + + RCC.cr().modify(|w| { + w.set_hsebyp(byp); + w.set_hseext(ext); + }); + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + Some(hse.freq) + } + }; + + // Configure HSI48. + RCC.cr().modify(|w| w.set_hsi48on(config.hsi48)); + let _hsi48 = match config.hsi48 { + false => None, + true => { + while !RCC.cr().read().hsi48rdy() {} + Some(CSI_FREQ) + } + }; + + // Configure CSI. + RCC.cr().modify(|w| w.set_csion(config.csi)); + let csi = match config.csi { + false => None, + true => { + while !RCC.cr().read().csirdy() {} + Some(CSI_FREQ) + } + }; + + // Configure PLLs. + let pll_input = PllInput { csi, hse, hsi }; + let pll1 = init_pll(0, config.pll1, &pll_input); + let _pll2 = init_pll(1, config.pll2, &pll_input); + #[cfg(rcc_h5)] + let _pll3 = init_pll(2, config.pll3, &pll_input); + + // Configure sysclk + let (sys, sw) = match config.sys { + Sysclk::HSI => (unwrap!(hsi), Sw::HSI), + Sysclk::HSE => (unwrap!(hse), Sw::HSE), + Sysclk::CSI => (unwrap!(csi), Sw::CSI), + Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1), + }; + assert!(sys <= max_clk); + + let hclk = config.ahb_pre.div(sys); + + let apb1 = config.apb1_pre.div(hclk); + let apb1_tim = config.apb1_pre.div_tim(hclk, config.timer_prescaler); + let apb2 = config.apb2_pre.div(hclk); + let apb2_tim = config.apb2_pre.div_tim(hclk, config.timer_prescaler); + let apb3 = config.apb3_pre.div(hclk); + + flash_setup(hclk, config.voltage_scale); + + // Set hpre + let hpre = config.ahb_pre.into(); + RCC.cfgr2().modify(|w| w.set_hpre(hpre)); + while RCC.cfgr2().read().hpre() != hpre {} + + // set ppre + RCC.cfgr2().modify(|w| { + w.set_ppre1(config.apb1_pre.into()); + w.set_ppre2(config.apb2_pre.into()); + w.set_ppre3(config.apb3_pre.into()); + }); + + RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); + + RCC.cfgr().modify(|w| w.set_sw(sw)); + while RCC.cfgr().read().sws() != sw {} + + set_freqs(Clocks { + sys, + ahb1: hclk, + ahb2: hclk, + ahb3: hclk, + ahb4: hclk, + apb1, + apb2, + apb3, + apb1_tim, + apb2_tim, + adc: None, + }); +} + +struct PllInput { + hsi: Option, + hse: Option, + csi: Option, +} + +struct PllOutput { + p: Option, + #[allow(dead_code)] + q: Option, + #[allow(dead_code)] + r: Option, +} + +unsafe fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { + let Some(config) = config else { + // Stop PLL + RCC.cr().modify(|w| w.set_pllon(num, false)); + while RCC.cr().read().pllrdy(num) {} + + // "To save power when PLL1 is not used, the value of PLL1M must be set to 0."" + RCC.pllcfgr(num).write(|w| { + w.set_divm(0); + }); + + return PllOutput{ + p: None, + q: None, + r: None, + } + }; + + assert!(1 <= config.prediv && config.prediv <= 63); + assert!(4 <= config.mul && config.mul <= 512); + + let (in_clk, src) = match config.source { + PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI), + PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE), + PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI), + }; + + let ref_clk = in_clk / config.prediv as u32; + + let ref_range = match ref_clk.0 { + ..=1_999_999 => Pllrge::RANGE1, + ..=3_999_999 => Pllrge::RANGE2, + ..=7_999_999 => Pllrge::RANGE4, + ..=16_000_000 => Pllrge::RANGE8, + x => panic!("pll ref_clk out of range: {} mhz", x), + }; + + // The smaller range (150 to 420 MHz) must + // be chosen when the reference clock frequency is lower than 2 MHz. + let wide_allowed = ref_range != Pllrge::RANGE1; + + let vco_clk = ref_clk * config.mul; + let vco_range = match vco_clk.0 { + VCO_MIN..=VCO_MAX => Pllvcosel::MEDIUMVCO, + VCO_WIDE_MIN..=VCO_WIDE_MAX if wide_allowed => Pllvcosel::WIDEVCO, + x => panic!("pll vco_clk out of range: {} mhz", x), + }; + + let p = config.divp.map(|div| { + assert!(1 <= div && div <= 128); + if num == 0 { + // on PLL1, DIVP must be even. + assert!(div % 2 == 0); + } + + vco_clk / div + }); + let q = config.divq.map(|div| { + assert!(1 <= div && div <= 128); + vco_clk / div + }); + let r = config.divr.map(|div| { + assert!(1 <= div && div <= 128); + vco_clk / div + }); + + RCC.pllcfgr(num).write(|w| { + w.set_pllsrc(src); + w.set_divm(config.prediv); + w.set_pllvcosel(vco_range); + w.set_pllrge(ref_range); + w.set_pllfracen(false); + w.set_pllpen(p.is_some()); + w.set_pllqen(q.is_some()); + w.set_pllren(r.is_some()); + }); + RCC.plldivr(num).write(|w| { + w.set_plln(config.mul - 1); + w.set_pllp((config.divp.unwrap_or(1) - 1) as u8); + w.set_pllq((config.divq.unwrap_or(1) - 1) as u8); + w.set_pllr((config.divr.unwrap_or(1) - 1) as u8); + }); + + RCC.cr().modify(|w| w.set_pllon(num, true)); + while !RCC.cr().read().pllrdy(num) {} + + PllOutput { p, q, r } +} + +fn flash_setup(clk: Hertz, vos: VoltageScale) { + // RM0481 Rev 1, table 37 + // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0 + // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz + // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz + // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz + // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz + // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz + // 5 2 170 to 200 MHz 210 to 250 MHz + + // See RM0433 Rev 7 Table 17. FLASH recommended number of wait + // states and programming delay + let (latency, wrhighfreq) = match (vos, clk.0) { + (VoltageScale::Scale0, ..=42_000_000) => (0, 0), + (VoltageScale::Scale0, ..=84_000_000) => (1, 0), + (VoltageScale::Scale0, ..=126_000_000) => (2, 1), + (VoltageScale::Scale0, ..=168_000_000) => (3, 1), + (VoltageScale::Scale0, ..=210_000_000) => (4, 2), + (VoltageScale::Scale0, ..=250_000_000) => (5, 2), + + (VoltageScale::Scale1, ..=34_000_000) => (0, 0), + (VoltageScale::Scale1, ..=68_000_000) => (1, 0), + (VoltageScale::Scale1, ..=102_000_000) => (2, 1), + (VoltageScale::Scale1, ..=136_000_000) => (3, 1), + (VoltageScale::Scale1, ..=170_000_000) => (4, 2), + (VoltageScale::Scale1, ..=200_000_000) => (5, 2), + + (VoltageScale::Scale2, ..=30_000_000) => (0, 0), + (VoltageScale::Scale2, ..=60_000_000) => (1, 0), + (VoltageScale::Scale2, ..=90_000_000) => (2, 1), + (VoltageScale::Scale2, ..=120_000_000) => (3, 1), + (VoltageScale::Scale2, ..=150_000_000) => (4, 2), + + (VoltageScale::Scale3, ..=20_000_000) => (0, 0), + (VoltageScale::Scale3, ..=40_000_000) => (1, 0), + (VoltageScale::Scale3, ..=60_000_000) => (2, 1), + (VoltageScale::Scale3, ..=80_000_000) => (3, 1), + (VoltageScale::Scale3, ..=100_000_000) => (4, 2), + + _ => unreachable!(), + }; + + defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); + + // NOTE(unsafe) Atomic write + unsafe { + FLASH.acr().write(|w| { + w.set_wrhighfreq(wrhighfreq); + w.set_latency(latency); + }); + while FLASH.acr().read().latency() != latency {} + } +} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index d4bd3d6b..d6a31f17 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -21,6 +21,7 @@ use crate::time::Hertz; #[cfg_attr(rcc_u5, path = "u5.rs")] #[cfg_attr(rcc_wb, path = "wb.rs")] #[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] +#[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")] mod _version; pub use _version::*; @@ -36,7 +37,7 @@ pub struct Clocks { pub apb2: Hertz, #[cfg(not(any(rcc_c0, rcc_g0)))] pub apb2_tim: Hertz, - #[cfg(any(rcc_wl5, rcc_wle, rcc_u5))] + #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_u5))] pub apb3: Hertz, #[cfg(any(rcc_h7, rcc_h7ab))] pub apb4: Hertz, @@ -44,14 +45,16 @@ pub struct Clocks { // AHB pub ahb1: Hertz, #[cfg(any( - rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, rcc_wl5, rcc_wle + rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, + rcc_wl5, rcc_wle ))] pub ahb2: Hertz, #[cfg(any( - rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5, rcc_wle + rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5, + rcc_wle ))] pub ahb3: Hertz, - #[cfg(any(rcc_h7, rcc_h7ab))] + #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] pub ahb4: Hertz, #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] @@ -60,7 +63,7 @@ pub struct Clocks { #[cfg(stm32f1)] pub adc: Hertz, - #[cfg(any(rcc_h7, rcc_h7ab))] + #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] pub adc: Option, } diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs index 975517a4..f08abe33 100644 --- a/embassy-stm32/src/time.rs +++ b/embassy-stm32/src/time.rs @@ -1,7 +1,9 @@ //! Time units +use core::ops::{Div, Mul}; + /// Hertz -#[derive(PartialEq, PartialOrd, Clone, Copy, Debug, Eq)] +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Hertz(pub u32); @@ -33,3 +35,45 @@ pub fn khz(kilohertz: u32) -> Hertz { pub fn mhz(megahertz: u32) -> Hertz { Hertz::mhz(megahertz) } + +impl Mul for Hertz { + type Output = Hertz; + fn mul(self, rhs: u32) -> Self::Output { + Hertz(self.0 * rhs) + } +} + +impl Div for Hertz { + type Output = Hertz; + fn div(self, rhs: u32) -> Self::Output { + Hertz(self.0 / rhs) + } +} + +impl Mul for Hertz { + type Output = Hertz; + fn mul(self, rhs: u16) -> Self::Output { + self * (rhs as u32) + } +} + +impl Div for Hertz { + type Output = Hertz; + fn div(self, rhs: u16) -> Self::Output { + self / (rhs as u32) + } +} + +impl Mul for Hertz { + type Output = Hertz; + fn mul(self, rhs: u8) -> Self::Output { + self * (rhs as u32) + } +} + +impl Div for Hertz { + type Output = Hertz; + fn div(self, rhs: u8) -> Self::Output { + self / (rhs as u32) + } +} diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index e6ee3954..ad68eaba 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -186,6 +186,11 @@ impl<'d, T: Instance> Driver<'d, T> { crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); } + #[cfg(pwr_h5)] + unsafe { + crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)) + } + unsafe { ::enable(); ::reset(); diff --git a/examples/stm32h5/.cargo/config.toml b/examples/stm32h5/.cargo/config.toml new file mode 100644 index 00000000..c8b864b6 --- /dev/null +++ b/examples/stm32h5/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.thumbv8m.main-none-eabihf] +runner = 'probe-rs-cli run --chip STM32H563ZITx' + +[build] +target = "thumbv8m.main-none-eabihf" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml new file mode 100644 index 00000000..70702863 --- /dev/null +++ b/examples/stm32h5/Cargo.toml @@ -0,0 +1,71 @@ +[package] +edition = "2021" +name = "embassy-stm32h7-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } +embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } +embedded-io = { version = "0.4.0", features = ["async"] } +embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } +embedded-hal-async = { version = "=0.2.0-alpha.0" } +embedded-nal-async = "0.4.0" +panic-probe = { version = "0.3", features = ["print-defmt"] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +heapless = { version = "0.7.5", default-features = false } +rand_core = "0.6.3" +critical-section = "1.1" +micromath = "2.0.0" +stm32-fmc = "0.2.4" +embedded-storage = "0.3.0" +static_cell = "1.0" + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- diff --git a/examples/stm32h5/build.rs b/examples/stm32h5/build.rs new file mode 100644 index 00000000..8cd32d7e --- /dev/null +++ b/examples/stm32h5/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32h5/memory.x b/examples/stm32h5/memory.x new file mode 100644 index 00000000..45606150 --- /dev/null +++ b/examples/stm32h5/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 0x200000 + RAM : ORIGIN = 0x20000000, LENGTH = 0x50000 +} diff --git a/examples/stm32h5/src/bin/blinky.rs b/examples/stm32h5/src/bin/blinky.rs new file mode 100644 index 00000000..f9bf90d2 --- /dev/null +++ b/examples/stm32h5/src/bin/blinky.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut led = Output::new(p.PB0, Level::High, Speed::Low); + + loop { + info!("high"); + led.set_high(); + Timer::after(Duration::from_millis(500)).await; + + info!("low"); + led.set_low(); + Timer::after(Duration::from_millis(500)).await; + } +} diff --git a/examples/stm32h5/src/bin/button_exti.rs b/examples/stm32h5/src/bin/button_exti.rs new file mode 100644 index 00000000..dfe587d4 --- /dev/null +++ b/examples/stm32h5/src/bin/button_exti.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::{Input, Pull}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let button = Input::new(p.PC13, Pull::Down); + let mut button = ExtiInput::new(button, p.EXTI13); + + info!("Press the USER button..."); + + loop { + button.wait_for_rising_edge().await; + info!("Pressed!"); + button.wait_for_falling_edge().await; + info!("Released!"); + } +} diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs new file mode 100644 index 00000000..6d650da9 --- /dev/null +++ b/examples/stm32h5/src/bin/eth.rs @@ -0,0 +1,133 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_net::tcp::TcpSocket; +use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_stm32::eth::generic_smi::GenericSMI; +use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::peripherals::ETH; +use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale}; +use embassy_stm32::rng::Rng; +use embassy_stm32::time::Hertz; +use embassy_stm32::{interrupt, Config}; +use embassy_time::{Duration, Timer}; +use embedded_io::asynch::Write; +use rand_core::RngCore; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +macro_rules! singleton { + ($val:expr) => {{ + type T = impl Sized; + static STATIC_CELL: StaticCell = StaticCell::new(); + let (x,) = STATIC_CELL.init(($val,)); + x + }}; +} + +type Device = Ethernet<'static, ETH, GenericSMI>; + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack) -> ! { + stack.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) -> ! { + let mut config = Config::default(); + config.rcc.hsi = None; + config.rcc.hsi48 = true; // needed for rng + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::BypassDigital, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::Hse, + prediv: 2, + mul: 125, + divp: Some(2), + divq: Some(2), + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::NotDivided; + config.rcc.apb1_pre = APBPrescaler::NotDivided; + config.rcc.apb2_pre = APBPrescaler::NotDivided; + config.rcc.apb3_pre = APBPrescaler::NotDivided; + config.rcc.sys = Sysclk::Pll1P; + config.rcc.voltage_scale = VoltageScale::Scale0; + let p = embassy_stm32::init(config); + info!("Hello World!"); + + // Generate random seed. + let mut rng = Rng::new(p.RNG); + let mut seed = [0; 8]; + rng.fill_bytes(&mut seed); + let seed = u64::from_le_bytes(seed); + + let eth_int = interrupt::take!(ETH); + let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + + let device = Ethernet::new( + singleton!(PacketQueue::<4, 4>::new()), + p.ETH, + eth_int, + p.PA1, + p.PA2, + p.PC1, + p.PA7, + p.PC4, + p.PC5, + p.PG13, + p.PB15, + p.PG11, + GenericSMI, + mac_addr, + 0, + ); + + let config = embassy_net::Config::Dhcp(Default::default()); + //let config = embassy_net::Config::Static(embassy_net::StaticConfig { + // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), + // dns_servers: Vec::new(), + // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), + //}); + + // Init network stack + let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); + + // Launch network task + unwrap!(spawner.spawn(net_task(&stack))); + + info!("Network task initialized"); + + // Then we can use it! + let mut rx_buffer = [0; 1024]; + let mut tx_buffer = [0; 1024]; + + loop { + let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); + + socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); + + let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000); + info!("connecting..."); + let r = socket.connect(remote_endpoint).await; + if let Err(e) = r { + info!("connect error: {:?}", e); + Timer::after(Duration::from_secs(3)).await; + continue; + } + info!("connected!"); + loop { + let r = socket.write_all(b"Hello\n").await; + if let Err(e) = r { + info!("write error: {:?}", e); + continue; + } + Timer::after(Duration::from_secs(1)).await; + } + } +} diff --git a/examples/stm32h5/src/bin/i2c.rs b/examples/stm32h5/src/bin/i2c.rs new file mode 100644 index 00000000..6cbf58bb --- /dev/null +++ b/examples/stm32h5/src/bin/i2c.rs @@ -0,0 +1,44 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; +use embassy_stm32::interrupt; +use embassy_stm32::time::Hertz; +use embassy_time::Duration; +use {defmt_rtt as _, panic_probe as _}; + +const ADDRESS: u8 = 0x5F; +const WHOAMI: u8 = 0x0F; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello world!"); + let p = embassy_stm32::init(Default::default()); + + let irq = interrupt::take!(I2C2_EV); + let mut i2c = I2c::new( + p.I2C2, + p.PB10, + p.PB11, + irq, + p.GPDMA1_CH4, + p.GPDMA1_CH5, + Hertz(100_000), + Default::default(), + ); + + // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long. + // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay. + let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000)); + + let mut data = [0u8; 1]; + + match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { + Ok(()) => info!("Whoami: {}", data[0]), + Err(Error::Timeout) => error!("Operation timed out"), + Err(e) => error!("I2c Error: {:?}", e), + } +} diff --git a/examples/stm32h5/src/bin/rng.rs b/examples/stm32h5/src/bin/rng.rs new file mode 100644 index 00000000..af9be0b6 --- /dev/null +++ b/examples/stm32h5/src/bin/rng.rs @@ -0,0 +1,20 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::rng::Rng; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut rng = Rng::new(p.RNG); + + let mut buf = [0u8; 16]; + unwrap!(rng.async_fill_bytes(&mut buf).await); + info!("random bytes: {:02x}", buf); +} diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs new file mode 100644 index 00000000..405f18ec --- /dev/null +++ b/examples/stm32h5/src/bin/usart.rs @@ -0,0 +1,43 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; +use embassy_stm32::usart::{Config, Uart}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn main_task() { + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let irq = interrupt::take!(UART7); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config); + + unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + loop { + unwrap!(usart.blocking_read(&mut buf)); + unwrap!(usart.blocking_write(&buf)); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs new file mode 100644 index 00000000..43d791aa --- /dev/null +++ b/examples/stm32h5/src/bin/usart_dma.rs @@ -0,0 +1,46 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use core::fmt::Write; + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; +use embassy_stm32::usart::{Config, Uart}; +use heapless::String; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn main_task() { + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let irq = interrupt::take!(UART7); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.GPDMA1_CH0, NoDma, config); + + for n in 0u32.. { + let mut s: String<128> = String::new(); + core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); + + usart.write(s.as_bytes()).await.ok(); + + info!("wrote DMA"); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs new file mode 100644 index 00000000..16a49958 --- /dev/null +++ b/examples/stm32h5/src/bin/usart_split.rs @@ -0,0 +1,58 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; +use embassy_stm32::peripherals::{GPDMA1_CH1, UART7}; +use embassy_stm32::usart::{Config, Uart, UartRx}; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::channel::Channel; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) { + unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + loop { + unwrap!(usart.blocking_read(&mut buf)); + unwrap!(usart.blocking_write(&buf)); + } +} + +static CHANNEL: Channel = Channel::new(); + +#[embassy_executor::main] +async fn main(spawner: Spawner) -> ! { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let config = Config::default(); + let irq = interrupt::take!(UART7); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.GPDMA1_CH0, p.GPDMA1_CH1, config); + unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); + + let (mut tx, rx) = usart.split(); + + unwrap!(spawner.spawn(reader(rx))); + + loop { + let buf = CHANNEL.recv().await; + info!("writing..."); + unwrap!(tx.write(&buf).await); + } +} + +#[embassy_executor::task] +async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) { + let mut buf = [0; 8]; + loop { + info!("reading..."); + unwrap!(rx.read(&mut buf).await); + CHANNEL.send(buf).await; + } +} diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs new file mode 100644 index 00000000..6af269c1 --- /dev/null +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -0,0 +1,128 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{panic, *}; +use embassy_executor::Spawner; +use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale}; +use embassy_stm32::time::Hertz; +use embassy_stm32::usb::{Driver, Instance}; +use embassy_stm32::{interrupt, pac, Config}; +use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; +use embassy_usb::driver::EndpointError; +use embassy_usb::Builder; +use futures::future::join; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.rcc.hsi = None; + config.rcc.hsi48 = true; // needed for usb + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::BypassDigital, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::Hse, + prediv: 2, + mul: 125, + divp: Some(2), // 250mhz + divq: None, + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::Div2; + config.rcc.apb1_pre = APBPrescaler::Div4; + config.rcc.apb2_pre = APBPrescaler::Div2; + config.rcc.apb3_pre = APBPrescaler::Div4; + config.rcc.sys = Sysclk::Pll1P; + config.rcc.voltage_scale = VoltageScale::Scale0; + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + unsafe { + pac::RCC.ccipr4().write(|w| { + w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); + }); + } + + // Create the driver, from the HAL. + let irq = interrupt::take!(USB_DRD_FS); + let driver = Driver::new(p.USB, irq, p.PA12, p.PA11); + + // Create embassy-usb Config + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-serial example"); + config.serial_number = Some("12345678"); + + // Required for windows compatiblity. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + &mut control_buf, + ); + + // Create classes on the builder. + let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Do stuff with the class! + let echo_fut = async { + loop { + class.wait_connection().await; + info!("Connected"); + let _ = echo(&mut class).await; + info!("Disconnected"); + } + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, echo_fut).await; +} + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = class.read_packet(&mut buf).await?; + let data = &buf[..n]; + info!("data: {:x}", data); + class.write_packet(data).await?; + } +} From e2516bba09fbb99da95939656e172156ad1924fc Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 6 Apr 2023 22:39:27 +0200 Subject: [PATCH 67/78] executor: fix doc features. --- embassy-executor/Cargo.toml | 19 ++++++++----------- rust-toolchain.toml | 1 + 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index bb8a46c8..29e1bd47 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -14,21 +14,18 @@ categories = [ [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" -features = ["nightly", "defmt"] +features = ["nightly", "defmt", "pender-callback"] flavors = [ - { name = "std", target = "x86_64-unknown-linux-gnu", features = ["std"] }, - { name = "wasm", target = "wasm32-unknown-unknown", features = ["wasm"] }, - { name = "thumbv6m-none-eabi", target = "thumbv6m-none-eabi", features = [] }, - { name = "thumbv7m-none-eabi", target = "thumbv7m-none-eabi", features = [] }, - { name = "thumbv7em-none-eabi", target = "thumbv7em-none-eabi", features = [] }, - { name = "thumbv7em-none-eabihf", target = "thumbv7em-none-eabihf", features = [] }, - { name = "thumbv8m.base-none-eabi", target = "thumbv8m.base-none-eabi", features = [] }, - { name = "thumbv8m.main-none-eabi", target = "thumbv8m.main-none-eabi", features = [] }, - { name = "thumbv8m.main-none-eabihf", target = "thumbv8m.main-none-eabihf", features = [] }, + { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] }, + { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] }, + { name = "cortex-m", target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }, + { name = "riscv32", target = "riscv32imac-unknown-none-elf", features = ["arch-riscv32", "executor-thread"] }, ] [package.metadata.docs.rs] -features = ["std", "nightly", "defmt"] +default-target = "thumbv7em-none-eabi" +targets = ["thumbv7em-none-eabi"] +features = ["nightly", "defmt", "pender-callback", "arch-cortex-m", "executor-thread", "executor-interrupt"] [features] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 22abacde..9785cd9e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -9,5 +9,6 @@ targets = [ "thumbv6m-none-eabi", "thumbv7em-none-eabihf", "thumbv8m.main-none-eabihf", + "riscv32imac-unknown-none-elf", "wasm32-unknown-unknown", ] From be37eee13dbd7833e0d74ea57d31d3e5c58cd47f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 6 Apr 2023 22:25:24 +0200 Subject: [PATCH 68/78] Update embedded-hal crates. --- embassy-embedded-hal/Cargo.toml | 4 +- embassy-embedded-hal/src/adapter.rs | 27 ++- embassy-embedded-hal/src/lib.rs | 2 +- .../src/shared_bus/asynch/i2c.rs | 42 ++--- .../src/shared_bus/asynch/spi.rs | 175 +++++++++++++++--- .../src/shared_bus/blocking/i2c.rs | 56 ------ .../src/shared_bus/blocking/spi.rs | 157 +++++++++++++--- embassy-lora/Cargo.toml | 4 +- embassy-nrf/Cargo.toml | 4 +- embassy-nrf/src/twim.rs | 49 ++--- embassy-rp/Cargo.toml | 6 +- embassy-rp/src/i2c.rs | 107 +++-------- embassy-rp/src/spi.rs | 1 + embassy-stm32/Cargo.toml | 6 +- embassy-stm32/src/i2c/timeout.rs | 75 +++----- embassy-stm32/src/i2c/v1.rs | 73 +++----- embassy-stm32/src/i2c/v2.rs | 158 +++++++--------- embassy-time/Cargo.toml | 4 +- embassy-time/src/delay.rs | 20 +- examples/rp/.cargo/config.toml | 2 +- examples/rp/Cargo.toml | 5 +- examples/rp/src/bin/spi_display.rs | 158 ++++------------ examples/stm32f1/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 4 +- examples/stm32h7/Cargo.toml | 4 +- examples/stm32l4/Cargo.toml | 4 +- tests/rp/Cargo.toml | 4 +- tests/stm32/Cargo.toml | 4 +- 28 files changed, 543 insertions(+), 614 deletions(-) diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 45eb0d43..c509d6ee 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -19,8 +19,8 @@ nightly = ["embedded-hal-async", "embedded-storage-async"] [dependencies] embassy-sync = { version = "0.1.0", path = "../embassy-sync" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } -embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } +embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true } embedded-storage = "0.3.0" embedded-storage-async = { version = "0.4.0", optional = true } nb = "1.0.0" diff --git a/embassy-embedded-hal/src/adapter.rs b/embassy-embedded-hal/src/adapter.rs index a49f8df4..ee919bd8 100644 --- a/embassy-embedded-hal/src/adapter.rs +++ b/embassy-embedded-hal/src/adapter.rs @@ -36,27 +36,22 @@ where E: embedded_hal_1::i2c::Error + 'static, T: blocking::i2c::WriteRead + blocking::i2c::Read + blocking::i2c::Write, { - async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), Self::Error> { - self.wrapped.read(address, buffer) + async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { + self.wrapped.read(address, read) } - async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), Self::Error> { - self.wrapped.write(address, bytes) + async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { + self.wrapped.write(address, write) } - async fn write_read<'a>( - &'a mut self, + async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.wrapped.write_read(address, write, read) + } + + async fn transaction( + &mut self, address: u8, - bytes: &'a [u8], - buffer: &'a mut [u8], - ) -> Result<(), Self::Error> { - self.wrapped.write_read(address, bytes, buffer) - } - - async fn transaction<'a, 'b>( - &'a mut self, - address: u8, - operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], + operations: &mut [embedded_hal_1::i2c::Operation<'_>], ) -> Result<(), Self::Error> { let _ = address; let _ = operations; diff --git a/embassy-embedded-hal/src/lib.rs b/embassy-embedded-hal/src/lib.rs index 8da04222..a23fbdc4 100644 --- a/embassy-embedded-hal/src/lib.rs +++ b/embassy-embedded-hal/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr( feature = "nightly", - feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections) + feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections, try_blocks) )] #![cfg_attr(feature = "nightly", allow(incomplete_features))] #![warn(missing_docs)] diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs index c5e1fd41..82955404 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs @@ -54,35 +54,35 @@ where M: RawMutex + 'static, BUS: i2c::I2c + 'static, { - async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), I2cDeviceError> { + async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), I2cDeviceError> { let mut bus = self.bus.lock().await; - bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?; + bus.read(address, read).await.map_err(I2cDeviceError::I2c)?; Ok(()) } - async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), I2cDeviceError> { + async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), I2cDeviceError> { let mut bus = self.bus.lock().await; - bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?; + bus.write(address, write).await.map_err(I2cDeviceError::I2c)?; Ok(()) } - async fn write_read<'a>( - &'a mut self, + async fn write_read( + &mut self, address: u8, - wr_buffer: &'a [u8], - rd_buffer: &'a mut [u8], + write: &[u8], + read: &mut [u8], ) -> Result<(), I2cDeviceError> { let mut bus = self.bus.lock().await; - bus.write_read(address, wr_buffer, rd_buffer) + bus.write_read(address, write, read) .await .map_err(I2cDeviceError::I2c)?; Ok(()) } - async fn transaction<'a, 'b>( - &'a mut self, + async fn transaction( + &mut self, address: u8, - operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], + operations: &mut [embedded_hal_async::i2c::Operation<'_>], ) -> Result<(), I2cDeviceError> { let _ = address; let _ = operations; @@ -121,25 +121,25 @@ where M: RawMutex + 'static, BUS: i2c::I2c + SetConfig + 'static, { - async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), I2cDeviceError> { + async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cDeviceError> { let mut bus = self.bus.lock().await; bus.set_config(&self.config); bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?; Ok(()) } - async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), I2cDeviceError> { + async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), I2cDeviceError> { let mut bus = self.bus.lock().await; bus.set_config(&self.config); bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?; Ok(()) } - async fn write_read<'a>( - &'a mut self, + async fn write_read( + &mut self, address: u8, - wr_buffer: &'a [u8], - rd_buffer: &'a mut [u8], + wr_buffer: &[u8], + rd_buffer: &mut [u8], ) -> Result<(), I2cDeviceError> { let mut bus = self.bus.lock().await; bus.set_config(&self.config); @@ -149,11 +149,7 @@ where Ok(()) } - async fn transaction<'a, 'b>( - &'a mut self, - address: u8, - operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], - ) -> Result<(), I2cDeviceError> { + async fn transaction(&mut self, address: u8, operations: &mut [i2c::Operation<'_>]) -> Result<(), Self::Error> { let _ = address; let _ = operations; todo!() diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs index d2571665..b5549a6c 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs @@ -25,12 +25,11 @@ //! let spi_dev2 = SpiDevice::new(spi_bus, cs_pin2); //! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128); //! ``` -use core::future::Future; use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::mutex::Mutex; use embedded_hal_1::digital::OutputPin; -use embedded_hal_1::spi::ErrorType; +use embedded_hal_1::spi::Operation; use embedded_hal_async::spi; use crate::shared_bus::SpiDeviceError; @@ -57,33 +56,92 @@ where type Error = SpiDeviceError; } -unsafe impl spi::SpiDevice for SpiDevice<'_, M, BUS, CS> +impl spi::SpiDeviceRead for SpiDevice<'_, M, BUS, CS> where - M: RawMutex + 'static, - BUS: spi::SpiBusFlush + 'static, + M: RawMutex, + BUS: spi::SpiBusRead, CS: OutputPin, { - type Bus = BUS; - - async fn transaction(&mut self, f: F) -> Result - where - F: FnOnce(*mut Self::Bus) -> Fut, - Fut: Future::Error>>, - { + async fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> { let mut bus = self.bus.lock().await; self.cs.set_low().map_err(SpiDeviceError::Cs)?; - let f_res = f(&mut *bus).await; + let op_res: Result<(), BUS::Error> = try { + for buf in operations { + bus.read(buf).await?; + } + }; // On failure, it's important to still flush and deassert CS. let flush_res = bus.flush().await; let cs_res = self.cs.set_high(); - let f_res = f_res.map_err(SpiDeviceError::Spi)?; + let op_res = op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; cs_res.map_err(SpiDeviceError::Cs)?; - Ok(f_res) + Ok(op_res) + } +} + +impl spi::SpiDeviceWrite for SpiDevice<'_, M, BUS, CS> +where + M: RawMutex, + BUS: spi::SpiBusWrite, + CS: OutputPin, +{ + async fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> { + let mut bus = self.bus.lock().await; + self.cs.set_low().map_err(SpiDeviceError::Cs)?; + + let op_res: Result<(), BUS::Error> = try { + for buf in operations { + bus.write(buf).await?; + } + }; + + // On failure, it's important to still flush and deassert CS. + let flush_res = bus.flush().await; + let cs_res = self.cs.set_high(); + + let op_res = op_res.map_err(SpiDeviceError::Spi)?; + flush_res.map_err(SpiDeviceError::Spi)?; + cs_res.map_err(SpiDeviceError::Cs)?; + + Ok(op_res) + } +} + +impl spi::SpiDevice for SpiDevice<'_, M, BUS, CS> +where + M: RawMutex, + BUS: spi::SpiBus, + CS: OutputPin, +{ + async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> { + let mut bus = self.bus.lock().await; + self.cs.set_low().map_err(SpiDeviceError::Cs)?; + + let op_res: Result<(), BUS::Error> = try { + for op in operations { + match op { + Operation::Read(buf) => bus.read(buf).await?, + Operation::Write(buf) => bus.write(buf).await?, + Operation::Transfer(read, write) => bus.transfer(read, write).await?, + Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await?, + } + } + }; + + // On failure, it's important to still flush and deassert CS. + let flush_res = bus.flush().await; + let cs_res = self.cs.set_high(); + + let op_res = op_res.map_err(SpiDeviceError::Spi)?; + flush_res.map_err(SpiDeviceError::Spi)?; + cs_res.map_err(SpiDeviceError::Cs)?; + + Ok(op_res) } } @@ -114,33 +172,94 @@ where type Error = SpiDeviceError; } -unsafe impl spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> +impl spi::SpiDeviceWrite for SpiDeviceWithConfig<'_, M, BUS, CS> where - M: RawMutex + 'static, - BUS: spi::SpiBusFlush + SetConfig + 'static, + M: RawMutex, + BUS: spi::SpiBusWrite + SetConfig, CS: OutputPin, { - type Bus = BUS; - - async fn transaction(&mut self, f: F) -> Result - where - F: FnOnce(*mut Self::Bus) -> Fut, - Fut: Future::Error>>, - { + async fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> { let mut bus = self.bus.lock().await; bus.set_config(&self.config); self.cs.set_low().map_err(SpiDeviceError::Cs)?; - let f_res = f(&mut *bus).await; + let op_res: Result<(), BUS::Error> = try { + for buf in operations { + bus.write(buf).await?; + } + }; // On failure, it's important to still flush and deassert CS. let flush_res = bus.flush().await; let cs_res = self.cs.set_high(); - let f_res = f_res.map_err(SpiDeviceError::Spi)?; + let op_res = op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; cs_res.map_err(SpiDeviceError::Cs)?; - Ok(f_res) + Ok(op_res) + } +} + +impl spi::SpiDeviceRead for SpiDeviceWithConfig<'_, M, BUS, CS> +where + M: RawMutex, + BUS: spi::SpiBusRead + SetConfig, + CS: OutputPin, +{ + async fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> { + let mut bus = self.bus.lock().await; + bus.set_config(&self.config); + self.cs.set_low().map_err(SpiDeviceError::Cs)?; + + let op_res: Result<(), BUS::Error> = try { + for buf in operations { + bus.read(buf).await?; + } + }; + + // On failure, it's important to still flush and deassert CS. + let flush_res = bus.flush().await; + let cs_res = self.cs.set_high(); + + let op_res = op_res.map_err(SpiDeviceError::Spi)?; + flush_res.map_err(SpiDeviceError::Spi)?; + cs_res.map_err(SpiDeviceError::Cs)?; + + Ok(op_res) + } +} + +impl spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> +where + M: RawMutex, + BUS: spi::SpiBus + SetConfig, + CS: OutputPin, +{ + async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> { + let mut bus = self.bus.lock().await; + bus.set_config(&self.config); + self.cs.set_low().map_err(SpiDeviceError::Cs)?; + + let op_res: Result<(), BUS::Error> = try { + for op in operations { + match op { + Operation::Read(buf) => bus.read(buf).await?, + Operation::Write(buf) => bus.write(buf).await?, + Operation::Transfer(read, write) => bus.transfer(read, write).await?, + Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await?, + } + } + }; + + // On failure, it's important to still flush and deassert CS. + let flush_res = bus.flush().await; + let cs_res = self.cs.set_high(); + + let op_res = op_res.map_err(SpiDeviceError::Spi)?; + flush_res.map_err(SpiDeviceError::Spi)?; + cs_res.map_err(SpiDeviceError::Cs)?; + + Ok(op_res) } } diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs index 892000b2..1fe520e6 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs @@ -72,34 +72,6 @@ where let _ = operations; todo!() } - - fn write_iter>(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error> { - let _ = addr; - let _ = bytes; - todo!() - } - - fn write_iter_read>( - &mut self, - addr: u8, - bytes: B, - buffer: &mut [u8], - ) -> Result<(), Self::Error> { - let _ = addr; - let _ = bytes; - let _ = buffer; - todo!() - } - - fn transaction_iter<'a, O: IntoIterator>>( - &mut self, - address: u8, - operations: O, - ) -> Result<(), Self::Error> { - let _ = address; - let _ = operations; - todo!() - } } impl<'a, M, BUS, E> embedded_hal_02::blocking::i2c::Write for I2cDevice<'_, M, BUS> @@ -204,32 +176,4 @@ where let _ = operations; todo!() } - - fn write_iter>(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error> { - let _ = addr; - let _ = bytes; - todo!() - } - - fn write_iter_read>( - &mut self, - addr: u8, - bytes: B, - buffer: &mut [u8], - ) -> Result<(), Self::Error> { - let _ = addr; - let _ = bytes; - let _ = buffer; - todo!() - } - - fn transaction_iter<'a, O: IntoIterator>>( - &mut self, - address: u8, - operations: O, - ) -> Result<(), Self::Error> { - let _ = address; - let _ = operations; - todo!() - } } diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs index 4a08dc36..7982ffb6 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs @@ -23,8 +23,7 @@ use core::cell::RefCell; use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::blocking_mutex::Mutex; use embedded_hal_1::digital::OutputPin; -use embedded_hal_1::spi; -use embedded_hal_1::spi::SpiBusFlush; +use embedded_hal_1::spi::{self, Operation, SpiBus, SpiBusRead, SpiBusWrite}; use crate::shared_bus::SpiDeviceError; use crate::SetConfig; @@ -50,30 +49,85 @@ where type Error = SpiDeviceError; } -impl embedded_hal_1::spi::SpiDevice for SpiDevice<'_, M, BUS, CS> +impl embedded_hal_1::spi::SpiDeviceRead for SpiDevice<'_, M, BUS, CS> where M: RawMutex, - BUS: SpiBusFlush, + BUS: SpiBusRead, CS: OutputPin, { - type Bus = BUS; - - fn transaction(&mut self, f: impl FnOnce(&mut Self::Bus) -> Result) -> Result { + fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> { self.bus.lock(|bus| { let mut bus = bus.borrow_mut(); self.cs.set_low().map_err(SpiDeviceError::Cs)?; - let f_res = f(&mut bus); + let op_res = operations.iter_mut().try_for_each(|buf| bus.read(buf)); // On failure, it's important to still flush and deassert CS. let flush_res = bus.flush(); let cs_res = self.cs.set_high(); - let f_res = f_res.map_err(SpiDeviceError::Spi)?; + let op_res = op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; cs_res.map_err(SpiDeviceError::Cs)?; - Ok(f_res) + Ok(op_res) + }) + } +} + +impl embedded_hal_1::spi::SpiDeviceWrite for SpiDevice<'_, M, BUS, CS> +where + M: RawMutex, + BUS: SpiBusWrite, + CS: OutputPin, +{ + fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> { + self.bus.lock(|bus| { + let mut bus = bus.borrow_mut(); + self.cs.set_low().map_err(SpiDeviceError::Cs)?; + + let op_res = operations.iter().try_for_each(|buf| bus.write(buf)); + + // On failure, it's important to still flush and deassert CS. + let flush_res = bus.flush(); + let cs_res = self.cs.set_high(); + + let op_res = op_res.map_err(SpiDeviceError::Spi)?; + flush_res.map_err(SpiDeviceError::Spi)?; + cs_res.map_err(SpiDeviceError::Cs)?; + + Ok(op_res) + }) + } +} + +impl embedded_hal_1::spi::SpiDevice for SpiDevice<'_, M, BUS, CS> +where + M: RawMutex, + BUS: SpiBus, + CS: OutputPin, +{ + fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> { + self.bus.lock(|bus| { + let mut bus = bus.borrow_mut(); + self.cs.set_low().map_err(SpiDeviceError::Cs)?; + + let op_res = operations.iter_mut().try_for_each(|op| match op { + Operation::Read(buf) => bus.read(buf), + Operation::Write(buf) => bus.write(buf), + Operation::Transfer(read, write) => bus.transfer(read, write), + Operation::TransferInPlace(buf) => bus.transfer_in_place(buf), + }); + + // On failure, it's important to still flush and deassert CS. + let flush_res = bus.flush(); + let cs_res = self.cs.set_high(); + + let op_res = op_res.map_err(SpiDeviceError::Spi)?; + flush_res.map_err(SpiDeviceError::Spi)?; + cs_res.map_err(SpiDeviceError::Cs)?; + + Ok(op_res) }) } } @@ -89,11 +143,11 @@ where self.bus.lock(|bus| { let mut bus = bus.borrow_mut(); self.cs.set_low().map_err(SpiDeviceError::Cs)?; - let f_res = bus.transfer(words); + let op_res = bus.transfer(words); let cs_res = self.cs.set_high(); - let f_res = f_res.map_err(SpiDeviceError::Spi)?; + let op_res = op_res.map_err(SpiDeviceError::Spi)?; cs_res.map_err(SpiDeviceError::Cs)?; - Ok(f_res) + Ok(op_res) }) } } @@ -110,11 +164,11 @@ where self.bus.lock(|bus| { let mut bus = bus.borrow_mut(); self.cs.set_low().map_err(SpiDeviceError::Cs)?; - let f_res = bus.write(words); + let op_res = bus.write(words); let cs_res = self.cs.set_high(); - let f_res = f_res.map_err(SpiDeviceError::Spi)?; + let op_res = op_res.map_err(SpiDeviceError::Spi)?; cs_res.map_err(SpiDeviceError::Cs)?; - Ok(f_res) + Ok(op_res) }) } } @@ -146,30 +200,85 @@ where type Error = SpiDeviceError; } -impl embedded_hal_1::spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> +impl embedded_hal_1::spi::SpiDeviceRead for SpiDeviceWithConfig<'_, M, BUS, CS> where M: RawMutex, - BUS: SpiBusFlush + SetConfig, + BUS: SpiBusRead + SetConfig, CS: OutputPin, { - type Bus = BUS; - - fn transaction(&mut self, f: impl FnOnce(&mut Self::Bus) -> Result) -> Result { + fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> { self.bus.lock(|bus| { let mut bus = bus.borrow_mut(); bus.set_config(&self.config); self.cs.set_low().map_err(SpiDeviceError::Cs)?; - let f_res = f(&mut bus); + let op_res = operations.iter_mut().try_for_each(|buf| bus.read(buf)); // On failure, it's important to still flush and deassert CS. let flush_res = bus.flush(); let cs_res = self.cs.set_high(); - let f_res = f_res.map_err(SpiDeviceError::Spi)?; + let op_res = op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; cs_res.map_err(SpiDeviceError::Cs)?; - Ok(f_res) + Ok(op_res) + }) + } +} + +impl embedded_hal_1::spi::SpiDeviceWrite for SpiDeviceWithConfig<'_, M, BUS, CS> +where + M: RawMutex, + BUS: SpiBusWrite + SetConfig, + CS: OutputPin, +{ + fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> { + self.bus.lock(|bus| { + let mut bus = bus.borrow_mut(); + bus.set_config(&self.config); + self.cs.set_low().map_err(SpiDeviceError::Cs)?; + + let op_res = operations.iter().try_for_each(|buf| bus.write(buf)); + + // On failure, it's important to still flush and deassert CS. + let flush_res = bus.flush(); + let cs_res = self.cs.set_high(); + + let op_res = op_res.map_err(SpiDeviceError::Spi)?; + flush_res.map_err(SpiDeviceError::Spi)?; + cs_res.map_err(SpiDeviceError::Cs)?; + Ok(op_res) + }) + } +} + +impl embedded_hal_1::spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> +where + M: RawMutex, + BUS: SpiBus + SetConfig, + CS: OutputPin, +{ + fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> { + self.bus.lock(|bus| { + let mut bus = bus.borrow_mut(); + bus.set_config(&self.config); + self.cs.set_low().map_err(SpiDeviceError::Cs)?; + + let op_res = operations.iter_mut().try_for_each(|op| match op { + Operation::Read(buf) => bus.read(buf), + Operation::Write(buf) => bus.write(buf), + Operation::Transfer(read, write) => bus.transfer(read, write), + Operation::TransferInPlace(buf) => bus.transfer_in_place(buf), + }); + + // On failure, it's important to still flush and deassert CS. + let flush_res = bus.flush(); + let cs_res = self.cs.set_high(); + + let op_res = op_res.map_err(SpiDeviceError::Spi)?; + flush_res.map_err(SpiDeviceError::Spi)?; + cs_res.map_err(SpiDeviceError::Cs)?; + Ok(op_res) }) } } diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index cbe78e59..c9174ea8 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml @@ -31,8 +31,8 @@ log = { version = "0.4.14", optional = true } embassy-time = { version = "0.1.0", path = "../embassy-time" } embassy-sync = { version = "0.1.0", path = "../embassy-sync" } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } -embedded-hal-async = { version = "=0.2.0-alpha.0" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } +embedded-hal-async = { version = "=0.2.0-alpha.1" } embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } embedded-hal = { version = "0.2", features = ["unproven"] } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 4e62ca89..4a4e7c9f 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -87,8 +87,8 @@ embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} -embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} +embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} embedded-io = { version = "0.4.0", features = ["async"], optional = true } defmt = { version = "0.3", optional = true } diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index ef4c929a..9ae56960 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -846,20 +846,6 @@ mod eh1 { self.blocking_write(address, buffer) } - fn write_iter(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error> - where - B: IntoIterator, - { - todo!(); - } - - fn write_iter_read(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error> - where - B: IntoIterator, - { - todo!(); - } - fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { self.blocking_write_read(address, wr_buffer, rd_buffer) } @@ -871,13 +857,6 @@ mod eh1 { ) -> Result<(), Self::Error> { todo!(); } - - fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error> - where - O: IntoIterator>, - { - todo!(); - } } } @@ -885,28 +864,22 @@ mod eh1 { mod eha { use super::*; impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { - async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), Error> { - self.read(address, buffer).await + async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { + self.read(address, read).await } - async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), Error> { - self.write(address, bytes).await + async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { + self.write(address, write).await + } + async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.write_read(address, write, read).await } - async fn write_read<'a>( - &'a mut self, + async fn transaction( + &mut self, address: u8, - wr_buffer: &'a [u8], - rd_buffer: &'a mut [u8], - ) -> Result<(), Error> { - self.write_read(address, wr_buffer, rd_buffer).await - } - - async fn transaction<'a, 'b>( - &'a mut self, - address: u8, - operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], - ) -> Result<(), Error> { + operations: &mut [embedded_hal_1::i2c::Operation<'_>], + ) -> Result<(), Self::Error> { let _ = address; let _ = operations; todo!() diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 209c665b..cb9c7be7 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -65,9 +65,9 @@ rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c90 #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} -embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} -embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} +embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} +embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} paste = "1.0" pio-proc = {version= "0.2", optional = true} diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index e48e16d8..40e85c66 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -490,14 +490,14 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { } } - fn read_blocking_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { - if buffer.is_empty() { + fn read_blocking_internal(&mut self, read: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { + if read.is_empty() { return Err(Error::InvalidReadBufferLength); } let p = T::regs(); - let lastindex = buffer.len() - 1; - for (i, byte) in buffer.iter_mut().enumerate() { + let lastindex = read.len() - 1; + for (i, byte) in read.iter_mut().enumerate() { let first = i == 0; let last = i == lastindex; @@ -524,15 +524,15 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { Ok(()) } - fn write_blocking_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> { - if bytes.is_empty() { + fn write_blocking_internal(&mut self, write: &[u8], send_stop: bool) -> Result<(), Error> { + if write.is_empty() { return Err(Error::InvalidWriteBufferLength); } let p = T::regs(); - for (i, byte) in bytes.iter().enumerate() { - let last = i == bytes.len() - 1; + for (i, byte) in write.iter().enumerate() { + let last = i == write.len() - 1; // NOTE(unsafe) We have &mut self unsafe { @@ -572,21 +572,21 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { // Blocking public API // ========================= - pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { + pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { Self::setup(address.into())?; - self.read_blocking_internal(buffer, true, true) + self.read_blocking_internal(read, true, true) // Automatic Stop } - pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { + pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { Self::setup(address.into())?; - self.write_blocking_internal(bytes, true) + self.write_blocking_internal(write, true) } - pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { + pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { Self::setup(address.into())?; - self.write_blocking_internal(bytes, false)?; - self.read_blocking_internal(buffer, true, true) + self.write_blocking_internal(write, false)?; + self.read_blocking_internal(read, true, true) // Automatic Stop } } @@ -644,48 +644,22 @@ mod eh1 { } impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> { - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(address, buffer) + fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(address, read) } - fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, buffer) + fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(address, write) } - fn write_iter(&mut self, address: u8, bytes: B) -> Result<(), Self::Error> - where - B: IntoIterator, - { - let mut peekable = bytes.into_iter().peekable(); - Self::setup(address.into())?; - - while let Some(tx) = peekable.next() { - self.write_blocking_internal(&[tx], peekable.peek().is_none())?; - } - Ok(()) + fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_write_read(address, write, read) } - fn write_iter_read(&mut self, address: u8, bytes: B, buffer: &mut [u8]) -> Result<(), Self::Error> - where - B: IntoIterator, - { - let peekable = bytes.into_iter().peekable(); - Self::setup(address.into())?; - - for tx in peekable { - self.write_blocking_internal(&[tx], false)? - } - self.read_blocking_internal(buffer, true, true) - } - - fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(address, wr_buffer, rd_buffer) - } - - fn transaction<'a>( + fn transaction( &mut self, address: u8, - operations: &mut [embedded_hal_1::i2c::Operation<'a>], + operations: &mut [embedded_hal_1::i2c::Operation<'_>], ) -> Result<(), Self::Error> { Self::setup(address.into())?; for i in 0..operations.len() { @@ -697,22 +671,6 @@ mod eh1 { } Ok(()) } - - fn transaction_iter<'a, O>(&mut self, address: u8, operations: O) -> Result<(), Self::Error> - where - O: IntoIterator>, - { - Self::setup(address.into())?; - let mut peekable = operations.into_iter().peekable(); - while let Some(operation) = peekable.next() { - let last = peekable.peek().is_none(); - match operation { - embedded_hal_1::i2c::Operation::Read(buf) => self.read_blocking_internal(buf, false, last)?, - embedded_hal_1::i2c::Operation::Write(buf) => self.write_blocking_internal(buf, last)?, - } - } - Ok(()) - } } } #[cfg(all(feature = "unstable-traits", feature = "nightly"))] @@ -727,36 +685,29 @@ mod nightly { A: AddressMode + Into + 'static, T: Instance + 'd, { - async fn read<'a>(&'a mut self, address: A, read: &'a mut [u8]) -> Result<(), Self::Error> { + async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> { let addr: u16 = address.into(); Self::setup(addr)?; self.read_async_internal(read, false, true).await } - async fn write<'a>(&'a mut self, address: A, write: &'a [u8]) -> Result<(), Self::Error> { + async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> { let addr: u16 = address.into(); Self::setup(addr)?; self.write_async_internal(write.iter().copied(), true).await } - async fn write_read<'a>( - &'a mut self, - address: A, - write: &'a [u8], - read: &'a mut [u8], - ) -> Result<(), Self::Error> { + + async fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { let addr: u16 = address.into(); Self::setup(addr)?; self.write_async_internal(write.iter().cloned(), false).await?; self.read_async_internal(read, false, true).await } - async fn transaction<'a, 'b>( - &'a mut self, - address: A, - operations: &'a mut [Operation<'b>], - ) -> Result<(), Self::Error> { + + async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { let addr: u16 = address.into(); let mut iterator = operations.iter_mut(); diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index ebd621ec..742a35d4 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -19,6 +19,7 @@ pub enum Error { } #[non_exhaustive] +#[derive(Clone)] pub struct Config { pub frequency: u32, pub phase: Phase, diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 3fd1e4b4..6710ff2d 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -44,9 +44,9 @@ embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} -embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} -embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} +embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} +embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} embedded-storage = "0.3.0" diff --git a/embassy-stm32/src/i2c/timeout.rs b/embassy-stm32/src/i2c/timeout.rs index 4fca1ca2..939e2750 100644 --- a/embassy-stm32/src/i2c/timeout.rs +++ b/embassy-stm32/src/i2c/timeout.rs @@ -28,64 +28,64 @@ impl<'d, T: Instance, TXDMA, RXDMA> TimeoutI2c<'d, T, TXDMA, RXDMA> { } /// Blocking read with a custom timeout - pub fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> { - self.i2c.blocking_read_timeout(addr, buffer, timeout_fn(timeout)) + pub fn blocking_read_timeout(&mut self, addr: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> { + self.i2c.blocking_read_timeout(addr, read, timeout_fn(timeout)) } /// Blocking read with default timeout, provided in [`TimeoutI2c::new()`] - pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(addr, buffer, self.timeout) + pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { + self.blocking_read_timeout(addr, read, self.timeout) } /// Blocking write with a custom timeout - pub fn blocking_write_timeout(&mut self, addr: u8, bytes: &[u8], timeout: Duration) -> Result<(), Error> { - self.i2c.blocking_write_timeout(addr, bytes, timeout_fn(timeout)) + pub fn blocking_write_timeout(&mut self, addr: u8, write: &[u8], timeout: Duration) -> Result<(), Error> { + self.i2c.blocking_write_timeout(addr, write, timeout_fn(timeout)) } /// Blocking write with default timeout, provided in [`TimeoutI2c::new()`] - pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { - self.blocking_write_timeout(addr, bytes, self.timeout) + pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { + self.blocking_write_timeout(addr, write, self.timeout) } /// Blocking write-read with a custom timeout pub fn blocking_write_read_timeout( &mut self, addr: u8, - bytes: &[u8], - buffer: &mut [u8], + write: &[u8], + read: &mut [u8], timeout: Duration, ) -> Result<(), Error> { self.i2c - .blocking_write_read_timeout(addr, bytes, buffer, timeout_fn(timeout)) + .blocking_write_read_timeout(addr, write, read, timeout_fn(timeout)) } /// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`] - pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { - self.blocking_write_read_timeout(addr, bytes, buffer, self.timeout) + pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + self.blocking_write_read_timeout(addr, write, read, self.timeout) } } impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> { type Error = Error; - fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(addr, buffer) + fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(addr, read) } } impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> { type Error = Error; - fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(addr, bytes) + fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(addr, write) } } impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> { type Error = Error; - fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(addr, bytes, buffer) + fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_write_read(addr, write, read) } } @@ -98,45 +98,24 @@ mod eh1 { } impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T, TXDMA, RXDMA> { - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(address, buffer) + fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(address, read) } - fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, buffer) + fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(address, write) } - fn write_iter(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error> - where - B: IntoIterator, - { - todo!(); + fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_write_read(address, write, read) } - fn write_iter_read(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error> - where - B: IntoIterator, - { - todo!(); - } - - fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(address, wr_buffer, rd_buffer) - } - - fn transaction<'a>( + fn transaction( &mut self, _address: u8, - _operations: &mut [embedded_hal_1::i2c::Operation<'a>], + _operations: &mut [embedded_hal_1::i2c::Operation<'_>], ) -> Result<(), Self::Error> { todo!(); } - - fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error> - where - O: IntoIterator>, - { - todo!(); - } } } diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index f140e2b0..4b47f0eb 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -307,18 +307,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } - pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(addr, buffer, || Ok(())) + pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { + self.blocking_read_timeout(addr, read, || Ok(())) } pub fn blocking_write_timeout( &mut self, addr: u8, - bytes: &[u8], + write: &[u8], check_timeout: impl Fn() -> Result<(), Error>, ) -> Result<(), Error> { unsafe { - self.write_bytes(addr, bytes, &check_timeout)?; + self.write_bytes(addr, write, &check_timeout)?; // Send a STOP condition T::regs().cr1().modify(|reg| reg.set_stop(true)); // Wait for STOP condition to transmit. @@ -331,49 +331,49 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } - pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { - self.blocking_write_timeout(addr, bytes, || Ok(())) + pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { + self.blocking_write_timeout(addr, write, || Ok(())) } pub fn blocking_write_read_timeout( &mut self, addr: u8, - bytes: &[u8], - buffer: &mut [u8], + write: &[u8], + read: &mut [u8], check_timeout: impl Fn() -> Result<(), Error>, ) -> Result<(), Error> { - unsafe { self.write_bytes(addr, bytes, &check_timeout)? }; - self.blocking_read_timeout(addr, buffer, &check_timeout)?; + unsafe { self.write_bytes(addr, write, &check_timeout)? }; + self.blocking_read_timeout(addr, read, &check_timeout)?; Ok(()) } - pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { - self.blocking_write_read_timeout(addr, bytes, buffer, || Ok(())) + pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + self.blocking_write_read_timeout(addr, write, read, || Ok(())) } } impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { type Error = Error; - fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(addr, buffer) + fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(addr, read) } } impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { type Error = Error; - fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(addr, bytes) + fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(addr, write) } } impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { type Error = Error; - fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(addr, bytes, buffer) + fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_write_read(addr, write, read) } } @@ -402,46 +402,25 @@ mod eh1 { } impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T> { - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(address, buffer) + fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(address, read) } - fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, buffer) + fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(address, write) } - fn write_iter(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error> - where - B: IntoIterator, - { - todo!(); + fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_write_read(address, write, read) } - fn write_iter_read(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error> - where - B: IntoIterator, - { - todo!(); - } - - fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(address, wr_buffer, rd_buffer) - } - - fn transaction<'a>( + fn transaction( &mut self, _address: u8, - _operations: &mut [embedded_hal_1::i2c::Operation<'a>], + _operations: &mut [embedded_hal_1::i2c::Operation<'_>], ) -> Result<(), Self::Error> { todo!(); } - - fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error> - where - O: IntoIterator>, - { - todo!(); - } } } diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 06ff07b2..28663fb3 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -345,12 +345,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { fn read_internal( &mut self, address: u8, - buffer: &mut [u8], + read: &mut [u8], restart: bool, check_timeout: impl Fn() -> Result<(), Error>, ) -> Result<(), Error> { - let completed_chunks = buffer.len() / 255; - let total_chunks = if completed_chunks * 255 == buffer.len() { + let completed_chunks = read.len() / 255; + let total_chunks = if completed_chunks * 255 == read.len() { completed_chunks } else { completed_chunks + 1 @@ -360,7 +360,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { unsafe { Self::master_read( address, - buffer.len().min(255), + read.len().min(255), Stop::Automatic, last_chunk_idx != 0, restart, @@ -368,7 +368,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { )?; } - for (number, chunk) in buffer.chunks_mut(255).enumerate() { + for (number, chunk) in read.chunks_mut(255).enumerate() { if number != 0 { // NOTE(unsafe) We have &mut self unsafe { @@ -391,12 +391,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { fn write_internal( &mut self, address: u8, - bytes: &[u8], + write: &[u8], send_stop: bool, check_timeout: impl Fn() -> Result<(), Error>, ) -> Result<(), Error> { - let completed_chunks = bytes.len() / 255; - let total_chunks = if completed_chunks * 255 == bytes.len() { + let completed_chunks = write.len() / 255; + let total_chunks = if completed_chunks * 255 == write.len() { completed_chunks } else { completed_chunks + 1 @@ -410,14 +410,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { unsafe { Self::master_write( address, - bytes.len().min(255), + write.len().min(255), Stop::Software, last_chunk_idx != 0, &check_timeout, )?; } - for (number, chunk) in bytes.chunks(255).enumerate() { + for (number, chunk) in write.chunks(255).enumerate() { if number != 0 { // NOTE(unsafe) We have &mut self unsafe { @@ -448,7 +448,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { async fn write_dma_internal( &mut self, address: u8, - bytes: &[u8], + write: &[u8], first_slice: bool, last_slice: bool, check_timeout: impl Fn() -> Result<(), Error>, @@ -456,7 +456,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { where TXDMA: crate::i2c::TxDma, { - let total_len = bytes.len(); + let total_len = write.len(); let completed_chunks = total_len / 255; let total_chunks = if completed_chunks * 255 == total_len { completed_chunks @@ -476,7 +476,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let ch = &mut self.tx_dma; let request = ch.request(); - crate::dma::write(ch, request, bytes, dst) + crate::dma::write(ch, request, write, dst) }; let state = T::state(); @@ -641,25 +641,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // ========================= // Async public API - pub async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> + pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { - if bytes.is_empty() { - self.write_internal(address, bytes, true, || Ok(())) + if write.is_empty() { + self.write_internal(address, write, true, || Ok(())) } else { - self.write_dma_internal(address, bytes, true, true, || Ok(())).await + self.write_dma_internal(address, write, true, true, || Ok(())).await } } - pub async fn write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> + pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { - if bytes.is_empty() { + if write.is_empty() { return Err(Error::ZeroLengthTransfer); } - let mut iter = bytes.iter(); + let mut iter = write.iter(); let mut first = true; let mut current = iter.next(); @@ -685,21 +685,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } - pub async fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> + pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> where TXDMA: super::TxDma, RXDMA: super::RxDma, { - if bytes.is_empty() { - self.write_internal(address, bytes, false, || Ok(()))?; + if write.is_empty() { + self.write_internal(address, write, false, || Ok(()))?; } else { - self.write_dma_internal(address, bytes, true, true, || Ok(())).await?; + self.write_dma_internal(address, write, true, true, || Ok(())).await?; } - if buffer.is_empty() { - self.read_internal(address, buffer, true, || Ok(()))?; + if read.is_empty() { + self.read_internal(address, read, true, || Ok(()))?; } else { - self.read_dma_internal(address, buffer, true, || Ok(())).await?; + self.read_dma_internal(address, read, true, || Ok(())).await?; } Ok(()) @@ -711,57 +711,57 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { pub fn blocking_read_timeout( &mut self, address: u8, - buffer: &mut [u8], + read: &mut [u8], check_timeout: impl Fn() -> Result<(), Error>, ) -> Result<(), Error> { - self.read_internal(address, buffer, false, &check_timeout) + self.read_internal(address, read, false, &check_timeout) // Automatic Stop } - pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(address, buffer, || Ok(())) + pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { + self.blocking_read_timeout(address, read, || Ok(())) } pub fn blocking_write_timeout( &mut self, address: u8, - bytes: &[u8], + write: &[u8], check_timeout: impl Fn() -> Result<(), Error>, ) -> Result<(), Error> { - self.write_internal(address, bytes, true, &check_timeout) + self.write_internal(address, write, true, &check_timeout) } - pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { - self.blocking_write_timeout(address, bytes, || Ok(())) + pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { + self.blocking_write_timeout(address, write, || Ok(())) } pub fn blocking_write_read_timeout( &mut self, address: u8, - bytes: &[u8], - buffer: &mut [u8], + write: &[u8], + read: &mut [u8], check_timeout: impl Fn() -> Result<(), Error>, ) -> Result<(), Error> { - self.write_internal(address, bytes, false, &check_timeout)?; - self.read_internal(address, buffer, true, &check_timeout) + self.write_internal(address, write, false, &check_timeout)?; + self.read_internal(address, read, true, &check_timeout) // Automatic Stop } - pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { - self.blocking_write_read_timeout(address, bytes, buffer, || Ok(())) + pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + self.blocking_write_read_timeout(address, write, read, || Ok(())) } pub fn blocking_write_vectored_timeout( &mut self, address: u8, - bytes: &[&[u8]], + write: &[&[u8]], check_timeout: impl Fn() -> Result<(), Error>, ) -> Result<(), Error> { - if bytes.is_empty() { + if write.is_empty() { return Err(Error::ZeroLengthTransfer); } - let first_length = bytes[0].len(); - let last_slice_index = bytes.len() - 1; + let first_length = write[0].len(); + let last_slice_index = write.len() - 1; // NOTE(unsafe) We have &mut self unsafe { @@ -774,7 +774,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { )?; } - for (idx, slice) in bytes.iter().enumerate() { + for (idx, slice) in write.iter().enumerate() { let slice_len = slice.len(); let completed_chunks = slice_len / 255; let total_chunks = if completed_chunks * 255 == slice_len { @@ -828,8 +828,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } - pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { - self.blocking_write_vectored_timeout(address, bytes, || Ok(())) + pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { + self.blocking_write_vectored_timeout(address, write, || Ok(())) } } @@ -847,16 +847,16 @@ mod eh02 { impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { type Error = Error; - fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, bytes) + fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(address, write) } } impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { type Error = Error; - fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(address, bytes, buffer) + fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_write_read(address, write, read) } } } @@ -1010,46 +1010,25 @@ mod eh1 { } impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> { - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(address, buffer) + fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(address, read) } - fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, buffer) + fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(address, write) } - fn write_iter(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error> - where - B: IntoIterator, - { - todo!(); + fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_write_read(address, write, read) } - fn write_iter_read(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error> - where - B: IntoIterator, - { - todo!(); - } - - fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(address, wr_buffer, rd_buffer) - } - - fn transaction<'a>( + fn transaction( &mut self, _address: u8, - _operations: &mut [embedded_hal_1::i2c::Operation<'a>], + _operations: &mut [embedded_hal_1::i2c::Operation<'_>], ) -> Result<(), Self::Error> { todo!(); } - - fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error> - where - O: IntoIterator>, - { - todo!(); - } } } @@ -1059,27 +1038,22 @@ mod eha { use super::*; impl<'d, T: Instance, TXDMA: TxDma, RXDMA: RxDma> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> { - async fn read<'a>(&'a mut self, address: u8, read: &'a mut [u8]) -> Result<(), Self::Error> { + async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { self.read(address, read).await } - async fn write<'a>(&'a mut self, address: u8, write: &'a [u8]) -> Result<(), Self::Error> { + async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { self.write(address, write).await } - async fn write_read<'a>( - &'a mut self, - address: u8, - write: &'a [u8], - read: &'a mut [u8], - ) -> Result<(), Self::Error> { + async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { self.write_read(address, write, read).await } - async fn transaction<'a, 'b>( - &'a mut self, + async fn transaction( + &mut self, address: u8, - operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], + operations: &mut [embedded_hal_1::i2c::Operation<'_>], ) -> Result<(), Self::Error> { let _ = address; let _ = operations; diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 5b14814a..38d31f1c 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -152,8 +152,8 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} -embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} +embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} futures-util = { version = "0.3.17", default-features = false } embassy-sync = { version = "0.1", path = "../embassy-sync" } diff --git a/embassy-time/src/delay.rs b/embassy-time/src/delay.rs index 0ca176ab..cf191872 100644 --- a/embassy-time/src/delay.rs +++ b/embassy-time/src/delay.rs @@ -19,14 +19,12 @@ mod eh1 { use super::*; impl embedded_hal_1::delay::DelayUs for Delay { - type Error = core::convert::Infallible; - - fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { - Ok(block_for(Duration::from_micros(us as u64))) + fn delay_us(&mut self, us: u32) { + block_for(Duration::from_micros(us as u64)) } - fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { - Ok(block_for(Duration::from_millis(ms as u64))) + fn delay_ms(&mut self, ms: u32) { + block_for(Duration::from_millis(ms as u64)) } } } @@ -37,14 +35,12 @@ mod eha { use crate::Timer; impl embedded_hal_async::delay::DelayUs for Delay { - type Error = core::convert::Infallible; - - async fn delay_us(&mut self, micros: u32) -> Result<(), Self::Error> { - Ok(Timer::after(Duration::from_micros(micros as _)).await) + async fn delay_us(&mut self, micros: u32) { + Timer::after(Duration::from_micros(micros as _)).await } - async fn delay_ms(&mut self, millis: u32) -> Result<(), Self::Error> { - Ok(Timer::after(Duration::from_millis(millis as _)).await) + async fn delay_ms(&mut self, millis: u32) { + Timer::after(Duration::from_millis(millis as _)).await } } } diff --git a/examples/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml index d1c8c1c5..2ee6fcb0 100644 --- a/examples/rp/.cargo/config.toml +++ b/examples/rp/.cargo/config.toml @@ -1,5 +1,5 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-run --chip RP2040" +runner = "probe-rs-cli run --chip RP2040" [build] target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index aea61eec..63d0ac82 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -6,6 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] +embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } @@ -30,8 +31,8 @@ display-interface = "0.4.1" byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.3.0" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } -embedded-hal-async = "0.2.0-alpha.0" +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } +embedded-hal-async = "0.2.0-alpha.1" embedded-io = { version = "0.4.0", features = ["async", "defmt"] } embedded-storage = { version = "0.3" } static_cell = "1.0.0" diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs index 778cad3f..85a19ce0 100644 --- a/examples/rp/src/bin/spi_display.rs +++ b/examples/rp/src/bin/spi_display.rs @@ -5,10 +5,13 @@ use core::cell::RefCell; use defmt::*; +use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; use embassy_rp::spi::{Blocking, Spi}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::blocking_mutex::Mutex; use embassy_time::Delay; use embedded_graphics::image::{Image, ImageRawLE}; use embedded_graphics::mono_font::ascii::FONT_10X20; @@ -21,10 +24,9 @@ use st7789::{Orientation, ST7789}; use {defmt_rtt as _, panic_probe as _}; use crate::my_display_interface::SPIDeviceInterface; -use crate::shared_spi::SpiDeviceWithCs; use crate::touch::Touch; -//const DISPLAY_FREQ: u32 = 64_000_000; +const DISPLAY_FREQ: u32 = 64_000_000; const TOUCH_FREQ: u32 = 200_000; #[embassy_executor::main] @@ -43,16 +45,20 @@ async fn main(_spawner: Spawner) { //let touch_irq = p.PIN_17; // create SPI - let mut config = spi::Config::default(); - config.frequency = TOUCH_FREQ; // use the lowest freq - config.phase = spi::Phase::CaptureOnSecondTransition; - config.polarity = spi::Polarity::IdleHigh; + let mut display_config = spi::Config::default(); + display_config.frequency = DISPLAY_FREQ; + display_config.phase = spi::Phase::CaptureOnSecondTransition; + display_config.polarity = spi::Polarity::IdleHigh; + let mut touch_config = spi::Config::default(); + touch_config.frequency = TOUCH_FREQ; + touch_config.phase = spi::Phase::CaptureOnSecondTransition; + touch_config.polarity = spi::Polarity::IdleHigh; - let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, config); - let spi_bus = RefCell::new(spi); + let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); + let spi_bus: Mutex = Mutex::new(RefCell::new(spi)); - let display_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(display_cs, Level::High)); - let touch_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(touch_cs, Level::High)); + let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); + let touch_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(touch_cs, Level::High), touch_config); let mut touch = Touch::new(touch_spi); @@ -104,85 +110,9 @@ async fn main(_spawner: Spawner) { } } -mod shared_spi { - use core::cell::RefCell; - use core::fmt::Debug; - - use embedded_hal_1::digital::OutputPin; - use embedded_hal_1::spi; - use embedded_hal_1::spi::SpiDevice; - - #[derive(Copy, Clone, Eq, PartialEq, Debug)] - pub enum SpiDeviceWithCsError { - #[allow(unused)] // will probably use in the future when adding a flush() to SpiBus - Spi(BUS), - Cs(CS), - } - - impl spi::Error for SpiDeviceWithCsError - where - BUS: spi::Error + Debug, - CS: Debug, - { - fn kind(&self) -> spi::ErrorKind { - match self { - Self::Spi(e) => e.kind(), - Self::Cs(_) => spi::ErrorKind::Other, - } - } - } - - pub struct SpiDeviceWithCs<'a, BUS, CS> { - bus: &'a RefCell, - cs: CS, - } - - impl<'a, BUS, CS> SpiDeviceWithCs<'a, BUS, CS> { - pub fn new(bus: &'a RefCell, cs: CS) -> Self { - Self { bus, cs } - } - } - - impl<'a, BUS, CS> spi::ErrorType for SpiDeviceWithCs<'a, BUS, CS> - where - BUS: spi::ErrorType, - CS: OutputPin, - { - type Error = SpiDeviceWithCsError; - } - - impl<'a, BUS, CS> SpiDevice for SpiDeviceWithCs<'a, BUS, CS> - where - BUS: spi::SpiBusFlush, - CS: OutputPin, - { - type Bus = BUS; - - fn transaction( - &mut self, - f: impl FnOnce(&mut Self::Bus) -> Result, - ) -> Result { - let mut bus = self.bus.borrow_mut(); - self.cs.set_low().map_err(SpiDeviceWithCsError::Cs)?; - - let f_res = f(&mut bus); - - // On failure, it's important to still flush and deassert CS. - let flush_res = bus.flush(); - let cs_res = self.cs.set_high(); - - let f_res = f_res.map_err(SpiDeviceWithCsError::Spi)?; - flush_res.map_err(SpiDeviceWithCsError::Spi)?; - cs_res.map_err(SpiDeviceWithCsError::Cs)?; - - Ok(f_res) - } - } -} - /// Driver for the XPT2046 resistive touchscreen sensor mod touch { - use embedded_hal_1::spi::{SpiBus, SpiBusRead, SpiBusWrite, SpiDevice}; + use embedded_hal_1::spi::{Operation, SpiDevice}; struct Calibration { x1: i32, @@ -209,7 +139,6 @@ mod touch { impl Touch where SPI: SpiDevice, - SPI::Bus: SpiBus, { pub fn new(spi: SPI) -> Self { Self { spi } @@ -219,13 +148,12 @@ mod touch { let mut x = [0; 2]; let mut y = [0; 2]; self.spi - .transaction(|bus| { - bus.write(&[0x90])?; - bus.read(&mut x)?; - bus.write(&[0xd0])?; - bus.read(&mut y)?; - Ok(()) - }) + .transaction(&mut [ + Operation::Write(&[0x90]), + Operation::Read(&mut x), + Operation::Write(&[0xd0]), + Operation::Read(&mut y), + ]) .unwrap(); let x = (u16::from_be_bytes(x) >> 3) as i32; @@ -247,7 +175,7 @@ mod touch { mod my_display_interface { use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; use embedded_hal_1::digital::OutputPin; - use embedded_hal_1::spi::{SpiBusWrite, SpiDevice}; + use embedded_hal_1::spi::SpiDeviceWrite; /// SPI display interface. /// @@ -259,8 +187,7 @@ mod my_display_interface { impl SPIDeviceInterface where - SPI: SpiDevice, - SPI::Bus: SpiBusWrite, + SPI: SpiDeviceWrite, DC: OutputPin, { /// Create new SPI interface for communciation with a display driver @@ -271,42 +198,27 @@ mod my_display_interface { impl WriteOnlyDataCommand for SPIDeviceInterface where - SPI: SpiDevice, - SPI::Bus: SpiBusWrite, + SPI: SpiDeviceWrite, DC: OutputPin, { fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { - let r = self.spi.transaction(|bus| { - // 1 = data, 0 = command - if let Err(_) = self.dc.set_low() { - return Ok(Err(DisplayError::DCError)); - } + // 1 = data, 0 = command + self.dc.set_low().map_err(|_| DisplayError::DCError)?; - // Send words over SPI - send_u8(bus, cmds)?; - - Ok(Ok(())) - }); - r.map_err(|_| DisplayError::BusWriteError)? + send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?; + Ok(()) } fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { - let r = self.spi.transaction(|bus| { - // 1 = data, 0 = command - if let Err(_) = self.dc.set_high() { - return Ok(Err(DisplayError::DCError)); - } + // 1 = data, 0 = command + self.dc.set_high().map_err(|_| DisplayError::DCError)?; - // Send words over SPI - send_u8(bus, buf)?; - - Ok(Ok(())) - }); - r.map_err(|_| DisplayError::BusWriteError)? + send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?; + Ok(()) } } - fn send_u8(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { + fn send_u8(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { match words { DataFormat::U8(slice) => spi.write(slice), DataFormat::U16(slice) => { diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 387af783..99f37cdd 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 70702863..f240c389 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -19,8 +19,8 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } -embedded-hal-async = { version = "=0.2.0-alpha.0" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } +embedded-hal-async = { version = "=0.2.0-alpha.1" } embedded-nal-async = "0.4.0" panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index d0d6a949..154f5a98 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -19,8 +19,8 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } -embedded-hal-async = { version = "=0.2.0-alpha.0" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } +embedded-hal-async = { version = "=0.2.0-alpha.1" } embedded-nal-async = "0.4.0" panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 7c254eba..fa39df6d 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -18,8 +18,8 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } -embedded-hal-async = { version = "=0.2.0-alpha.0" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } +embedded-hal-async = { version = "=0.2.0-alpha.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index eb447be3..463a370f 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -17,8 +17,8 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6" } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } -embedded-hal-async = { version = "=0.2.0-alpha.0" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } +embedded-hal-async = { version = "=0.2.0-alpha.1" } panic-probe = { version = "0.3.0", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } embedded-io = { version = "0.4.0", features = ["async"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 17b64079..6070a5a8 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -25,8 +25,8 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } -embedded-hal-async = { version = "=0.2.0-alpha.0" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } +embedded-hal-async = { version = "=0.2.0-alpha.1" } panic-probe = { version = "0.3.0", features = ["print-defmt"] } [profile.dev] From dee1d51ad3089b03c67aaa75c7985cf95ce90eec Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 7 Apr 2023 02:20:59 +0200 Subject: [PATCH 69/78] stm32: remove subghz feature. It's available only on WL. if you're using a WL, you want subghz for sure. --- embassy-lora/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 1 - embassy-stm32/src/lib.rs | 5 ++--- examples/stm32wl/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index c9174ea8..784cc228 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml @@ -19,7 +19,7 @@ flavors = [ [features] sx126x = [] sx127x = [] -stm32wl = ["embassy-stm32", "embassy-stm32/subghz"] +stm32wl = ["dep:embassy-stm32"] time = [] defmt = ["dep:defmt", "lorawan/defmt", "lorawan-device/defmt"] diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 6710ff2d..36ee5801 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -81,7 +81,6 @@ stm32-metapac = { version = "4", default-features = false, features = ["metadata 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 = [] exti = [] # Enables additional driver features that depend on embassy-time diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 3f2d078f..d4d7155b 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -53,6 +53,8 @@ pub mod rng; pub mod sdmmc; #[cfg(spi)] pub mod spi; +#[cfg(stm32wl)] +pub mod subghz; #[cfg(usart)] pub mod usart; #[cfg(all(usb, feature = "time"))] @@ -62,9 +64,6 @@ pub mod usb_otg; #[cfg(iwdg)] pub mod wdg; -#[cfg(feature = "subghz")] -pub mod subghz; - // This must go last, so that it sees all the impl_foo! macros defined earlier. pub(crate) mod _generated { #![allow(dead_code)] diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 9fc7e0f4..0d2194ea 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "subghz", "unstable-pac", "exti"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } lorawan-device = { version = "0.8.0", default-features = false, features = ["async"] } From 8469a2409c9ded4bb66040475f365c60b261b51f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 7 Apr 2023 02:21:38 +0200 Subject: [PATCH 70/78] stm32/otg: add U5 support. --- embassy-stm32/src/usb_otg/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs index 84fef78c..193e0df0 100644 --- a/embassy-stm32/src/usb_otg/mod.rs +++ b/embassy-stm32/src/usb_otg/mod.rs @@ -89,6 +89,9 @@ foreach_interrupt!( } else if #[cfg(stm32h7)] { const FIFO_DEPTH_WORDS: u16 = 1024; const ENDPOINT_COUNT: usize = 9; + } else if #[cfg(stm32u5)] { + const FIFO_DEPTH_WORDS: u16 = 320; + const ENDPOINT_COUNT: usize = 6; } else { compile_error!("USB_OTG_FS peripheral is not supported by this chip."); } @@ -137,6 +140,9 @@ foreach_interrupt!( ))] { const FIFO_DEPTH_WORDS: u16 = 1024; const ENDPOINT_COUNT: usize = 9; + } else if #[cfg(stm32u5)] { + const FIFO_DEPTH_WORDS: u16 = 1024; + const ENDPOINT_COUNT: usize = 9; } else { compile_error!("USB_OTG_HS peripheral is not supported by this chip."); } From f38899728c8bc9c81c4ac02d8177ec6420c07f02 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 7 Apr 2023 02:22:10 +0200 Subject: [PATCH 71/78] stm32: add h5 flavor. --- embassy-stm32/Cargo.toml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 36ee5801..4ab30622 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -8,10 +8,7 @@ license = "MIT OR Apache-2.0" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" -# TODO: sdmmc -# TODO: net -# TODO: subghz -features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any"] +features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time"] flavors = [ { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, @@ -22,6 +19,7 @@ flavors = [ { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" }, + { regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" }, { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, From 1fbb8f0b321a15fd6b473c466d41fac40302ec3c Mon Sep 17 00:00:00 2001 From: Brooks J Rady Date: Sun, 9 Apr 2023 09:15:57 +0100 Subject: [PATCH 72/78] feat(rp): add `Wait` impl to `OutputOpenDrain` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A while ago `OutputOpenDrain` was made to implement `InputPin`, something that allowed drivers for various one-wire protocols to be written, but it's been lacking a `Wait` implementation — something that's needed to write async versions of these drivers. This commit also adds `get_level()` to `OutputOpenDrain`, since `is_high()` and `is_low()` were already implemented, but `get_level()` itself was missing. --- embassy-rp/src/gpio.rs | 59 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index fb45ef7c..98e18286 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -437,6 +437,37 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { pub fn is_low(&self) -> bool { self.pin.is_low() } + + /// Returns current pin level + #[inline] + pub fn get_level(&self) -> Level { + self.is_high().into() + } + + #[inline] + pub async fn wait_for_high(&mut self) { + self.pin.wait_for_high().await; + } + + #[inline] + pub async fn wait_for_low(&mut self) { + self.pin.wait_for_low().await; + } + + #[inline] + pub async fn wait_for_rising_edge(&mut self) { + self.pin.wait_for_rising_edge().await; + } + + #[inline] + pub async fn wait_for_falling_edge(&mut self) { + self.pin.wait_for_falling_edge().await; + } + + #[inline] + pub async fn wait_for_any_edge(&mut self) { + self.pin.wait_for_any_edge().await; + } } /// GPIO flexible pin. @@ -1117,4 +1148,32 @@ mod eh1 { Ok(()) } } + + #[cfg(feature = "nightly")] + impl<'d, T: Pin> embedded_hal_async::digital::Wait for OutputOpenDrain<'d, T> { + async fn wait_for_high(&mut self) -> Result<(), Self::Error> { + self.wait_for_high().await; + Ok(()) + } + + async fn wait_for_low(&mut self) -> Result<(), Self::Error> { + self.wait_for_low().await; + Ok(()) + } + + async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_rising_edge().await; + Ok(()) + } + + async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_falling_edge().await; + Ok(()) + } + + async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_any_edge().await; + Ok(()) + } + } } From dee8c71a2d57f3015fde55da28758a35fcbf7ca6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 9 Apr 2023 22:40:09 +0200 Subject: [PATCH 73/78] lora: fix embassy docs build. --- embassy-lora/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index 784cc228..604358c5 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml @@ -9,9 +9,9 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-lora-v$VERSION/em src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-lora/src/" features = ["time", "defmt"] flavors = [ - { name = "sx126x", target = "thumbv7em-none-eabihf", features = ["sx126x"] }, - { name = "sx127x", target = "thumbv7em-none-eabihf", features = ["sx127x", "embassy-stm32/stm32wl55jc-cm4", "embassy-stm32/time-driver-any"] }, - { name = "stm32wl", target = "thumbv7em-none-eabihf", features = ["stm32wl", "embassy-stm32/stm32wl55jc-cm4", "embassy-stm32/time-driver-any"] }, + { name = "sx126x", target = "thumbv7em-none-eabihf", features = ["sx126x"] }, + { name = "sx127x", target = "thumbv7em-none-eabihf", features = ["sx127x"] }, + { name = "stm32wl", target = "thumbv7em-none-eabihf", features = ["stm32wl", "embassy-stm32?/stm32wl55jc-cm4", "embassy-stm32?/time-driver-any"] }, ] [lib] From 44b7fe45e279f713a49f92e786f358af6c68e157 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 10 Apr 2023 15:11:07 +0200 Subject: [PATCH 74/78] stm32/gpdma: fix race condition when resetting channel when done. --- embassy-stm32/src/dma/gpdma.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 442fee48..6f26fd19 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -190,6 +190,10 @@ mod low_level_api { fence(Ordering::SeqCst); let ch = dma.ch(channel_number as _); + + // Reset ch + ch.cr().write(|w| w.set_reset(true)); + ch.llr().write(|_| {}); // no linked list ch.tr1().write(|w| { w.set_sdw(data_size.into()); @@ -252,7 +256,7 @@ mod low_level_api { /// Gets the running status of the channel pub unsafe fn is_running(dma: Gpdma, ch: u8) -> bool { let ch = dma.ch(ch as _); - !ch.sr().read().idlef() + !ch.sr().read().tcf() } /// Gets the total remaining transfers for the channel @@ -291,7 +295,10 @@ mod low_level_api { } if sr.suspf() || sr.tcf() { - ch.cr().write(|w| w.set_reset(true)); + // disable all xxIEs to prevent the irq from firing again. + ch.cr().write(|_| {}); + + // Wake the future. It'll look at tcf and see it's set. STATE.channels[state_index].waker.wake(); } } From 4ef8e008e8e052e5e2f84b36733284b19d246794 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 10 Apr 2023 15:11:23 +0200 Subject: [PATCH 75/78] stm32/spi: add v4/v5 support (for H5). --- embassy-stm32/src/spi/mod.rs | 72 ++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 1f170887..481ea4ab 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -258,7 +258,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { w.set_spe(true); }); } - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] unsafe { T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); T::REGS.cfg2().modify(|w| { @@ -317,7 +317,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { }); } - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] unsafe { T::REGS.cfg2().modify(|w| { w.set_cpha(cpha); @@ -330,7 +330,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { pub fn get_current_config(&self) -> Config { #[cfg(any(spi_v1, spi_f1, spi_v2))] let cfg = unsafe { T::REGS.cr1().read() }; - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] let cfg = unsafe { T::REGS.cfg2().read() }; let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { Polarity::IdleLow @@ -383,7 +383,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { w.set_spe(true); }); } - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] unsafe { T::REGS.cr1().modify(|w| { w.set_csusp(true); @@ -429,7 +429,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { T::REGS.cr1().modify(|w| { w.set_spe(true); }); - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] T::REGS.cr1().modify(|w| { w.set_cstart(true); }); @@ -459,7 +459,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { } // SPIv3 clears rxfifo on SPE=0 - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] flush_rx_fifo(T::REGS); set_rxdmaen(T::REGS, true); @@ -481,7 +481,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { T::REGS.cr1().modify(|w| { w.set_spe(true); }); - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] T::REGS.cr1().modify(|w| { w.set_cstart(true); }); @@ -514,7 +514,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { } // SPIv3 clears rxfifo on SPE=0 - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] flush_rx_fifo(T::REGS); set_rxdmaen(T::REGS, true); @@ -534,7 +534,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { T::REGS.cr1().modify(|w| { w.set_spe(true); }); - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] T::REGS.cr1().modify(|w| { w.set_cstart(true); }); @@ -619,9 +619,9 @@ impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { } } -#[cfg(not(any(spi_v3, spi_v4)))] +#[cfg(not(any(spi_v3, spi_v4, spi_v5)))] use vals::Br; -#[cfg(any(spi_v3, spi_v4))] +#[cfg(any(spi_v3, spi_v4, spi_v5))] use vals::Mbr as Br; fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { @@ -647,17 +647,17 @@ trait RegsExt { impl RegsExt for Regs { fn tx_ptr(&self) -> *mut W { - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] let dr = self.dr(); - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] let dr = self.txdr(); dr.ptr() as *mut W } fn rx_ptr(&self) -> *mut W { - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] let dr = self.dr(); - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] let dr = self.rxdr(); dr.ptr() as *mut W } @@ -667,22 +667,22 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> { if sr.ovr() { return Err(Error::Overrun); } - #[cfg(not(any(spi_f1, spi_v3, spi_v4)))] + #[cfg(not(any(spi_f1, spi_v3, spi_v4, spi_v5)))] if sr.fre() { return Err(Error::Framing); } - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] if sr.tifre() { return Err(Error::Framing); } if sr.modf() { return Err(Error::ModeFault); } - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] if sr.crcerr() { return Err(Error::Crc); } - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] if sr.crce() { return Err(Error::Crc); } @@ -696,11 +696,11 @@ fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { check_error_flags(sr)?; - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] if sr.txe() { return Ok(()); } - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] if sr.txp() { return Ok(()); } @@ -713,11 +713,11 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { check_error_flags(sr)?; - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] if sr.rxne() { return Ok(()); } - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] if sr.rxp() { return Ok(()); } @@ -726,11 +726,11 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { fn flush_rx_fifo(regs: Regs) { unsafe { - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] while regs.sr().read().rxne() { let _ = regs.dr().read(); } - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] while regs.sr().read().rxp() { let _ = regs.rxdr().read(); } @@ -739,11 +739,11 @@ fn flush_rx_fifo(regs: Regs) { fn set_txdmaen(regs: Regs, val: bool) { unsafe { - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] regs.cr2().modify(|reg| { reg.set_txdmaen(val); }); - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] regs.cfg1().modify(|reg| { reg.set_txdmaen(val); }); @@ -752,11 +752,11 @@ fn set_txdmaen(regs: Regs, val: bool) { fn set_rxdmaen(regs: Regs, val: bool) { unsafe { - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] regs.cr2().modify(|reg| { reg.set_rxdmaen(val); }); - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] regs.cfg1().modify(|reg| { reg.set_rxdmaen(val); }); @@ -768,9 +768,9 @@ fn finish_dma(regs: Regs) { #[cfg(spi_v2)] while regs.sr().read().ftlvl() > 0 {} - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] while !regs.sr().read().txc() {} - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] while regs.sr().read().bsy() {} // Disable the spi peripheral @@ -780,12 +780,12 @@ fn finish_dma(regs: Regs) { // The peripheral automatically disables the DMA stream on completion without error, // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. - #[cfg(not(any(spi_v3, spi_v4)))] + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] regs.cr2().modify(|reg| { reg.set_txdmaen(false); reg.set_rxdmaen(false); }); - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] regs.cfg1().modify(|reg| { reg.set_txdmaen(false); reg.set_rxdmaen(false); @@ -799,7 +799,7 @@ fn transfer_word(regs: Regs, tx_word: W) -> Result { unsafe { ptr::write_volatile(regs.tx_ptr(), tx_word); - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] regs.cr1().modify(|reg| reg.set_cstart(true)); } @@ -970,7 +970,7 @@ pub(crate) mod sealed { } } - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] pub fn dsize(&self) -> u8 { match self { WordSize::EightBit => 0b0111, @@ -978,7 +978,7 @@ pub(crate) mod sealed { } } - #[cfg(any(spi_v3, spi_v4))] + #[cfg(any(spi_v3, spi_v4, spi_v5))] pub fn _frxth(&self) -> vals::Fthlv { match self { WordSize::EightBit => vals::Fthlv::ONEFRAME, From dbfd28130f95a6f8df81823253ec71c1ae6d36e6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 10 Apr 2023 15:12:47 +0200 Subject: [PATCH 76/78] stm32/test: add h5 hil tests. --- ci.sh | 1 + tests/stm32/Cargo.toml | 1 + tests/stm32/src/bin/gpio.rs | 2 ++ tests/stm32/src/bin/spi.rs | 19 +++++++++++-------- tests/stm32/src/bin/spi_dma.rs | 18 ++++++++++-------- tests/stm32/src/bin/usart.rs | 2 ++ tests/stm32/src/bin/usart_dma.rs | 9 +++++++++ 7 files changed, 36 insertions(+), 16 deletions(-) diff --git a/ci.sh b/ci.sh index 82b72ae3..47bf5d66 100755 --- a/ci.sh +++ b/ci.sh @@ -119,6 +119,7 @@ cargo batch \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/nucleo-stm32g071rb \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/nucleo-stm32h755zi \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/nucleo-stm32h563zi \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \ --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 6070a5a8..bd181f23 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -11,6 +11,7 @@ stm32g071rb = ["embassy-stm32/stm32g071rb"] # Nucleo stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo stm32h755zi = ["embassy-stm32/stm32h755zi-cm7"] # Nucleo stm32wb55rg = ["embassy-stm32/stm32wb55rg"] # Nucleo +stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board [dependencies] diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs index 18fd85d4..6a36df8c 100644 --- a/tests/stm32/src/bin/gpio.rs +++ b/tests/stm32/src/bin/gpio.rs @@ -30,6 +30,8 @@ async fn main(_spawner: Spawner) { let (mut a, mut b) = (p.PB6, p.PB7); #[cfg(feature = "stm32u585ai")] let (mut a, mut b) = (p.PD9, p.PD8); + #[cfg(feature = "stm32h563zi")] + let (mut a, mut b) = (p.PB6, p.PB7); // Test initial output { diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs index 1c5dc87c..bf8098b1 100644 --- a/tests/stm32/src/bin/spi.rs +++ b/tests/stm32/src/bin/spi.rs @@ -17,22 +17,25 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); #[cfg(feature = "stm32f103c8")] - let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); + let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); #[cfg(feature = "stm32f429zi")] - let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); + let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); #[cfg(feature = "stm32h755zi")] - let (sck, mosi, miso) = (p.PA5, p.PB5, p.PA6); + let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PB5, p.PA6); #[cfg(feature = "stm32g491re")] - let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); + let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); #[cfg(feature = "stm32g071rb")] - let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); + let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); #[cfg(feature = "stm32wb55rg")] - let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); + let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); #[cfg(feature = "stm32u585ai")] - let (sck, mosi, miso) = (p.PE13, p.PE15, p.PE14); + let (spi, sck, mosi, miso) = (p.SPI1, p.PE13, p.PE15, p.PE14); + #[cfg(feature = "stm32h563zi")] + let (spi, sck, mosi, miso) = (p.SPI4, p.PE12, p.PE14, p.PE13); + info!("asdfa;"); let mut spi = Spi::new( - p.SPI1, + spi, sck, // Arduino D13 mosi, // Arduino D11 miso, // Arduino D12 diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs index cb2152e0..b3dad813 100644 --- a/tests/stm32/src/bin/spi_dma.rs +++ b/tests/stm32/src/bin/spi_dma.rs @@ -16,22 +16,24 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); #[cfg(feature = "stm32f103c8")] - let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH3, p.DMA1_CH2); + let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH3, p.DMA1_CH2); #[cfg(feature = "stm32f429zi")] - let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA2_CH3, p.DMA2_CH2); + let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA2_CH3, p.DMA2_CH2); #[cfg(feature = "stm32h755zi")] - let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PB5, p.PA6, p.DMA1_CH0, p.DMA1_CH1); + let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PB5, p.PA6, p.DMA1_CH0, p.DMA1_CH1); #[cfg(feature = "stm32g491re")] - let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); + let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32g071rb")] - let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); + let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32wb55rg")] - let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); + let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32u585ai")] - let (sck, mosi, miso, tx_dma, rx_dma) = (p.PE13, p.PE15, p.PE14, p.GPDMA1_CH0, p.GPDMA1_CH1); + let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PE13, p.PE15, p.PE14, p.GPDMA1_CH0, p.GPDMA1_CH1); + #[cfg(feature = "stm32h563zi")] + let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI4, p.PE12, p.PE14, p.PE13, p.GPDMA1_CH0, p.GPDMA1_CH1); let mut spi = Spi::new( - p.SPI1, + spi, sck, // Arduino D13 mosi, // Arduino D11 miso, // Arduino D12 diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index af55867f..52409567 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -32,6 +32,8 @@ async fn main(_spawner: Spawner) { let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); #[cfg(feature = "stm32u585ai")] let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3)); + #[cfg(feature = "stm32h563zi")] + let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1)); let config = Config::default(); let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config); diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index d12605a9..3f70791c 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs @@ -62,6 +62,15 @@ async fn main(_spawner: Spawner) { p.GPDMA1_CH0, p.GPDMA1_CH1, ); + #[cfg(feature = "stm32h563zi")] + let (tx, rx, usart, irq, tx_dma, rx_dma) = ( + p.PB6, + p.PB7, + p.LPUART1, + interrupt::take!(LPUART1), + p.GPDMA1_CH0, + p.GPDMA1_CH1, + ); let config = Config::default(); let mut usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); From 6760258ec39c629b911a417d0a554bc6167c5b5b Mon Sep 17 00:00:00 2001 From: Glenn Dirkx Date: Mon, 10 Apr 2023 16:20:47 +0200 Subject: [PATCH 77/78] fix I2C controller problems after NACK --- embassy-stm32/src/i2c/v2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 28663fb3..7218f770 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -262,7 +262,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if T::regs().isr().read().txis() { T::regs().txdr().write(|w| w.set_txdata(0)); } - if T::regs().isr().read().txe() { + if !T::regs().isr().read().txe() { T::regs().isr().modify(|w| w.set_txe(true)) } } From cae683cd41261312e8a8da70c862832f0acb847c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 10 Apr 2023 21:12:48 +0200 Subject: [PATCH 78/78] stm32: update pac. --- 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 4ab30622..a8ebacd2 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,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 = "4" +stm32-metapac = "5" vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -73,7 +73,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { version = "4", default-features = false, features = ["metadata"]} +stm32-metapac = { version = "5", default-features = false, features = ["metadata"]} [features] default = ["stm32-metapac/rt"]