diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 0f86684e..d09cc62f 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -55,51 +55,10 @@ pub struct Flash<'d, T: Instance, const FLASH_SIZE: usize>(PhantomData<&'d mut T impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { pub fn new(_flash: impl Peripheral

+ 'd) -> Self { - // FIXME: WHY is this needed?! - cortex_m::asm::delay(50_000); Self(PhantomData) } - /// Make sure to uphold the contract points with rp2040-flash. - /// - interrupts must be disabled - /// - DMA must not access flash memory - unsafe fn in_ram(&mut self, operation: impl FnOnce()) { - let dma_status = &mut [false; crate::dma::CHANNEL_COUNT]; - - // TODO: Make sure CORE1 is paused during the entire duration of the RAM function - - critical_section::with(|_| { - // Pause all DMA channels for the duration of the ram operation - for (number, status) in dma_status.iter_mut().enumerate() { - let ch = crate::pac::DMA.ch(number as _); - *status = ch.ctrl_trig().read().en(); - if *status { - ch.ctrl_trig().modify(|w| w.set_en(false)); - } - } - - // Run our flash operation in RAM - operation(); - - // Re-enable previously enabled DMA channels - for (number, status) in dma_status.iter().enumerate() { - let ch = crate::pac::DMA.ch(number as _); - if *status { - ch.ctrl_trig().modify(|w| w.set_en(true)); - } - } - }); - } -} - -impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, FLASH_SIZE> { - type Error = Error; -} - -impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, FLASH_SIZE> { - const READ_SIZE: usize = READ_SIZE; - - fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { check_read(self, offset, bytes.len())?; let flash_data = unsafe { core::slice::from_raw_parts((FLASH_BASE as u32 + offset) as *const u8, bytes.len()) }; @@ -108,19 +67,11 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, FLA Ok(()) } - fn capacity(&self) -> usize { + pub fn capacity(&self) -> usize { FLASH_SIZE } -} -impl<'d, T: Instance, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, FLASH_SIZE> {} - -impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_SIZE> { - const WRITE_SIZE: usize = WRITE_SIZE; - - const ERASE_SIZE: usize = ERASE_SIZE; - - fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + pub fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { check_erase(self, from, to)?; trace!( @@ -136,7 +87,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_S Ok(()) } - fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + pub fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { check_write(self, offset, bytes.len())?; trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), FLASH_BASE as u32 + offset); @@ -199,6 +150,69 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_S Ok(()) } + + /// Make sure to uphold the contract points with rp2040-flash. + /// - interrupts must be disabled + /// - DMA must not access flash memory + unsafe fn in_ram(&mut self, operation: impl FnOnce()) { + let dma_status = &mut [false; crate::dma::CHANNEL_COUNT]; + + // TODO: Make sure CORE1 is paused during the entire duration of the RAM function + + critical_section::with(|_| { + // Pause all DMA channels for the duration of the ram operation + for (number, status) in dma_status.iter_mut().enumerate() { + let ch = crate::pac::DMA.ch(number as _); + *status = ch.ctrl_trig().read().en(); + if *status { + ch.ctrl_trig().modify(|w| w.set_en(false)); + } + } + + // Run our flash operation in RAM + operation(); + + // Re-enable previously enabled DMA channels + for (number, status) in dma_status.iter().enumerate() { + let ch = crate::pac::DMA.ch(number as _); + if *status { + ch.ctrl_trig().modify(|w| w.set_en(true)); + } + } + }); + } +} + +impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, FLASH_SIZE> { + type Error = Error; +} + +impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, FLASH_SIZE> { + const READ_SIZE: usize = READ_SIZE; + + fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + self.read(offset, bytes) + } + + fn capacity(&self) -> usize { + self.capacity() + } +} + +impl<'d, T: Instance, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, FLASH_SIZE> {} + +impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_SIZE> { + const WRITE_SIZE: usize = WRITE_SIZE; + + const ERASE_SIZE: usize = ERASE_SIZE; + + fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + self.erase(from, to) + } + + fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + self.write(offset, bytes) + } } #[allow(dead_code)] diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs index d4dfca75..8d6b379f 100644 --- a/examples/rp/src/bin/flash.rs +++ b/examples/rp/src/bin/flash.rs @@ -6,7 +6,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE}; use embassy_rp::peripherals::FLASH; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; +use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; const ADDR_OFFSET: u32 = 0x100000; @@ -17,6 +17,12 @@ async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); info!("Hello World!"); + // add some delay to give an attached debug probe time to parse the + // defmt RTT header. Reading that header might touch flash memory, which + // interferes with flash write operations. + // https://github.com/knurling-rs/defmt/pull/683 + Timer::after(Duration::from_millis(10)).await; + let mut flash = embassy_rp::flash::Flash::<_, FLASH_SIZE>::new(p.FLASH); erase_write_sector(&mut flash, 0x00);