diff options
| -rw-r--r-- | embassy-nrf/src/qspi.rs | 208 | ||||
| -rw-r--r-- | examples/nrf/src/bin/qspi.rs | 1 | ||||
| -rw-r--r-- | examples/nrf/src/bin/qspi_lowpower.rs | 1 |
3 files changed, 88 insertions, 122 deletions
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 6afba4931..89262ac05 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs | |||
| @@ -1,11 +1,9 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use core::future::Future; | ||
| 4 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 5 | use core::ptr; | 4 | use core::ptr; |
| 6 | use core::task::Poll; | 5 | use core::task::Poll; |
| 7 | use embassy::interrupt::{Interrupt, InterruptExt}; | 6 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 8 | use embassy::traits::flash::{Error, Flash}; | ||
| 9 | use embassy::util::Unborrow; | 7 | use embassy::util::Unborrow; |
| 10 | use embassy_hal_common::drop::DropBomb; | 8 | use embassy_hal_common::drop::DropBomb; |
| 11 | use embassy_hal_common::unborrow; | 9 | use embassy_hal_common::unborrow; |
| @@ -58,6 +56,13 @@ impl Default for Config { | |||
| 58 | } | 56 | } |
| 59 | } | 57 | } |
| 60 | 58 | ||
| 59 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 60 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 61 | #[non_exhaustive] | ||
| 62 | pub enum Error { | ||
| 63 | // TODO add "not in data memory" error and check for it | ||
| 64 | } | ||
| 65 | |||
| 61 | pub struct Qspi<'d, T: Instance> { | 66 | pub struct Qspi<'d, T: Instance> { |
| 62 | dpm_enabled: bool, | 67 | dpm_enabled: bool, |
| 63 | phantom: PhantomData<&'d mut T>, | 68 | phantom: PhantomData<&'d mut T>, |
| @@ -240,6 +245,87 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 240 | }) | 245 | }) |
| 241 | .await | 246 | .await |
| 242 | } | 247 | } |
| 248 | |||
| 249 | pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { | ||
| 250 | let bomb = DropBomb::new(); | ||
| 251 | |||
| 252 | assert_eq!(data.as_ptr() as u32 % 4, 0); | ||
| 253 | assert_eq!(data.len() as u32 % 4, 0); | ||
| 254 | assert_eq!(address as u32 % 4, 0); | ||
| 255 | |||
| 256 | let r = T::regs(); | ||
| 257 | |||
| 258 | r.read | ||
| 259 | .src | ||
| 260 | .write(|w| unsafe { w.src().bits(address as u32) }); | ||
| 261 | r.read | ||
| 262 | .dst | ||
| 263 | .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); | ||
| 264 | r.read | ||
| 265 | .cnt | ||
| 266 | .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); | ||
| 267 | |||
| 268 | r.events_ready.reset(); | ||
| 269 | r.intenset.write(|w| w.ready().set()); | ||
| 270 | r.tasks_readstart.write(|w| w.tasks_readstart().bit(true)); | ||
| 271 | |||
| 272 | self.wait_ready().await; | ||
| 273 | |||
| 274 | bomb.defuse(); | ||
| 275 | |||
| 276 | Ok(()) | ||
| 277 | } | ||
| 278 | |||
| 279 | pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { | ||
| 280 | let bomb = DropBomb::new(); | ||
| 281 | |||
| 282 | assert_eq!(data.as_ptr() as u32 % 4, 0); | ||
| 283 | assert_eq!(data.len() as u32 % 4, 0); | ||
| 284 | assert_eq!(address as u32 % 4, 0); | ||
| 285 | |||
| 286 | let r = T::regs(); | ||
| 287 | r.write | ||
| 288 | .src | ||
| 289 | .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); | ||
| 290 | r.write | ||
| 291 | .dst | ||
| 292 | .write(|w| unsafe { w.dst().bits(address as u32) }); | ||
| 293 | r.write | ||
| 294 | .cnt | ||
| 295 | .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); | ||
| 296 | |||
| 297 | r.events_ready.reset(); | ||
| 298 | r.intenset.write(|w| w.ready().set()); | ||
| 299 | r.tasks_writestart.write(|w| w.tasks_writestart().bit(true)); | ||
| 300 | |||
| 301 | self.wait_ready().await; | ||
| 302 | |||
| 303 | bomb.defuse(); | ||
| 304 | |||
| 305 | Ok(()) | ||
| 306 | } | ||
| 307 | |||
| 308 | pub async fn erase(&mut self, address: usize) -> Result<(), Error> { | ||
| 309 | let bomb = DropBomb::new(); | ||
| 310 | |||
| 311 | assert_eq!(address as u32 % 4096, 0); | ||
| 312 | |||
| 313 | let r = T::regs(); | ||
| 314 | r.erase | ||
| 315 | .ptr | ||
| 316 | .write(|w| unsafe { w.ptr().bits(address as u32) }); | ||
| 317 | r.erase.len.write(|w| w.len()._4kb()); | ||
| 318 | |||
| 319 | r.events_ready.reset(); | ||
| 320 | r.intenset.write(|w| w.ready().set()); | ||
| 321 | r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true)); | ||
| 322 | |||
| 323 | self.wait_ready().await; | ||
| 324 | |||
| 325 | bomb.defuse(); | ||
| 326 | |||
| 327 | Ok(()) | ||
| 328 | } | ||
| 243 | } | 329 | } |
| 244 | 330 | ||
| 245 | impl<'d, T: Instance> Drop for Qspi<'d, T> { | 331 | impl<'d, T: Instance> Drop for Qspi<'d, T> { |
| @@ -285,124 +371,6 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> { | |||
| 285 | } | 371 | } |
| 286 | } | 372 | } |
| 287 | 373 | ||
| 288 | impl<'d, T: Instance> Flash for Qspi<'d, T> { | ||
| 289 | type ReadFuture<'a> | ||
| 290 | where | ||
| 291 | Self: 'a, | ||
| 292 | = impl Future<Output = Result<(), Error>> + 'a; | ||
| 293 | type WriteFuture<'a> | ||
| 294 | where | ||
| 295 | Self: 'a, | ||
| 296 | = impl Future<Output = Result<(), Error>> + 'a; | ||
| 297 | type ErasePageFuture<'a> | ||
| 298 | where | ||
| 299 | Self: 'a, | ||
| 300 | = impl Future<Output = Result<(), Error>> + 'a; | ||
| 301 | |||
| 302 | fn read<'a>(&'a mut self, address: usize, data: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 303 | async move { | ||
| 304 | let bomb = DropBomb::new(); | ||
| 305 | |||
| 306 | assert_eq!(data.as_ptr() as u32 % 4, 0); | ||
| 307 | assert_eq!(data.len() as u32 % 4, 0); | ||
| 308 | assert_eq!(address as u32 % 4, 0); | ||
| 309 | |||
| 310 | let r = T::regs(); | ||
| 311 | |||
| 312 | r.read | ||
| 313 | .src | ||
| 314 | .write(|w| unsafe { w.src().bits(address as u32) }); | ||
| 315 | r.read | ||
| 316 | .dst | ||
| 317 | .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); | ||
| 318 | r.read | ||
| 319 | .cnt | ||
| 320 | .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); | ||
| 321 | |||
| 322 | r.events_ready.reset(); | ||
| 323 | r.intenset.write(|w| w.ready().set()); | ||
| 324 | r.tasks_readstart.write(|w| w.tasks_readstart().bit(true)); | ||
| 325 | |||
| 326 | self.wait_ready().await; | ||
| 327 | |||
| 328 | bomb.defuse(); | ||
| 329 | |||
| 330 | Ok(()) | ||
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | fn write<'a>(&'a mut self, address: usize, data: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 335 | async move { | ||
| 336 | let bomb = DropBomb::new(); | ||
| 337 | |||
| 338 | assert_eq!(data.as_ptr() as u32 % 4, 0); | ||
| 339 | assert_eq!(data.len() as u32 % 4, 0); | ||
| 340 | assert_eq!(address as u32 % 4, 0); | ||
| 341 | |||
| 342 | let r = T::regs(); | ||
| 343 | r.write | ||
| 344 | .src | ||
| 345 | .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); | ||
| 346 | r.write | ||
| 347 | .dst | ||
| 348 | .write(|w| unsafe { w.dst().bits(address as u32) }); | ||
| 349 | r.write | ||
| 350 | .cnt | ||
| 351 | .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); | ||
| 352 | |||
| 353 | r.events_ready.reset(); | ||
| 354 | r.intenset.write(|w| w.ready().set()); | ||
| 355 | r.tasks_writestart.write(|w| w.tasks_writestart().bit(true)); | ||
| 356 | |||
| 357 | self.wait_ready().await; | ||
| 358 | |||
| 359 | bomb.defuse(); | ||
| 360 | |||
| 361 | Ok(()) | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | fn erase<'a>(&'a mut self, address: usize) -> Self::ErasePageFuture<'a> { | ||
| 366 | async move { | ||
| 367 | let bomb = DropBomb::new(); | ||
| 368 | |||
| 369 | assert_eq!(address as u32 % 4096, 0); | ||
| 370 | |||
| 371 | let r = T::regs(); | ||
| 372 | r.erase | ||
| 373 | .ptr | ||
| 374 | .write(|w| unsafe { w.ptr().bits(address as u32) }); | ||
| 375 | r.erase.len.write(|w| w.len()._4kb()); | ||
| 376 | |||
| 377 | r.events_ready.reset(); | ||
| 378 | r.intenset.write(|w| w.ready().set()); | ||
| 379 | r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true)); | ||
| 380 | |||
| 381 | self.wait_ready().await; | ||
| 382 | |||
| 383 | bomb.defuse(); | ||
| 384 | |||
| 385 | Ok(()) | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | fn size(&self) -> usize { | ||
| 390 | 256 * 4096 // TODO | ||
| 391 | } | ||
| 392 | |||
| 393 | fn read_size(&self) -> usize { | ||
| 394 | 4 // TODO | ||
| 395 | } | ||
| 396 | |||
| 397 | fn write_size(&self) -> usize { | ||
| 398 | 4 // TODO | ||
| 399 | } | ||
| 400 | |||
| 401 | fn erase_size(&self) -> usize { | ||
| 402 | 4096 // TODO | ||
| 403 | } | ||
| 404 | } | ||
| 405 | |||
| 406 | pub(crate) mod sealed { | 374 | pub(crate) mod sealed { |
| 407 | use embassy::waitqueue::AtomicWaker; | 375 | use embassy::waitqueue::AtomicWaker; |
| 408 | 376 | ||
diff --git a/examples/nrf/src/bin/qspi.rs b/examples/nrf/src/bin/qspi.rs index c7f9503bb..b2e6bfc15 100644 --- a/examples/nrf/src/bin/qspi.rs +++ b/examples/nrf/src/bin/qspi.rs | |||
| @@ -7,7 +7,6 @@ mod example_common; | |||
| 7 | 7 | ||
| 8 | use defmt::assert_eq; | 8 | use defmt::assert_eq; |
| 9 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 10 | use embassy::traits::flash::Flash; | ||
| 11 | use embassy_nrf::Peripherals; | 10 | use embassy_nrf::Peripherals; |
| 12 | use embassy_nrf::{interrupt, qspi}; | 11 | use embassy_nrf::{interrupt, qspi}; |
| 13 | use example_common::*; | 12 | use example_common::*; |
diff --git a/examples/nrf/src/bin/qspi_lowpower.rs b/examples/nrf/src/bin/qspi_lowpower.rs index e9e1bac42..4e264ef2f 100644 --- a/examples/nrf/src/bin/qspi_lowpower.rs +++ b/examples/nrf/src/bin/qspi_lowpower.rs | |||
| @@ -8,7 +8,6 @@ mod example_common; | |||
| 8 | use core::mem; | 8 | use core::mem; |
| 9 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 10 | use embassy::time::{Duration, Timer}; | 10 | use embassy::time::{Duration, Timer}; |
| 11 | use embassy::traits::flash::Flash; | ||
| 12 | use embassy_nrf::Peripherals; | 11 | use embassy_nrf::Peripherals; |
| 13 | use embassy_nrf::{interrupt, qspi}; | 12 | use embassy_nrf::{interrupt, qspi}; |
| 14 | use example_common::*; | 13 | use example_common::*; |
