diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 10023e637..81d8966e9 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -11,6 +11,9 @@ use crate::Peri; use crate::_generated::FLASH_BASE; use crate::peripherals::FLASH; +#[cfg(eeprom)] +use crate::_generated::{EEPROM_BASE, EEPROM_SIZE}; + /// Internal flash memory driver. pub struct Flash<'d, MODE = Async> { pub(crate) inner: Peri<'d, FLASH>, @@ -72,6 +75,100 @@ impl<'d, MODE> Flash<'d, MODE> { } } +#[cfg(eeprom)] +impl<'d> Flash<'d, Blocking> { + fn eeprom_base(&self) -> u32 { + EEPROM_BASE as u32 + } + + fn eeprom_size(&self) -> u32 { + EEPROM_SIZE as u32 + } + + fn check_eeprom_offset(&self, offset: u32, size: u32) -> Result<(), Error> { + if offset + size > self.eeprom_size() { + Err(Error::Size) + } else { + Ok(()) + } + } + + /// Read a byte (u8) from EEPROM at the given offset. + pub fn eeprom_read_u8(&self, offset: u32) -> Result { + self.check_eeprom_offset(offset, 1)?; + let addr = self.eeprom_base() + offset; + Ok(unsafe { core::ptr::read_volatile(addr as *const u8) }) + } + + /// Read a half-word (u16) from EEPROM at the given offset. + pub fn eeprom_read_u16(&self, offset: u32) -> Result { + if offset % 2 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 2)?; + let addr = self.eeprom_base() + offset; + Ok(unsafe { core::ptr::read_volatile(addr as *const u16) }) + } + + /// Read a word (u32) from EEPROM at the given offset. + pub fn eeprom_read_u32(&self, offset: u32) -> Result { + if offset % 4 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 4)?; + let addr = self.eeprom_base() + offset; + Ok(unsafe { core::ptr::read_volatile(addr as *const u32) }) + } + + /// Write a byte (u8) to EEPROM at the given offset. + pub fn eeprom_write_u8(&mut self, offset: u32, value: u8) -> Result<(), Error> { + self.check_eeprom_offset(offset, 1)?; + let addr = self.eeprom_base() + offset; + unsafe { + family::unlock(); + core::ptr::write_volatile(addr as *mut u8, value); + family::wait_ready_blocking()?; + family::clear_all_err(); + family::lock(); + } + Ok(()) + } + + /// Write a half-word (u16) to EEPROM at the given offset. + pub fn eeprom_write_u16(&mut self, offset: u32, value: u16) -> Result<(), Error> { + if offset % 2 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 2)?; + let addr = self.eeprom_base() + offset; + unsafe { + family::unlock(); + core::ptr::write_volatile(addr as *mut u16, value); + family::wait_ready_blocking()?; + family::clear_all_err(); + family::lock(); + } + Ok(()) + } + + /// Write a word (u32) to EEPROM at the given offset. + pub fn eeprom_write_u32(&mut self, offset: u32, value: u32) -> Result<(), Error> { + if offset % 4 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 4)?; + let addr = self.eeprom_base() + offset; + unsafe { + family::unlock(); + core::ptr::write_volatile(addr as *mut u32, value); + family::wait_ready_blocking()?; + family::clear_all_err(); + family::lock(); + } + Ok(()) + } +} + pub(super) 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); diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 65cea005c..1b82704ec 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -162,7 +162,7 @@ pub(crate) unsafe fn clear_all_err() { pac::FLASH.nssr().modify(|_| {}); } -unsafe fn wait_ready_blocking() -> Result<(), Error> { +pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { loop { #[cfg(not(flash_l5))] {