aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-03-05 02:55:00 +0100
committerDario Nieuwenhuis <[email protected]>2023-03-05 02:55:00 +0100
commitf7dfc49c5c40d70852d6d3c7313973adf97e4716 (patch)
tree098db6120048536095b6b24e775dd62a187bc86f
parent8eb8ea617419726915834555266e37568b8504e0 (diff)
nrf/qspi: add _raw variants of methods that don't do bounds checks.
Useful for the nRF7002, which presents as a "fake" QSPI flash, and the "capacity" concept doesn't really apply to it.
-rw-r--r--embassy-nrf/src/qspi.rs90
-rw-r--r--examples/nrf52840/src/bin/qspi.rs3
-rw-r--r--examples/nrf52840/src/bin/qspi_lowpower.rs3
3 files changed, 76 insertions, 20 deletions
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 3f7f464d0..d514e0274 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -329,12 +329,10 @@ impl<'d, T: Instance> Qspi<'d, T> {
329 } 329 }
330 330
331 fn start_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { 331 fn start_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
332 // TODO: Return these as errors instead.
332 assert_eq!(data.as_ptr() as u32 % 4, 0); 333 assert_eq!(data.as_ptr() as u32 % 4, 0);
333 assert_eq!(data.len() as u32 % 4, 0); 334 assert_eq!(data.len() as u32 % 4, 0);
334 assert_eq!(address % 4, 0); 335 assert_eq!(address % 4, 0);
335 if address > self.capacity {
336 return Err(Error::OutOfBounds);
337 }
338 336
339 let r = T::regs(); 337 let r = T::regs();
340 338
@@ -350,14 +348,11 @@ impl<'d, T: Instance> Qspi<'d, T> {
350 } 348 }
351 349
352 fn start_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { 350 fn start_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
351 // TODO: Return these as errors instead.
353 assert_eq!(data.as_ptr() as u32 % 4, 0); 352 assert_eq!(data.as_ptr() as u32 % 4, 0);
354 assert_eq!(data.len() as u32 % 4, 0); 353 assert_eq!(data.len() as u32 % 4, 0);
355 assert_eq!(address % 4, 0); 354 assert_eq!(address % 4, 0);
356 355
357 if address > self.capacity {
358 return Err(Error::OutOfBounds);
359 }
360
361 let r = T::regs(); 356 let r = T::regs();
362 r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); 357 r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
363 r.write.dst.write(|w| unsafe { w.dst().bits(address) }); 358 r.write.dst.write(|w| unsafe { w.dst().bits(address) });
@@ -371,10 +366,8 @@ impl<'d, T: Instance> Qspi<'d, T> {
371 } 366 }
372 367
373 fn start_erase(&mut self, address: u32) -> Result<(), Error> { 368 fn start_erase(&mut self, address: u32) -> Result<(), Error> {
369 // TODO: Return these as errors instead.
374 assert_eq!(address % 4096, 0); 370 assert_eq!(address % 4096, 0);
375 if address > self.capacity {
376 return Err(Error::OutOfBounds);
377 }
378 371
379 let r = T::regs(); 372 let r = T::regs();
380 r.erase.ptr.write(|w| unsafe { w.ptr().bits(address) }); 373 r.erase.ptr.write(|w| unsafe { w.ptr().bits(address) });
@@ -387,8 +380,12 @@ impl<'d, T: Instance> Qspi<'d, T> {
387 Ok(()) 380 Ok(())
388 } 381 }
389 382
390 /// Read data from the flash memory. 383 /// Raw QSPI read.
391 pub async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { 384 ///
385 /// The difference with `read` is that this does not do bounds checks
386 /// against the flash capacity. It is intended for use when QSPI is used as
387 /// a raw bus, not with flash memory.
388 pub async fn read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
392 let ondrop = OnDrop::new(Self::blocking_wait_ready); 389 let ondrop = OnDrop::new(Self::blocking_wait_ready);
393 390
394 self.start_read(address, data)?; 391 self.start_read(address, data)?;
@@ -399,8 +396,12 @@ impl<'d, T: Instance> Qspi<'d, T> {
399 Ok(()) 396 Ok(())
400 } 397 }
401 398
402 /// Write data to the flash memory. 399 /// Raw QSPI write.
403 pub async fn write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { 400 ///
401 /// The difference with `write` is that this does not do bounds checks
402 /// against the flash capacity. It is intended for use when QSPI is used as
403 /// a raw bus, not with flash memory.
404 pub async fn write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
404 let ondrop = OnDrop::new(Self::blocking_wait_ready); 405 let ondrop = OnDrop::new(Self::blocking_wait_ready);
405 406
406 self.start_write(address, data)?; 407 self.start_write(address, data)?;
@@ -411,8 +412,46 @@ impl<'d, T: Instance> Qspi<'d, T> {
411 Ok(()) 412 Ok(())
412 } 413 }
413 414
415 /// Raw QSPI read, blocking version.
416 ///
417 /// The difference with `blocking_read` is that this does not do bounds checks
418 /// against the flash capacity. It is intended for use when QSPI is used as
419 /// a raw bus, not with flash memory.
420 pub fn blocking_read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
421 self.start_read(address, data)?;
422 Self::blocking_wait_ready();
423 Ok(())
424 }
425
426 /// Raw QSPI write, blocking version.
427 ///
428 /// The difference with `blocking_write` is that this does not do bounds checks
429 /// against the flash capacity. It is intended for use when QSPI is used as
430 /// a raw bus, not with flash memory.
431 pub fn blocking_write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
432 self.start_write(address, data)?;
433 Self::blocking_wait_ready();
434 Ok(())
435 }
436
437 /// Read data from the flash memory.
438 pub async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
439 self.bounds_check(address, data.len())?;
440 self.read_raw(address, data).await
441 }
442
443 /// Write data to the flash memory.
444 pub async fn write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
445 self.bounds_check(address, data.len())?;
446 self.write_raw(address, data).await
447 }
448
414 /// Erase a sector on the flash memory. 449 /// Erase a sector on the flash memory.
415 pub async fn erase(&mut self, address: u32) -> Result<(), Error> { 450 pub async fn erase(&mut self, address: u32) -> Result<(), Error> {
451 if address >= self.capacity {
452 return Err(Error::OutOfBounds);
453 }
454
416 let ondrop = OnDrop::new(Self::blocking_wait_ready); 455 let ondrop = OnDrop::new(Self::blocking_wait_ready);
417 456
418 self.start_erase(address)?; 457 self.start_erase(address)?;
@@ -425,24 +464,35 @@ impl<'d, T: Instance> Qspi<'d, T> {
425 464
426 /// Read data from the flash memory, blocking version. 465 /// Read data from the flash memory, blocking version.
427 pub fn blocking_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { 466 pub fn blocking_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
428 self.start_read(address, data)?; 467 self.bounds_check(address, data.len())?;
429 Self::blocking_wait_ready(); 468 self.blocking_read_raw(address, data)
430 Ok(())
431 } 469 }
432 470
433 /// Write data to the flash memory, blocking version. 471 /// Write data to the flash memory, blocking version.
434 pub fn blocking_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { 472 pub fn blocking_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
435 self.start_write(address, data)?; 473 self.bounds_check(address, data.len())?;
436 Self::blocking_wait_ready(); 474 self.blocking_write_raw(address, data)
437 Ok(())
438 } 475 }
439 476
440 /// Erase a sector on the flash memory, blocking version. 477 /// Erase a sector on the flash memory, blocking version.
441 pub fn blocking_erase(&mut self, address: u32) -> Result<(), Error> { 478 pub fn blocking_erase(&mut self, address: u32) -> Result<(), Error> {
479 if address >= self.capacity {
480 return Err(Error::OutOfBounds);
481 }
482
442 self.start_erase(address)?; 483 self.start_erase(address)?;
443 Self::blocking_wait_ready(); 484 Self::blocking_wait_ready();
444 Ok(()) 485 Ok(())
445 } 486 }
487
488 fn bounds_check(&self, address: u32, len: usize) -> Result<(), Error> {
489 let len_u32: u32 = len.try_into().map_err(|_| Error::OutOfBounds)?;
490 let end_address = address.checked_add(len_u32).ok_or(Error::OutOfBounds)?;
491 if end_address > self.capacity {
492 return Err(Error::OutOfBounds);
493 }
494 Ok(())
495 }
446} 496}
447 497
448impl<'d, T: Instance> Drop for Qspi<'d, T> { 498impl<'d, T: Instance> Drop for Qspi<'d, T> {
diff --git a/examples/nrf52840/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs
index be665149a..21a10940d 100644
--- a/examples/nrf52840/src/bin/qspi.rs
+++ b/examples/nrf52840/src/bin/qspi.rs
@@ -4,6 +4,7 @@
4 4
5use defmt::{assert_eq, info, unwrap}; 5use defmt::{assert_eq, info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::qspi::Frequency;
7use embassy_nrf::{interrupt, qspi}; 8use embassy_nrf::{interrupt, qspi};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
@@ -19,6 +20,8 @@ async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default()); 20 let p = embassy_nrf::init(Default::default());
20 // Config for the MX25R64 present in the nRF52840 DK 21 // Config for the MX25R64 present in the nRF52840 DK
21 let mut config = qspi::Config::default(); 22 let mut config = qspi::Config::default();
23 config.capacity = 8 * 1024 * 1024; // 8 MB
24 config.frequency = Frequency::M32;
22 config.read_opcode = qspi::ReadOpcode::READ4IO; 25 config.read_opcode = qspi::ReadOpcode::READ4IO;
23 config.write_opcode = qspi::WriteOpcode::PP4IO; 26 config.write_opcode = qspi::WriteOpcode::PP4IO;
24 config.write_page_size = qspi::WritePageSize::_256BYTES; 27 config.write_page_size = qspi::WritePageSize::_256BYTES;
diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs
index 5008481c1..20c903914 100644
--- a/examples/nrf52840/src/bin/qspi_lowpower.rs
+++ b/examples/nrf52840/src/bin/qspi_lowpower.rs
@@ -6,6 +6,7 @@ use core::mem;
6 6
7use defmt::{info, unwrap}; 7use defmt::{info, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::qspi::Frequency;
9use embassy_nrf::{interrupt, qspi}; 10use embassy_nrf::{interrupt, qspi};
10use embassy_time::{Duration, Timer}; 11use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
@@ -23,6 +24,8 @@ async fn main(_p: Spawner) {
23 loop { 24 loop {
24 // Config for the MX25R64 present in the nRF52840 DK 25 // Config for the MX25R64 present in the nRF52840 DK
25 let mut config = qspi::Config::default(); 26 let mut config = qspi::Config::default();
27 config.capacity = 8 * 1024 * 1024; // 8 MB
28 config.frequency = Frequency::M32;
26 config.read_opcode = qspi::ReadOpcode::READ4IO; 29 config.read_opcode = qspi::ReadOpcode::READ4IO;
27 config.write_opcode = qspi::WriteOpcode::PP4IO; 30 config.write_opcode = qspi::WriteOpcode::PP4IO;
28 config.write_page_size = qspi::WritePageSize::_256BYTES; 31 config.write_page_size = qspi::WritePageSize::_256BYTES;