summaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
authorHenrik Alsér <henrik@mindbite.se>2022-05-07 00:46:36 +0200
committerHenrik Alsér <henrik@mindbite.se>2022-05-07 00:46:36 +0200
commit840bb2952e68465ff5e58846db5a4f1ced76834b (patch)
tree296f49f2ee68a0d5ba558fcad8bacc86315457fc /embassy-nrf
parentf7af9a549f165419f4fa85c82b42a3e5b54d417e (diff)
downloadembassy-840bb2952e68465ff5e58846db5a4f1ced76834b.zip
Add qdec module
Diffstat (limited to 'embassy-nrf')
-rw-r--r--embassy-nrf/src/chips/nrf52805.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52810.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52811.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52820.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs3
-rw-r--r--embassy-nrf/src/lib.rs2
-rw-r--r--embassy-nrf/src/qdec.rs222
9 files changed, 245 insertions, 0 deletions
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs
index 68989648..c917dcdd 100644
--- a/embassy-nrf/src/chips/nrf52805.rs
+++ b/embassy-nrf/src/chips/nrf52805.rs
@@ -122,6 +122,9 @@ embassy_hal_common::peripherals! {
// TEMP
TEMP,
+
+ // QDEC
+ QDEC,
}
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs
index b3b3593b..922b683f 100644
--- a/embassy-nrf/src/chips/nrf52810.rs
+++ b/embassy-nrf/src/chips/nrf52810.rs
@@ -125,6 +125,9 @@ embassy_hal_common::peripherals! {
// TEMP
TEMP,
+
+ // QDEC
+ QDEC,
}
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs
index 7551492c..d23ab5b3 100644
--- a/embassy-nrf/src/chips/nrf52811.rs
+++ b/embassy-nrf/src/chips/nrf52811.rs
@@ -125,6 +125,9 @@ embassy_hal_common::peripherals! {
// TEMP
TEMP,
+
+ // QDEC
+ QDEC,
}
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs
index 136ef4ec..e94ddbb1 100644
--- a/embassy-nrf/src/chips/nrf52820.rs
+++ b/embassy-nrf/src/chips/nrf52820.rs
@@ -123,6 +123,9 @@ embassy_hal_common::peripherals! {
// TEMP
TEMP,
+
+ // QDEC
+ QDEC,
}
#[cfg(feature = "nightly")]
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index f1216cf2..fec7e10d 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -135,6 +135,9 @@ embassy_hal_common::peripherals! {
// TEMP
TEMP,
+
+ // QDEC
+ QDEC,
}
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index 35cf4224..e09c7718 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -155,6 +155,9 @@ embassy_hal_common::peripherals! {
// TEMP
TEMP,
+
+ // QDEC
+ QDEC,
}
#[cfg(feature = "nightly")]
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index d20abbfb..2e71e04b 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -27,6 +27,9 @@ embassy_hal_common::peripherals! {
// QSPI
QSPI,
+ // QDEC
+ QDEC,
+
// UARTE
UARTE0,
UARTE1,
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 3b180902..46234b4b 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -73,6 +73,8 @@ pub mod nvmc;
pub mod ppi;
#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))]
pub mod pwm;
+#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340")))]
+pub mod qdec;
#[cfg(feature = "nrf52840")]
pub mod qspi;
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
new file mode 100644
index 00000000..c124ba35
--- /dev/null
+++ b/embassy-nrf/src/qdec.rs
@@ -0,0 +1,222 @@
+//! Quadrature decoder interface
+
+use crate::gpio::sealed::Pin as _;
+use crate::gpio::{AnyPin, Pin as GpioPin};
+use crate::interrupt;
+use crate::pac;
+use crate::peripherals::QDEC;
+
+use core::marker::PhantomData;
+use core::task::Poll;
+use embassy::interrupt::InterruptExt;
+use embassy::util::Unborrow;
+use embassy::waitqueue::AtomicWaker;
+use embassy_hal_common::{drop::OnDrop, unborrow};
+use futures::future::poll_fn;
+
+/// Quadrature decoder
+pub struct Qdec<'d> {
+ phantom: PhantomData<&'d QDEC>,
+}
+
+#[non_exhaustive]
+pub struct Config {
+ pub num_samples: NumSamples,
+ pub period: SamplePeriod,
+ pub led_polarity: LedPolarity,
+ pub debounce: bool,
+ pub led_pre_usecs: u16,
+}
+
+impl Default for Config {
+ fn default() -> Self {
+ Self {
+ num_samples: NumSamples::_1smpl,
+ period: SamplePeriod::_256us,
+ led_polarity: LedPolarity::ActiveHigh,
+ debounce: true,
+ led_pre_usecs: 0,
+ }
+ }
+}
+
+static WAKER: AtomicWaker = AtomicWaker::new();
+
+impl<'d> Qdec<'d> {
+ pub fn new(
+ qdec: impl Unborrow<Target = QDEC> + 'd,
+ irq: impl Unborrow<Target = interrupt::QDEC> + 'd,
+ a: impl Unborrow<Target = impl GpioPin> + 'd,
+ b: impl Unborrow<Target = impl GpioPin> + 'd,
+ config: Config,
+ ) -> Self {
+ unborrow!(a, b);
+ Self::new_inner(qdec, irq, a.degrade(), b.degrade(), None, config)
+ }
+
+ pub fn new_with_led(
+ qdec: impl Unborrow<Target = QDEC> + 'd,
+ irq: impl Unborrow<Target = interrupt::QDEC> + 'd,
+ a: impl Unborrow<Target = impl GpioPin> + 'd,
+ b: impl Unborrow<Target = impl GpioPin> + 'd,
+ led: impl Unborrow<Target = impl GpioPin> + 'd,
+ config: Config,
+ ) -> Self {
+ unborrow!(a, b, led);
+ Self::new_inner(
+ qdec,
+ irq,
+ a.degrade(),
+ b.degrade(),
+ Some(led.degrade()),
+ config,
+ )
+ }
+
+ fn new_inner(
+ _t: impl Unborrow<Target = QDEC> + 'd,
+ irq: impl Unborrow<Target = interrupt::QDEC> + 'd,
+ a: AnyPin,
+ b: AnyPin,
+ led: Option<AnyPin>,
+ config: Config,
+ ) -> Self {
+ unborrow!(irq);
+ let r = Self::regs();
+
+ // Select pins.
+ a.conf().write(|w| w.input().connect().pull().pullup());
+ b.conf().write(|w| w.input().connect().pull().pullup());
+ r.psel.a.write(|w| unsafe { w.bits(a.psel_bits()) });
+ r.psel.b.write(|w| unsafe { w.bits(b.psel_bits()) });
+ if let Some(led_pin) = &led {
+ led_pin.conf().write(|w| w.dir().output());
+ r.psel.led.write(|w| unsafe { w.bits(led_pin.psel_bits()) });
+ }
+
+ // Enables/disable input debounce filters
+ r.dbfen.write(|w| match config.debounce {
+ true => w.dbfen().enabled(),
+ false => w.dbfen().disabled(),
+ });
+
+ // Set LED output pin polarity
+ r.ledpol.write(|w| match config.led_polarity {
+ LedPolarity::ActiveHigh => w.ledpol().active_high(),
+ LedPolarity::ActiveLow => w.ledpol().active_low(),
+ });
+
+ // Set time period the LED is switched ON prior to sampling (0..511 us).
+ r.ledpre
+ .write(|w| unsafe { w.ledpre().bits(config.led_pre_usecs.min(511)) });
+
+ // Set sample period
+ r.sampleper.write(|w| match config.period {
+ SamplePeriod::_128us => w.sampleper()._128us(),
+ SamplePeriod::_256us => w.sampleper()._256us(),
+ SamplePeriod::_512us => w.sampleper()._512us(),
+ SamplePeriod::_1024us => w.sampleper()._1024us(),
+ SamplePeriod::_2048us => w.sampleper()._2048us(),
+ SamplePeriod::_4096us => w.sampleper()._4096us(),
+ SamplePeriod::_8192us => w.sampleper()._8192us(),
+ SamplePeriod::_16384us => w.sampleper()._16384us(),
+ SamplePeriod::_32ms => w.sampleper()._32ms(),
+ SamplePeriod::_65ms => w.sampleper()._65ms(),
+ SamplePeriod::_131ms => w.sampleper()._131ms(),
+ });
+
+ // Enable peripheral
+ r.enable.write(|w| w.enable().set_bit());
+
+ irq.disable();
+ irq.set_handler(|_| {
+ let r = Self::regs();
+ r.intenclr.write(|w| w.reportrdy().clear());
+ WAKER.wake();
+ });
+ irq.enable();
+
+ Self {
+ phantom: PhantomData,
+ }
+ }
+
+ /// Perform an asynchronous read of the decoder.
+ /// The returned future can be awaited to obtain the number of steps.
+ ///
+ /// If the future is dropped, the read is cancelled.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// let irq = interrupt::take!(QDEC);
+ /// let config = qdec::Config::default();
+ /// let mut q = Qdec::new(p.QDEC, p.P0_31, p.P0_30, config);
+ /// let delta = q.read().await;
+ /// ```
+ pub async fn read(&mut self) -> i16 {
+ // In case the future is dropped, stop the task and reset events.
+ let on_drop = OnDrop::new(|| {
+ let t = Self::regs();
+ t.tasks_stop.write(|w| unsafe { w.bits(1) });
+ t.events_reportrdy.reset();
+ });
+
+ let t = Self::regs();
+ t.intenset.write(|w| w.reportrdy().set());
+ unsafe { t.tasks_start.write(|w| w.bits(1)) };
+ unsafe { t.tasks_readclracc.write(|w| w.bits(1)) };
+
+ let value = poll_fn(|cx| {
+ WAKER.register(cx.waker());
+ if t.events_reportrdy.read().bits() == 0 {
+ return Poll::Pending;
+ } else {
+ t.events_reportrdy.reset();
+ let acc = t.accread.read().bits();
+ Poll::Ready(acc as i16)
+ }
+ })
+ .await;
+ on_drop.defuse();
+ value
+ }
+
+ fn regs() -> &'static pac::qdec::RegisterBlock {
+ unsafe { &*pac::QDEC::ptr() }
+ }
+}
+
+#[derive(Debug, Eq, PartialEq, Clone, Copy)]
+pub enum SamplePeriod {
+ _128us,
+ _256us,
+ _512us,
+ _1024us,
+ _2048us,
+ _4096us,
+ _8192us,
+ _16384us,
+ _32ms,
+ _65ms,
+ _131ms,
+}
+
+#[derive(Debug, Eq, PartialEq, Clone, Copy)]
+pub enum NumSamples {
+ _10smpl,
+ _40smpl,
+ _80smpl,
+ _120smpl,
+ _160smpl,
+ _200smpl,
+ _240smpl,
+ _280smpl,
+ _1smpl,
+}
+
+#[derive(Debug, Eq, PartialEq, Clone, Copy)]
+pub enum LedPolarity {
+ ActiveHigh,
+ ActiveLow,
+}