From f71cf6cf6f1d117f3440789ce2a14c6f01193274 Mon Sep 17 00:00:00 2001 From: ferris Date: Thu, 26 Oct 2023 12:23:33 +0200 Subject: [PATCH] Fix interrupts --- embassy-nrf/src/chips/nrf5340_app.rs | 3 + embassy-nrf/src/nfc.rs | 98 ++++++++++++++++++++++------ examples/nrf5340/src/bin/nfc.rs | 42 ++++++++++++ 3 files changed, 124 insertions(+), 19 deletions(-) create mode 100644 examples/nrf5340/src/bin/nfc.rs diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 5e9a8ed0..ff1fe1a0 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -246,6 +246,9 @@ embassy_hal_internal::peripherals! { // NVMC NVMC, + // NFC + NFCT, + // UARTE, TWI & SPI SERIAL0, SERIAL1, diff --git a/embassy-nrf/src/nfc.rs b/embassy-nrf/src/nfc.rs index 5a029285..ade0bc88 100644 --- a/embassy-nrf/src/nfc.rs +++ b/embassy-nrf/src/nfc.rs @@ -3,18 +3,18 @@ #![macro_use] use core::future::poll_fn; -use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -// use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; -use pac::{nfct, NFCT}; -use crate::util::slice_in_ram; -use crate::{interrupt, pac, peripherals, Peripheral}; +use crate::interrupt::InterruptExt; +// use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; +use crate::peripherals::NFCT; +use crate::util::slice_in_ram_or; +use crate::{interrupt, pac, Peripheral}; /// Interrupt handler. pub struct InterruptHandler { @@ -23,20 +23,41 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let r = unsafe { &*NFCT::ptr() }; + let r = unsafe { &*pac::NFCT::ptr() }; if r.events_rxframeend.read().bits() != 0 { - r.intenclr.write(|w| w.rxframeend().clear()); + r.intenclr.write(|w| w.rxframeend().set_bit()); WAKER.wake(); + info!("NFC Interrupt: rxframeend") } if r.events_rxerror.read().bits() != 0 { - r.intenclr.write(|w| w.rxerror().clear()); + r.intenclr.write(|w| w.rxerror().set_bit()); WAKER.wake(); + info!("NFC Interrupt: rxerror") } if r.events_endtx.read().bits() != 0 { - r.intenclr.write(|w| w.endtx().clear()); + r.intenclr.write(|w| w.endtx().set_bit()); WAKER.wake(); + info!("NFC Interrupt: endtx") + } + + if r.events_fielddetected.read().bits() != 0 { + r.intenclr.write(|w| w.fielddetected().set_bit()); + WAKER.wake(); + info!("NFC Interrupt: fielddetected") + } + + if r.events_fieldlost.read().bits() != 0 { + r.intenclr.write(|w| w.fieldlost().set_bit()); + WAKER.wake(); + info!("NFC Interrupt: fieldlost") + } + + if r.events_ready.read().bits() != 0 { + r.intenclr.write(|w| w.ready().set_bit()); + WAKER.wake(); + info!("NFC Interrupt: ready") } } } @@ -52,6 +73,8 @@ pub enum Error { RxError, /// Rx buffer was overrun, increase your buffer size to resolve this RxOverrun, + /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. + BufferNotInRAM, } /// Nfc Tag Read/Writer driver @@ -67,14 +90,19 @@ impl<'d> NfcT<'d> { ) -> Self { into_ref!(_p); - let r = unsafe { &*NFCT::ptr() }; - r.tasks_activate.write(|w| w.tasks_activate().set_bit()); + let r = unsafe { &*pac::NFCT::ptr() }; + // r.intenset.write(|w| unsafe { w.bits(u32::MAX) }); + r.intenset.write(|w| w.ready().set()); + interrupt::NFCT.unpend(); + unsafe { interrupt::NFCT.enable() }; + + // r.tasks_activate.write(|w| w.tasks_activate().set_bit()); Self { _p } } - fn regs() -> &'static nfct::RegisterBlock { - unsafe { &*NFCT::ptr() } + fn regs() -> &'static pac::nfct::RegisterBlock { + unsafe { &*pac::NFCT::ptr() } } fn stop_recv_frame() { @@ -102,10 +130,39 @@ impl<'d> NfcT<'d> { r.events_endtx.reset(); } + /// Checks if field is already present + pub fn is_field_present(&self) -> bool { + let r = Self::regs(); + return r.fieldpresent.read().fieldpresent().bit(); + } + + /// Blocks until field-detected event is triggered + pub async fn wait_for_field(&mut self) { + let r = Self::regs(); + + r.tasks_sense.write(|w| w.tasks_sense().set_bit()); + r.intenset.write(|w| w.fielddetected().set()); + r.intenset.write(|w| w.fieldlost().set()); + poll_fn(|cx| { + let r = Self::regs(); + + WAKER.register(cx.waker()); + + if r.events_fielddetected.read().bits() != 0 { + r.events_fielddetected.reset(); + return Poll::Ready(()); + } + + Poll::Pending + }) + .await; + } + /// Transmit an NFC frame /// `buf` is not pointing to the Data RAM region, an EasyDMA transfer may result in a hard fault or RAM corruption. - pub async fn tx_frame(&mut self, buf: &[u8]) { - // TODO: requires buf slice in ram validation + pub async fn tx_frame(&mut self, buf: &[u8]) -> Result<(), Error> { + slice_in_ram_or(buf, Error::BufferNotInRAM)?; + let r = Self::regs(); let on_drop = OnDrop::new(Self::stop_tx_frame); @@ -139,11 +196,13 @@ impl<'d> NfcT<'d> { .await; drop(on_drop); + Ok(()) } /// Waits for a single frame to be loaded into `buf` /// `buf` is not pointing to the Data RAM region, an EasyDMA transfer may result in a hard fault or RAM corruption. - pub async fn recv_frame(&mut self, buf: &mut [u8; N]) -> Result<(), Error> { + pub async fn recv_frame<'a, const N: usize>(&mut self, buf: &'a mut [u8; N]) -> Result<&'a [u8], Error> { + slice_in_ram_or(buf, Error::BufferNotInRAM)?; let r = Self::regs(); let on_drop = OnDrop::new(Self::stop_recv_frame); @@ -165,14 +224,15 @@ impl<'d> NfcT<'d> { r.tasks_enablerxdata.write(|w| w.tasks_enablerxdata().set_bit()); // Wait for 'rxframeend'/'rxerror' event. - poll_fn(|cx| { + let res = poll_fn(|cx| { let r = Self::regs(); WAKER.register(cx.waker()); if r.events_rxframeend.read().bits() != 0 { r.events_rxframeend.reset(); - return Poll::Ready(Ok(())); + let amount_read = r.rxd.amount.read().bits() as usize; + return Poll::Ready(Ok(&buf[..amount_read])); } if r.events_rxerror.read().bits() != 0 { @@ -189,6 +249,6 @@ impl<'d> NfcT<'d> { .await?; drop(on_drop); - Ok(()) + Ok(res) } } diff --git a/examples/nrf5340/src/bin/nfc.rs b/examples/nrf5340/src/bin/nfc.rs new file mode 100644 index 00000000..9222bfab --- /dev/null +++ b/examples/nrf5340/src/bin/nfc.rs @@ -0,0 +1,42 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::nfc::NfcT; +use embassy_nrf::peripherals::NFCT; +use embassy_nrf::{bind_interrupts, nfc}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + NFCT => nfc::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P0_28, Level::Low, OutputDrive::Standard); + let mut nfc = NfcT::new(p.NFCT, Irqs); + + // let mut buf: [u8; 1024] = [0; 1024]; + loop { + nfc.wait_for_field().await; + // let field = nfc.is_field_present(); + // info!("Field present: {=bool}", field); + + // dbg!("Starting recv_frame"); + // let frame = nfc.recv_frame(&mut buf).await; + // if let Ok(frame_data) = frame { + // dbg!("Got frame: {}", frame_data); + // } else if let Err(e) = frame { + // dbg!("Got frame err: {}", e); + // } + led.set_high(); + Timer::after_millis(300).await; + led.set_low(); + Timer::after_millis(300).await; + } +}