aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-boot/rp/src/lib.rs14
-rw-r--r--embassy-rp/Cargo.toml3
-rw-r--r--embassy-rp/src/flash.rs203
-rw-r--r--examples/boot/application/rp/src/bin/a.rs4
-rw-r--r--examples/rp/src/bin/flash.rs42
-rw-r--r--tests/rp/src/bin/flash.rs14
6 files changed, 254 insertions, 26 deletions
diff --git a/embassy-boot/rp/src/lib.rs b/embassy-boot/rp/src/lib.rs
index 25329f9e9..35fc104ec 100644
--- a/embassy-boot/rp/src/lib.rs
+++ b/embassy-boot/rp/src/lib.rs
@@ -6,7 +6,7 @@ mod fmt;
6#[cfg(feature = "nightly")] 6#[cfg(feature = "nightly")]
7pub use embassy_boot::FirmwareUpdater; 7pub use embassy_boot::FirmwareUpdater;
8pub use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareUpdaterConfig, State}; 8pub use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareUpdaterConfig, State};
9use embassy_rp::flash::{Flash, ERASE_SIZE}; 9use embassy_rp::flash::{Blocking, Flash, ERASE_SIZE};
10use embassy_rp::peripherals::{FLASH, WATCHDOG}; 10use embassy_rp::peripherals::{FLASH, WATCHDOG};
11use embassy_rp::watchdog::Watchdog; 11use embassy_rp::watchdog::Watchdog;
12use embassy_time::Duration; 12use embassy_time::Duration;
@@ -58,14 +58,14 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>
58 58
59/// A flash implementation that will feed a watchdog when touching flash. 59/// A flash implementation that will feed a watchdog when touching flash.
60pub struct WatchdogFlash<'d, const SIZE: usize> { 60pub struct WatchdogFlash<'d, const SIZE: usize> {
61 flash: Flash<'d, FLASH, SIZE>, 61 flash: Flash<'d, FLASH, Blocking, SIZE>,
62 watchdog: Watchdog, 62 watchdog: Watchdog,
63} 63}
64 64
65impl<'d, const SIZE: usize> WatchdogFlash<'d, SIZE> { 65impl<'d, const SIZE: usize> WatchdogFlash<'d, SIZE> {
66 /// Start a new watchdog with a given flash and watchdog peripheral and a timeout 66 /// Start a new watchdog with a given flash and watchdog peripheral and a timeout
67 pub fn start(flash: FLASH, watchdog: WATCHDOG, timeout: Duration) -> Self { 67 pub fn start(flash: FLASH, watchdog: WATCHDOG, timeout: Duration) -> Self {
68 let flash: Flash<'_, FLASH, SIZE> = Flash::new(flash); 68 let flash = Flash::<_, Blocking, SIZE>::new(flash);
69 let mut watchdog = Watchdog::new(watchdog); 69 let mut watchdog = Watchdog::new(watchdog);
70 watchdog.start(timeout); 70 watchdog.start(timeout);
71 Self { flash, watchdog } 71 Self { flash, watchdog }
@@ -73,12 +73,12 @@ impl<'d, const SIZE: usize> WatchdogFlash<'d, SIZE> {
73} 73}
74 74
75impl<'d, const SIZE: usize> ErrorType for WatchdogFlash<'d, SIZE> { 75impl<'d, const SIZE: usize> ErrorType for WatchdogFlash<'d, SIZE> {
76 type Error = <Flash<'d, FLASH, SIZE> as ErrorType>::Error; 76 type Error = <Flash<'d, FLASH, Blocking, SIZE> as ErrorType>::Error;
77} 77}
78 78
79impl<'d, const SIZE: usize> NorFlash for WatchdogFlash<'d, SIZE> { 79impl<'d, const SIZE: usize> NorFlash for WatchdogFlash<'d, SIZE> {
80 const WRITE_SIZE: usize = <Flash<'d, FLASH, SIZE> as NorFlash>::WRITE_SIZE; 80 const WRITE_SIZE: usize = <Flash<'d, FLASH, Blocking, SIZE> as NorFlash>::WRITE_SIZE;
81 const ERASE_SIZE: usize = <Flash<'d, FLASH, SIZE> as NorFlash>::ERASE_SIZE; 81 const ERASE_SIZE: usize = <Flash<'d, FLASH, Blocking, SIZE> as NorFlash>::ERASE_SIZE;
82 82
83 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { 83 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
84 self.watchdog.feed(); 84 self.watchdog.feed();
@@ -91,7 +91,7 @@ impl<'d, const SIZE: usize> NorFlash for WatchdogFlash<'d, SIZE> {
91} 91}
92 92
93impl<'d, const SIZE: usize> ReadNorFlash for WatchdogFlash<'d, SIZE> { 93impl<'d, const SIZE: usize> ReadNorFlash for WatchdogFlash<'d, SIZE> {
94 const READ_SIZE: usize = <Flash<'d, FLASH, SIZE> as ReadNorFlash>::READ_SIZE; 94 const READ_SIZE: usize = <Flash<'d, FLASH, Blocking, SIZE> as ReadNorFlash>::READ_SIZE;
95 fn read(&mut self, offset: u32, data: &mut [u8]) -> Result<(), Self::Error> { 95 fn read(&mut self, offset: u32, data: &mut [u8]) -> Result<(), Self::Error> {
96 self.watchdog.feed(); 96 self.watchdog.feed();
97 self.flash.read(offset, data) 97 self.flash.read(offset, data)
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index b53c7a01a..6310ffb62 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -48,7 +48,7 @@ boot2-w25x10cl = []
48run-from-ram = [] 48run-from-ram = []
49 49
50# Enable nightly-only features 50# Enable nightly-only features
51nightly = ["embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"] 51nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"]
52 52
53# Implement embedded-hal 1.0 alpha traits. 53# Implement embedded-hal 1.0 alpha traits.
54# Implement embedded-hal-async traits if `nightly` is set as well. 54# Implement embedded-hal-async traits if `nightly` is set as well.
@@ -73,6 +73,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
73chrono = { version = "0.4", default-features = false, optional = true } 73chrono = { version = "0.4", default-features = false, optional = true }
74embedded-io = { version = "0.4.0", features = ["async"], optional = true } 74embedded-io = { version = "0.4.0", features = ["async"], optional = true }
75embedded-storage = { version = "0.3" } 75embedded-storage = { version = "0.3" }
76embedded-storage-async = { version = "0.4.0", optional = true }
76rand_core = "0.6.4" 77rand_core = "0.6.4"
77fixed = "1.23.1" 78fixed = "1.23.1"
78 79
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 0ed6808eb..70d867319 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -1,11 +1,15 @@
1use core::future::Future;
1use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::pin::Pin;
4use core::task::{Context, Poll};
2 5
3use embassy_hal_internal::Peripheral; 6use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
4use embedded_storage::nor_flash::{ 7use embedded_storage::nor_flash::{
5 check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, 8 check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind,
6 ReadNorFlash, 9 ReadNorFlash,
7}; 10};
8 11
12use crate::dma::{AnyChannel, Channel, Transfer};
9use crate::pac; 13use crate::pac;
10use crate::peripherals::FLASH; 14use crate::peripherals::FLASH;
11 15
@@ -24,6 +28,7 @@ pub const PAGE_SIZE: usize = 256;
24pub const WRITE_SIZE: usize = 1; 28pub const WRITE_SIZE: usize = 1;
25pub const READ_SIZE: usize = 1; 29pub const READ_SIZE: usize = 1;
26pub const ERASE_SIZE: usize = 4096; 30pub const ERASE_SIZE: usize = 4096;
31pub const ASYNC_READ_SIZE: usize = 4;
27 32
28/// Error type for NVMC operations. 33/// Error type for NVMC operations.
29#[derive(Debug, Copy, Clone, PartialEq, Eq)] 34#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -57,13 +62,46 @@ impl NorFlashError for Error {
57 } 62 }
58} 63}
59 64
60pub struct Flash<'d, T: Instance, const FLASH_SIZE: usize>(PhantomData<&'d mut T>); 65/// Future that waits for completion of a background read
66#[must_use = "futures do nothing unless you `.await` or poll them"]
67pub struct BackgroundRead<'a, 'd, T: Instance, const FLASH_SIZE: usize> {
68 flash: PhantomData<&'a mut Flash<'d, T, Async, FLASH_SIZE>>,
69 transfer: Transfer<'a, AnyChannel>,
70}
61 71
62impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { 72impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Future for BackgroundRead<'a, 'd, T, FLASH_SIZE> {
63 pub fn new(_flash: impl Peripheral<P = T> + 'd) -> Self { 73 type Output = ();
64 Self(PhantomData) 74 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
75 Pin::new(&mut self.transfer).poll(cx)
65 } 76 }
77}
66 78
79impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Drop for BackgroundRead<'a, 'd, T, FLASH_SIZE> {
80 fn drop(&mut self) {
81 if pac::XIP_CTRL.stream_ctr().read().0 == 0 {
82 return;
83 }
84 pac::XIP_CTRL
85 .stream_ctr()
86 .write_value(pac::xip_ctrl::regs::StreamCtr(0));
87 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
88 // Errata RP2040-E8: Perform an uncached read to make sure there's not a transfer in
89 // flight that might effect an address written to start a new transfer. This stalls
90 // until after any transfer is complete, so the address will not change anymore.
91 const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x13000000 as *const _;
92 unsafe {
93 core::ptr::read_volatile(XIP_NOCACHE_NOALLOC_BASE);
94 }
95 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
96 }
97}
98
99pub struct Flash<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> {
100 dma: Option<PeripheralRef<'d, AnyChannel>>,
101 phantom: PhantomData<(&'d mut T, M)>,
102}
103
104impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> {
67 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 105 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
68 trace!( 106 trace!(
69 "Reading from 0x{:x} to 0x{:x}", 107 "Reading from 0x{:x} to 0x{:x}",
@@ -182,6 +220,8 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
182 let ch = crate::pac::DMA.ch(n); 220 let ch = crate::pac::DMA.ch(n);
183 while ch.read_addr().read() < SRAM_LOWER && ch.ctrl_trig().read().busy() {} 221 while ch.read_addr().read() < SRAM_LOWER && ch.ctrl_trig().read().busy() {}
184 } 222 }
223 // Wait for completion of any background reads
224 while pac::XIP_CTRL.stream_ctr().read().0 > 0 {}
185 225
186 // Run our flash operation in RAM 226 // Run our flash operation in RAM
187 operation(); 227 operation();
@@ -210,11 +250,73 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
210 } 250 }
211} 251}
212 252
213impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, FLASH_SIZE> { 253impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> {
254 pub fn new(_flash: impl Peripheral<P = T> + 'd) -> Self {
255 Self {
256 dma: None,
257 phantom: PhantomData,
258 }
259 }
260}
261
262impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> {
263 pub fn new(_flash: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = impl Channel> + 'd) -> Self {
264 into_ref!(dma);
265 Self {
266 dma: Some(dma.map_into()),
267 phantom: PhantomData,
268 }
269 }
270
271 pub fn background_read<'a>(
272 &'a mut self,
273 offset: u32,
274 data: &'a mut [u32],
275 ) -> Result<BackgroundRead<'a, 'd, T, FLASH_SIZE>, Error> {
276 trace!(
277 "Reading in background from 0x{:x} to 0x{:x}",
278 FLASH_BASE as u32 + offset,
279 FLASH_BASE as u32 + offset + (data.len() * 4) as u32
280 );
281 // Can't use check_read because we need to enforce 4-byte alignment
282 let offset = offset as usize;
283 let length = data.len() * 4;
284 if length > self.capacity() || offset > self.capacity() - length {
285 return Err(Error::OutOfBounds);
286 }
287 if offset % 4 != 0 {
288 return Err(Error::Unaligned);
289 }
290
291 while !pac::XIP_CTRL.stat().read().fifo_empty() {
292 pac::XIP_CTRL.stream_fifo().read();
293 }
294
295 pac::XIP_CTRL
296 .stream_addr()
297 .write_value(pac::xip_ctrl::regs::StreamAddr(FLASH_BASE as u32 + offset as u32));
298 pac::XIP_CTRL
299 .stream_ctr()
300 .write_value(pac::xip_ctrl::regs::StreamCtr(data.len() as u32));
301
302 // Use the XIP AUX bus port, rather than the FIFO register access (e.x.
303 // pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on
304 // general XIP access.
305 const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _;
306 let transfer = unsafe { crate::dma::read(self.dma.as_mut().unwrap(), XIP_AUX_BASE, data, 37) };
307
308 Ok(BackgroundRead {
309 flash: PhantomData,
310 transfer,
311 })
312 }
313}
314
315impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, M, FLASH_SIZE> {
214 type Error = Error; 316 type Error = Error;
215} 317}
216 318
217impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, FLASH_SIZE> { 319impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, M, FLASH_SIZE> {
218 const READ_SIZE: usize = READ_SIZE; 320 const READ_SIZE: usize = READ_SIZE;
219 321
220 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 322 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
@@ -226,9 +328,9 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, FLA
226 } 328 }
227} 329}
228 330
229impl<'d, T: Instance, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, FLASH_SIZE> {} 331impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, M, FLASH_SIZE> {}
230 332
231impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_SIZE> { 333impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, M, FLASH_SIZE> {
232 const WRITE_SIZE: usize = WRITE_SIZE; 334 const WRITE_SIZE: usize = WRITE_SIZE;
233 335
234 const ERASE_SIZE: usize = ERASE_SIZE; 336 const ERASE_SIZE: usize = ERASE_SIZE;
@@ -242,6 +344,74 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_S
242 } 344 }
243} 345}
244 346
347#[cfg(feature = "nightly")]
348impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash::ReadNorFlash
349 for Flash<'d, T, Async, FLASH_SIZE>
350{
351 const READ_SIZE: usize = ASYNC_READ_SIZE;
352
353 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
354 use core::mem::MaybeUninit;
355
356 // Checked early to simplify address validity checks
357 if bytes.len() % 4 != 0 {
358 return Err(Error::Unaligned);
359 }
360
361 // If the destination address is already aligned, then we can just DMA directly
362 if (bytes.as_ptr() as u32) % 4 == 0 {
363 // Safety: alignment and size have been checked for compatibility
364 let mut buf: &mut [u32] =
365 unsafe { core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut u32, bytes.len() / 4) };
366 self.background_read(offset, &mut buf)?.await;
367 return Ok(());
368 }
369
370 // Destination address is unaligned, so use an intermediate buffer
371 const REALIGN_CHUNK: usize = PAGE_SIZE;
372 // Safety: MaybeUninit requires no initialization
373 let mut buf: [MaybeUninit<u32>; REALIGN_CHUNK / 4] = unsafe { MaybeUninit::uninit().assume_init() };
374 let mut chunk_offset: usize = 0;
375 while chunk_offset < bytes.len() {
376 let chunk_size = (bytes.len() - chunk_offset).min(REALIGN_CHUNK);
377 let buf = &mut buf[..(chunk_size / 4)];
378
379 // Safety: this is written to completely by DMA before any reads
380 let buf = unsafe { &mut *(buf as *mut [MaybeUninit<u32>] as *mut [u32]) };
381 self.background_read(offset + chunk_offset as u32, buf)?.await;
382
383 // Safety: [u8] has more relaxed alignment and size requirements than [u32], so this is just aliasing
384 let buf = unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const _, buf.len() * 4) };
385 bytes[chunk_offset..(chunk_offset + chunk_size)].copy_from_slice(&buf[..chunk_size]);
386
387 chunk_offset += chunk_size;
388 }
389
390 Ok(())
391 }
392
393 fn capacity(&self) -> usize {
394 self.capacity()
395 }
396}
397
398#[cfg(feature = "nightly")]
399impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash::NorFlash
400 for Flash<'d, T, Async, FLASH_SIZE>
401{
402 const WRITE_SIZE: usize = WRITE_SIZE;
403
404 const ERASE_SIZE: usize = ERASE_SIZE;
405
406 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
407 self.erase(from, to)
408 }
409
410 async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
411 self.write(offset, bytes)
412 }
413}
414
245#[allow(dead_code)] 415#[allow(dead_code)]
246mod ram_helpers { 416mod ram_helpers {
247 use core::marker::PhantomData; 417 use core::marker::PhantomData;
@@ -699,9 +869,24 @@ mod ram_helpers {
699 869
700mod sealed { 870mod sealed {
701 pub trait Instance {} 871 pub trait Instance {}
872 pub trait Mode {}
702} 873}
703 874
704pub trait Instance: sealed::Instance {} 875pub trait Instance: sealed::Instance {}
876pub trait Mode: sealed::Mode {}
705 877
706impl sealed::Instance for FLASH {} 878impl sealed::Instance for FLASH {}
707impl Instance for FLASH {} 879impl Instance for FLASH {}
880
881macro_rules! impl_mode {
882 ($name:ident) => {
883 impl sealed::Mode for $name {}
884 impl Mode for $name {}
885 };
886}
887
888pub struct Blocking;
889pub struct Async;
890
891impl_mode!(Blocking);
892impl_mode!(Async);
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
index c8497494c..b5e1950cc 100644
--- a/examples/boot/application/rp/src/bin/a.rs
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -7,7 +7,7 @@ use core::cell::RefCell;
7use defmt_rtt as _; 7use defmt_rtt as _;
8use embassy_boot_rp::*; 8use embassy_boot_rp::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::flash::Flash; 10use embassy_rp::flash::{self, Flash};
11use embassy_rp::gpio::{Level, Output}; 11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::watchdog::Watchdog; 12use embassy_rp::watchdog::Watchdog;
13use embassy_sync::blocking_mutex::Mutex; 13use embassy_sync::blocking_mutex::Mutex;
@@ -34,7 +34,7 @@ async fn main(_s: Spawner) {
34 let mut watchdog = Watchdog::new(p.WATCHDOG); 34 let mut watchdog = Watchdog::new(p.WATCHDOG);
35 watchdog.start(Duration::from_secs(8)); 35 watchdog.start(Duration::from_secs(8));
36 36
37 let flash: Flash<_, FLASH_SIZE> = Flash::new(p.FLASH); 37 let flash = Flash::<_, flash::Blocking, FLASH_SIZE>::new(p.FLASH);
38 let flash = Mutex::new(RefCell::new(flash)); 38 let flash = Mutex::new(RefCell::new(flash));
39 39
40 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 40 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs
index 4c4982acc..88bb931d2 100644
--- a/examples/rp/src/bin/flash.rs
+++ b/examples/rp/src/bin/flash.rs
@@ -6,7 +6,7 @@
6 6
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE}; 9use embassy_rp::flash::{Async, ERASE_SIZE, FLASH_BASE};
10use embassy_rp::peripherals::FLASH; 10use embassy_rp::peripherals::FLASH;
11use embassy_time::{Duration, Timer}; 11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
@@ -25,7 +25,7 @@ async fn main(_spawner: Spawner) {
25 // https://github.com/knurling-rs/defmt/pull/683 25 // https://github.com/knurling-rs/defmt/pull/683
26 Timer::after(Duration::from_millis(10)).await; 26 Timer::after(Duration::from_millis(10)).await;
27 27
28 let mut flash = embassy_rp::flash::Flash::<_, FLASH_SIZE>::new(p.FLASH); 28 let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0);
29 29
30 // Get JEDEC id 30 // Get JEDEC id
31 let jedec = flash.jedec_id().unwrap(); 31 let jedec = flash.jedec_id().unwrap();
@@ -40,10 +40,12 @@ async fn main(_spawner: Spawner) {
40 40
41 multiwrite_bytes(&mut flash, ERASE_SIZE as u32); 41 multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
42 42
43 background_read(&mut flash, (ERASE_SIZE * 2) as u32).await;
44
43 loop {} 45 loop {}
44} 46}
45 47
46fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) { 48fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
47 info!(">>>> [multiwrite_bytes]"); 49 info!(">>>> [multiwrite_bytes]");
48 let mut read_buf = [0u8; ERASE_SIZE]; 50 let mut read_buf = [0u8; ERASE_SIZE];
49 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf)); 51 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
@@ -71,7 +73,7 @@ fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>,
71 } 73 }
72} 74}
73 75
74fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) { 76fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
75 info!(">>>> [erase_write_sector]"); 77 info!(">>>> [erase_write_sector]");
76 let mut buf = [0u8; ERASE_SIZE]; 78 let mut buf = [0u8; ERASE_SIZE];
77 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf)); 79 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
@@ -99,3 +101,35 @@ fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE
99 defmt::panic!("unexpected"); 101 defmt::panic!("unexpected");
100 } 102 }
101} 103}
104
105async fn background_read(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
106 info!(">>>> [background_read]");
107
108 let mut buf = [0u32; 8];
109 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await;
110
111 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
112 info!("Contents start with {=u32:x}", buf[0]);
113
114 defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
115
116 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await;
117 info!("Contents after erase starts with {=u32:x}", buf[0]);
118 if buf.iter().any(|x| *x != 0xFFFFFFFF) {
119 defmt::panic!("unexpected");
120 }
121
122 for b in buf.iter_mut() {
123 *b = 0xDABA1234;
124 }
125
126 defmt::unwrap!(flash.write(ADDR_OFFSET + offset, unsafe {
127 core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len() * 4)
128 }));
129
130 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await;
131 info!("Contents after write starts with {=u32:x}", buf[0]);
132 if buf.iter().any(|x| *x != 0xDABA1234) {
133 defmt::panic!("unexpected");
134 }
135}
diff --git a/tests/rp/src/bin/flash.rs b/tests/rp/src/bin/flash.rs
index cf9b86df5..c31d6decf 100644
--- a/tests/rp/src/bin/flash.rs
+++ b/tests/rp/src/bin/flash.rs
@@ -6,11 +6,11 @@ mod common;
6 6
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE}; 9use embassy_rp::flash::{Async, ERASE_SIZE, FLASH_BASE};
10use embassy_time::{Duration, Timer}; 10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13const ADDR_OFFSET: u32 = 0x4000; 13const ADDR_OFFSET: u32 = 0x8000;
14 14
15#[embassy_executor::main] 15#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
@@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
23 // https://github.com/knurling-rs/defmt/pull/683 23 // https://github.com/knurling-rs/defmt/pull/683
24 Timer::after(Duration::from_millis(10)).await; 24 Timer::after(Duration::from_millis(10)).await;
25 25
26 let mut flash = embassy_rp::flash::Flash::<_, { 2 * 1024 * 1024 }>::new(p.FLASH); 26 let mut flash = embassy_rp::flash::Flash::<_, Async, { 2 * 1024 * 1024 }>::new(p.FLASH, p.DMA_CH0);
27 27
28 // Get JEDEC id 28 // Get JEDEC id
29 let jedec = defmt::unwrap!(flash.jedec_id()); 29 let jedec = defmt::unwrap!(flash.jedec_id());
@@ -60,6 +60,14 @@ async fn main(_spawner: Spawner) {
60 defmt::panic!("unexpected"); 60 defmt::panic!("unexpected");
61 } 61 }
62 62
63 let mut buf = [0u32; ERASE_SIZE / 4];
64
65 defmt::unwrap!(flash.background_read(ADDR_OFFSET, &mut buf)).await;
66 info!("Contents after write starts with {=u32:x}", buf[0]);
67 if buf.iter().any(|x| *x != 0xDADADADA) {
68 defmt::panic!("unexpected");
69 }
70
63 info!("Test OK"); 71 info!("Test OK");
64 cortex_m::asm::bkpt(); 72 cortex_m::asm::bkpt();
65} 73}