From 9cf2d529b1a2de3ad526de792c49ffa454884ac9 Mon Sep 17 00:00:00 2001 From: Astro Date: Thu, 10 Dec 2020 18:04:53 +0100 Subject: [PATCH 1/2] Implement flash read/erase/program --- CHANGELOG.md | 1 + src/flash.rs | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 7 +++ 3 files changed, 173 insertions(+) create mode 100644 src/flash.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 082de926..2ddc6da5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -131,6 +131,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). STM32F417, STM32F423, STM32F427, STM32F429, STM32F437, STM32F439, STM32F469, and STM32F479 [#262] - Added `gpio::gpiox::Pxi::downgrade2` method [#272] +- Added flash driver [#231]: https://github.com/stm32-rs/stm32f4xx-hal/pull/231 [#262]: https://github.com/stm32-rs/stm32f4xx-hal/pull/262 diff --git a/src/flash.rs b/src/flash.rs new file mode 100644 index 00000000..13bb4f59 --- /dev/null +++ b/src/flash.rs @@ -0,0 +1,165 @@ +use crate::signature::FlashSize; +use crate::stm32::FLASH; +use core::{ptr, slice}; + +/// Flash erase/program error +#[derive(Debug, Clone, Copy)] +pub enum Error { + ProgrammingSequence, + ProgrammingParallelism, + ProgrammingAlignment, + WriteProtection, + Operation, +} + +impl Error { + fn read(flash: &FLASH) -> Option { + let sr = flash.sr.read(); + if sr.pgserr().bit() { + Some(Error::ProgrammingSequence) + } else if sr.pgperr().bit() { + Some(Error::ProgrammingParallelism) + } else if sr.pgaerr().bit() { + Some(Error::ProgrammingAlignment) + } else if sr.wrperr().bit() { + Some(Error::WriteProtection) + } else if sr.operr().bit() { + Some(Error::Operation) + } else { + None + } + } +} + +/// Flash methods implemented for `stm32::FLASH` +pub trait FlashExt { + /// Memory-mapped address + fn address(&self) -> usize; + /// Size in bytes + fn len(&self) -> usize; + /// Returns a read-only view of flash memory + fn read(&self) -> &[u8] { + let ptr = self.address() as *const _; + unsafe { slice::from_raw_parts(ptr, self.len()) } + } + /// Unlock flash for erasing/programming until this method's + /// result is dropped + fn unlocked(&mut self) -> UnlockedFlash; +} + +impl FlashExt for FLASH { + fn address(&self) -> usize { + 0x0800_0000 + } + + fn len(&self) -> usize { + FlashSize::get().bytes() + } + + fn unlocked(&mut self) -> UnlockedFlash { + unlock(self); + UnlockedFlash { flash: self } + } +} + +const PSIZE_X8: u8 = 0b00; + +/// Result of `FlashExt::unlocked()` +pub struct UnlockedFlash<'a> { + flash: &'a mut FLASH, +} + +/// Automatically lock flash erase/program when leaving scope +impl Drop for UnlockedFlash<'_> { + fn drop(&mut self) { + lock(&self.flash); + } +} + +impl UnlockedFlash<'_> { + /// Erase a flash sector + /// + /// Refer to the reference manual to see which sector corresponds + /// to which memory address. + pub fn erase(&mut self, sector: u8) -> Result<(), Error> { + let snb = if sector < 12 { sector } else { sector + 4 }; + + #[rustfmt::skip] + self.flash.cr.modify(|_, w| unsafe { + w + // start + .strt().set_bit() + .psize().bits(PSIZE_X8) + // sector number + .snb().bits(snb) + // sectore erase + .ser().set_bit() + // no programming + .pg().clear_bit() + }); + self.wait_ready(); + self.ok() + } + + /// Program bytes with offset into flash memory, + /// aligned to 128-bit rows + pub fn program<'a, I>(&mut self, mut offset: usize, mut bytes: I) -> Result<(), Error> + where + I: Iterator, + { + let ptr = self.flash.address() as *mut u8; + let mut bytes_written = 1; + while bytes_written > 0 { + bytes_written = 0; + let amount = 16 - (offset % 16); + + #[rustfmt::skip] + self.flash.cr.modify(|_, w| unsafe { + w + .psize().bits(PSIZE_X8) + // no sector erase + .ser().clear_bit() + // programming + .pg().set_bit() + }); + for _ in 0..amount { + match bytes.next() { + Some(byte) => { + unsafe { + ptr::write_volatile(ptr.add(offset), *byte); + } + offset += 1; + bytes_written += 1; + } + None => break, + } + } + self.wait_ready(); + self.ok()?; + } + self.flash.cr.modify(|_, w| w.pg().clear_bit()); + + Ok(()) + } + + fn ok(&self) -> Result<(), Error> { + Error::read(&self.flash).map(Err).unwrap_or(Ok(())) + } + + fn wait_ready(&self) { + while self.flash.sr.read().bsy().bit() {} + } +} + +const UNLOCK_KEY1: u32 = 0x45670123; +const UNLOCK_KEY2: u32 = 0xCDEF89AB; + +fn unlock(flash: &FLASH) { + flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY1) }); + flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY2) }); + assert!(!flash.cr.read().lock().bit()) +} + +fn lock(flash: &FLASH) { + flash.cr.modify(|_, w| w.lock().set_bit()); +} diff --git a/src/lib.rs b/src/lib.rs index d8b3c434..2fedc788 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,9 +23,12 @@ compile_error!( stm32f479" ); +#[cfg(feature = "device-selected")] pub use embedded_hal as hal; +#[cfg(feature = "device-selected")] pub use nb; +#[cfg(feature = "device-selected")] pub use nb::block; #[cfg(feature = "stm32f401")] @@ -141,6 +144,8 @@ pub use pac as stm32; pub mod dma; #[cfg(feature = "device-selected")] pub mod dwt; +#[cfg(feature = "device-selected")] +pub mod flash; #[cfg(all( feature = "device-selected", feature = "fsmc_lcd", @@ -176,7 +181,9 @@ pub mod timer; #[cfg(feature = "device-selected")] pub mod watchdog; +#[cfg(feature = "device-selected")] mod sealed { pub trait Sealed {} } +#[cfg(feature = "device-selected")] pub(crate) use sealed::Sealed; From 68ae4f12ec93651913af147659bbf006743d22fa Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 16 Jul 2021 14:17:23 +0300 Subject: [PATCH 2/2] clippy --- src/flash.rs | 1 + src/gpio/convert.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/flash.rs b/src/flash.rs index 13bb4f59..22a06803 100644 --- a/src/flash.rs +++ b/src/flash.rs @@ -32,6 +32,7 @@ impl Error { } /// Flash methods implemented for `stm32::FLASH` +#[allow(clippy::len_without_is_empty)] pub trait FlashExt { /// Memory-mapped address fn address(&self) -> usize; diff --git a/src/gpio/convert.rs b/src/gpio/convert.rs index 8809242d..722740d8 100644 --- a/src/gpio/convert.rs +++ b/src/gpio/convert.rs @@ -603,17 +603,17 @@ impl Pin { fn mode(&mut self) { let offset = 2 * N; unsafe { - &(*Gpio::

::ptr()).pupdr.modify(|r, w| { + (*Gpio::

::ptr()).pupdr.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (u32::from(M::PUPDR) << offset)) }); if let Some(otyper) = M::OTYPER { - &(*Gpio::

::ptr()) + (*Gpio::

::ptr()) .otyper .modify(|r, w| w.bits(r.bits() & !(0b1 << N) | (u32::from(otyper) << N))); } - &(*Gpio::

::ptr()).moder.modify(|r, w| { + (*Gpio::

::ptr()).moder.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (u32::from(M::MODER) << offset)) }); }