diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-03-05 02:55:00 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-03-05 02:55:00 +0100 |
| commit | f7dfc49c5c40d70852d6d3c7313973adf97e4716 (patch) | |
| tree | 098db6120048536095b6b24e775dd62a187bc86f | |
| parent | 8eb8ea617419726915834555266e37568b8504e0 (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.rs | 90 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/qspi.rs | 3 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/qspi_lowpower.rs | 3 |
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 | ||
| 448 | impl<'d, T: Instance> Drop for Qspi<'d, T> { | 498 | impl<'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 | ||
| 5 | use defmt::{assert_eq, info, unwrap}; | 5 | use defmt::{assert_eq, info, unwrap}; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::qspi::Frequency; | ||
| 7 | use embassy_nrf::{interrupt, qspi}; | 8 | use embassy_nrf::{interrupt, qspi}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {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 | ||
| 7 | use defmt::{info, unwrap}; | 7 | use defmt::{info, unwrap}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::qspi::Frequency; | ||
| 9 | use embassy_nrf::{interrupt, qspi}; | 10 | use embassy_nrf::{interrupt, qspi}; |
| 10 | use embassy_time::{Duration, Timer}; | 11 | use embassy_time::{Duration, Timer}; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {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; |
