diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-09-27 21:18:29 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2025-09-28 21:05:37 +0200 |
| commit | 19fdd8d96c778697610386c829f6a0a655c39940 (patch) | |
| tree | a5e209048d1252def5f75e8051022da02e6dc338 /embassy-nrf | |
| parent | 6a262521811a435f2cfedd7e25fb70a1aab957ca (diff) | |
nrf/qspi: erase instance generics
Diffstat (limited to 'embassy-nrf')
| -rwxr-xr-x | embassy-nrf/src/qspi.rs | 109 |
1 files changed, 52 insertions, 57 deletions
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index e6e829f6e..94ad3f0d6 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs | |||
| @@ -138,16 +138,18 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | /// QSPI flash driver. | 140 | /// QSPI flash driver. |
| 141 | pub struct Qspi<'d, T: Instance> { | 141 | pub struct Qspi<'d> { |
| 142 | _peri: Peri<'d, T>, | 142 | r: pac::qspi::Qspi, |
| 143 | state: &'static State, | ||
| 143 | dpm_enabled: bool, | 144 | dpm_enabled: bool, |
| 144 | capacity: u32, | 145 | capacity: u32, |
| 146 | _phantom: PhantomData<&'d ()>, | ||
| 145 | } | 147 | } |
| 146 | 148 | ||
| 147 | impl<'d, T: Instance> Qspi<'d, T> { | 149 | impl<'d> Qspi<'d> { |
| 148 | /// Create a new QSPI driver. | 150 | /// Create a new QSPI driver. |
| 149 | pub fn new( | 151 | pub fn new<T: Instance>( |
| 150 | qspi: Peri<'d, T>, | 152 | _qspi: Peri<'d, T>, |
| 151 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 153 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 152 | sck: Peri<'d, impl GpioPin>, | 154 | sck: Peri<'d, impl GpioPin>, |
| 153 | csn: Peri<'d, impl GpioPin>, | 155 | csn: Peri<'d, impl GpioPin>, |
| @@ -214,9 +216,11 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 214 | r.enable().write(|w| w.set_enable(true)); | 216 | r.enable().write(|w| w.set_enable(true)); |
| 215 | 217 | ||
| 216 | let res = Self { | 218 | let res = Self { |
| 217 | _peri: qspi, | 219 | r: T::regs(), |
| 220 | state: T::state(), | ||
| 218 | dpm_enabled: config.deep_power_down.is_some(), | 221 | dpm_enabled: config.deep_power_down.is_some(), |
| 219 | capacity: config.capacity, | 222 | capacity: config.capacity, |
| 223 | _phantom: PhantomData, | ||
| 220 | }; | 224 | }; |
| 221 | 225 | ||
| 222 | r.events_ready().write_value(0); | 226 | r.events_ready().write_value(0); |
| @@ -274,14 +278,13 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 274 | } | 278 | } |
| 275 | } | 279 | } |
| 276 | 280 | ||
| 277 | let r = T::regs(); | 281 | self.r.cinstrdat0().write(|w| w.0 = dat0); |
| 278 | r.cinstrdat0().write(|w| w.0 = dat0); | 282 | self.r.cinstrdat1().write(|w| w.0 = dat1); |
| 279 | r.cinstrdat1().write(|w| w.0 = dat1); | ||
| 280 | 283 | ||
| 281 | r.events_ready().write_value(0); | 284 | self.r.events_ready().write_value(0); |
| 282 | r.intenset().write(|w| w.set_ready(true)); | 285 | self.r.intenset().write(|w| w.set_ready(true)); |
| 283 | 286 | ||
| 284 | r.cinstrconf().write(|w| { | 287 | self.r.cinstrconf().write(|w| { |
| 285 | w.set_opcode(opcode); | 288 | w.set_opcode(opcode); |
| 286 | w.set_length(vals::Length::from_bits(len + 1)); | 289 | w.set_length(vals::Length::from_bits(len + 1)); |
| 287 | w.set_lio2(true); | 290 | w.set_lio2(true); |
| @@ -295,10 +298,8 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 295 | } | 298 | } |
| 296 | 299 | ||
| 297 | fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> { | 300 | fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> { |
| 298 | let r = T::regs(); | 301 | let dat0 = self.r.cinstrdat0().read().0; |
| 299 | 302 | let dat1 = self.r.cinstrdat1().read().0; | |
| 300 | let dat0 = r.cinstrdat0().read().0; | ||
| 301 | let dat1 = r.cinstrdat1().read().0; | ||
| 302 | for i in 0..4 { | 303 | for i in 0..4 { |
| 303 | if i < resp.len() { | 304 | if i < resp.len() { |
| 304 | resp[i] = (dat0 >> (i * 8)) as u8; | 305 | resp[i] = (dat0 >> (i * 8)) as u8; |
| @@ -313,9 +314,9 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 313 | } | 314 | } |
| 314 | 315 | ||
| 315 | fn wait_ready(&mut self) -> impl Future<Output = ()> { | 316 | fn wait_ready(&mut self) -> impl Future<Output = ()> { |
| 317 | let r = self.r; | ||
| 318 | let s = self.state; | ||
| 316 | poll_fn(move |cx| { | 319 | poll_fn(move |cx| { |
| 317 | let r = T::regs(); | ||
| 318 | let s = T::state(); | ||
| 319 | s.waker.register(cx.waker()); | 320 | s.waker.register(cx.waker()); |
| 320 | if r.events_ready().read() != 0 { | 321 | if r.events_ready().read() != 0 { |
| 321 | return Poll::Ready(()); | 322 | return Poll::Ready(()); |
| @@ -326,7 +327,7 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 326 | 327 | ||
| 327 | fn blocking_wait_ready() { | 328 | fn blocking_wait_ready() { |
| 328 | loop { | 329 | loop { |
| 329 | let r = T::regs(); | 330 | let r = pac::QSPI; |
| 330 | if r.events_ready().read() != 0 { | 331 | if r.events_ready().read() != 0 { |
| 331 | break; | 332 | break; |
| 332 | } | 333 | } |
| @@ -339,15 +340,13 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 339 | assert_eq!(data.len() as u32 % 4, 0); | 340 | assert_eq!(data.len() as u32 % 4, 0); |
| 340 | assert_eq!(address % 4, 0); | 341 | assert_eq!(address % 4, 0); |
| 341 | 342 | ||
| 342 | let r = T::regs(); | 343 | self.r.read().src().write_value(address); |
| 343 | 344 | self.r.read().dst().write_value(data.as_ptr() as u32); | |
| 344 | r.read().src().write_value(address); | 345 | self.r.read().cnt().write(|w| w.set_cnt(data.len() as u32)); |
| 345 | r.read().dst().write_value(data.as_ptr() as u32); | ||
| 346 | r.read().cnt().write(|w| w.set_cnt(data.len() as u32)); | ||
| 347 | 346 | ||
| 348 | r.events_ready().write_value(0); | 347 | self.r.events_ready().write_value(0); |
| 349 | r.intenset().write(|w| w.set_ready(true)); | 348 | self.r.intenset().write(|w| w.set_ready(true)); |
| 350 | r.tasks_readstart().write_value(1); | 349 | self.r.tasks_readstart().write_value(1); |
| 351 | 350 | ||
| 352 | Ok(()) | 351 | Ok(()) |
| 353 | } | 352 | } |
| @@ -358,14 +357,13 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 358 | assert_eq!(data.len() as u32 % 4, 0); | 357 | assert_eq!(data.len() as u32 % 4, 0); |
| 359 | assert_eq!(address % 4, 0); | 358 | assert_eq!(address % 4, 0); |
| 360 | 359 | ||
| 361 | let r = T::regs(); | 360 | self.r.write().src().write_value(data.as_ptr() as u32); |
| 362 | r.write().src().write_value(data.as_ptr() as u32); | 361 | self.r.write().dst().write_value(address); |
| 363 | r.write().dst().write_value(address); | 362 | self.r.write().cnt().write(|w| w.set_cnt(data.len() as u32)); |
| 364 | r.write().cnt().write(|w| w.set_cnt(data.len() as u32)); | ||
| 365 | 363 | ||
| 366 | r.events_ready().write_value(0); | 364 | self.r.events_ready().write_value(0); |
| 367 | r.intenset().write(|w| w.set_ready(true)); | 365 | self.r.intenset().write(|w| w.set_ready(true)); |
| 368 | r.tasks_writestart().write_value(1); | 366 | self.r.tasks_writestart().write_value(1); |
| 369 | 367 | ||
| 370 | Ok(()) | 368 | Ok(()) |
| 371 | } | 369 | } |
| @@ -374,13 +372,12 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 374 | // TODO: Return these as errors instead. | 372 | // TODO: Return these as errors instead. |
| 375 | assert_eq!(address % 4096, 0); | 373 | assert_eq!(address % 4096, 0); |
| 376 | 374 | ||
| 377 | let r = T::regs(); | 375 | self.r.erase().ptr().write_value(address); |
| 378 | r.erase().ptr().write_value(address); | 376 | self.r.erase().len().write(|w| w.set_len(vals::Len::_4KB)); |
| 379 | r.erase().len().write(|w| w.set_len(vals::Len::_4KB)); | ||
| 380 | 377 | ||
| 381 | r.events_ready().write_value(0); | 378 | self.r.events_ready().write_value(0); |
| 382 | r.intenset().write(|w| w.set_ready(true)); | 379 | self.r.intenset().write(|w| w.set_ready(true)); |
| 383 | r.tasks_erasestart().write_value(1); | 380 | self.r.tasks_erasestart().write_value(1); |
| 384 | 381 | ||
| 385 | Ok(()) | 382 | Ok(()) |
| 386 | } | 383 | } |
| @@ -520,19 +517,17 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 520 | } | 517 | } |
| 521 | } | 518 | } |
| 522 | 519 | ||
| 523 | impl<'d, T: Instance> Drop for Qspi<'d, T> { | 520 | impl<'d> Drop for Qspi<'d> { |
| 524 | fn drop(&mut self) { | 521 | fn drop(&mut self) { |
| 525 | let r = T::regs(); | ||
| 526 | |||
| 527 | if self.dpm_enabled { | 522 | if self.dpm_enabled { |
| 528 | trace!("qspi: doing deep powerdown..."); | 523 | trace!("qspi: doing deep powerdown..."); |
| 529 | 524 | ||
| 530 | r.ifconfig1().modify(|w| w.set_dpmen(true)); | 525 | self.r.ifconfig1().modify(|w| w.set_dpmen(true)); |
| 531 | 526 | ||
| 532 | // Wait for DPM enter. | 527 | // Wait for DPM enter. |
| 533 | // Unfortunately we must spin. There's no way to do this interrupt-driven. | 528 | // Unfortunately we must spin. There's no way to do this interrupt-driven. |
| 534 | // The READY event does NOT fire on DPM enter (but it does fire on DPM exit :shrug:) | 529 | // The READY event does NOT fire on DPM enter (but it does fire on DPM exit :shrug:) |
| 535 | while !r.status().read().dpm() {} | 530 | while !self.r.status().read().dpm() {} |
| 536 | 531 | ||
| 537 | // Wait MORE for DPM enter. | 532 | // Wait MORE for DPM enter. |
| 538 | // I have absolutely no idea why, but the wait above is not enough :'( | 533 | // I have absolutely no idea why, but the wait above is not enough :'( |
| @@ -541,29 +536,29 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> { | |||
| 541 | } | 536 | } |
| 542 | 537 | ||
| 543 | // it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it. | 538 | // it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it. |
| 544 | r.tasks_deactivate().write_value(1); | 539 | self.r.tasks_deactivate().write_value(1); |
| 545 | 540 | ||
| 546 | // Workaround https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_122.html | 541 | // Workaround https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_122.html |
| 547 | // Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate, | 542 | // Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate, |
| 548 | // so we only do the second one here. | 543 | // so we only do the second one here. |
| 549 | unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) } | 544 | unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) } |
| 550 | 545 | ||
| 551 | r.enable().write(|w| w.set_enable(false)); | 546 | self.r.enable().write(|w| w.set_enable(false)); |
| 552 | 547 | ||
| 553 | // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, | 548 | // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, |
| 554 | // leaving it floating, the flash chip might read it as zero which would cause it to | 549 | // leaving it floating, the flash chip might read it as zero which would cause it to |
| 555 | // spuriously exit DPM. | 550 | // spuriously exit DPM. |
| 556 | gpio::deconfigure_pin(r.psel().sck().read()); | 551 | gpio::deconfigure_pin(self.r.psel().sck().read()); |
| 557 | gpio::deconfigure_pin(r.psel().io0().read()); | 552 | gpio::deconfigure_pin(self.r.psel().io0().read()); |
| 558 | gpio::deconfigure_pin(r.psel().io1().read()); | 553 | gpio::deconfigure_pin(self.r.psel().io1().read()); |
| 559 | gpio::deconfigure_pin(r.psel().io2().read()); | 554 | gpio::deconfigure_pin(self.r.psel().io2().read()); |
| 560 | gpio::deconfigure_pin(r.psel().io3().read()); | 555 | gpio::deconfigure_pin(self.r.psel().io3().read()); |
| 561 | 556 | ||
| 562 | trace!("qspi: dropped"); | 557 | trace!("qspi: dropped"); |
| 563 | } | 558 | } |
| 564 | } | 559 | } |
| 565 | 560 | ||
| 566 | impl<'d, T: Instance> ErrorType for Qspi<'d, T> { | 561 | impl<'d> ErrorType for Qspi<'d> { |
| 567 | type Error = Error; | 562 | type Error = Error; |
| 568 | } | 563 | } |
| 569 | 564 | ||
| @@ -573,7 +568,7 @@ impl NorFlashError for Error { | |||
| 573 | } | 568 | } |
| 574 | } | 569 | } |
| 575 | 570 | ||
| 576 | impl<'d, T: Instance> ReadNorFlash for Qspi<'d, T> { | 571 | impl<'d> ReadNorFlash for Qspi<'d> { |
| 577 | const READ_SIZE: usize = 4; | 572 | const READ_SIZE: usize = 4; |
| 578 | 573 | ||
| 579 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | 574 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| @@ -586,7 +581,7 @@ impl<'d, T: Instance> ReadNorFlash for Qspi<'d, T> { | |||
| 586 | } | 581 | } |
| 587 | } | 582 | } |
| 588 | 583 | ||
| 589 | impl<'d, T: Instance> NorFlash for Qspi<'d, T> { | 584 | impl<'d> NorFlash for Qspi<'d> { |
| 590 | const WRITE_SIZE: usize = 4; | 585 | const WRITE_SIZE: usize = 4; |
| 591 | const ERASE_SIZE: usize = 4096; | 586 | const ERASE_SIZE: usize = 4096; |
| 592 | 587 | ||
| @@ -611,7 +606,7 @@ mod _eh1 { | |||
| 611 | 606 | ||
| 612 | use super::*; | 607 | use super::*; |
| 613 | 608 | ||
| 614 | impl<'d, T: Instance> AsyncNorFlash for Qspi<'d, T> { | 609 | impl<'d> AsyncNorFlash for Qspi<'d> { |
| 615 | const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE; | 610 | const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE; |
| 616 | const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE; | 611 | const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE; |
| 617 | 612 | ||
| @@ -627,7 +622,7 @@ mod _eh1 { | |||
| 627 | } | 622 | } |
| 628 | } | 623 | } |
| 629 | 624 | ||
| 630 | impl<'d, T: Instance> AsyncReadNorFlash for Qspi<'d, T> { | 625 | impl<'d> AsyncReadNorFlash for Qspi<'d> { |
| 631 | const READ_SIZE: usize = 4; | 626 | const READ_SIZE: usize = 4; |
| 632 | async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> { | 627 | async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> { |
| 633 | self.read(address, data).await | 628 | self.read(address, data).await |
