diff options
author | Henrik Alsér <henrik@mindbite.se> | 2022-05-07 00:46:36 +0200 |
---|---|---|
committer | Henrik Alsér <henrik@mindbite.se> | 2022-05-07 00:46:36 +0200 |
commit | 840bb2952e68465ff5e58846db5a4f1ced76834b (patch) | |
tree | 296f49f2ee68a0d5ba558fcad8bacc86315457fc /embassy-nrf | |
parent | f7af9a549f165419f4fa85c82b42a3e5b54d417e (diff) | |
download | embassy-840bb2952e68465ff5e58846db5a4f1ced76834b.zip |
Add qdec module
Diffstat (limited to 'embassy-nrf')
-rw-r--r-- | embassy-nrf/src/chips/nrf52805.rs | 3 | ||||
-rw-r--r-- | embassy-nrf/src/chips/nrf52810.rs | 3 | ||||
-rw-r--r-- | embassy-nrf/src/chips/nrf52811.rs | 3 | ||||
-rw-r--r-- | embassy-nrf/src/chips/nrf52820.rs | 3 | ||||
-rw-r--r-- | embassy-nrf/src/chips/nrf52832.rs | 3 | ||||
-rw-r--r-- | embassy-nrf/src/chips/nrf52833.rs | 3 | ||||
-rw-r--r-- | embassy-nrf/src/chips/nrf52840.rs | 3 | ||||
-rw-r--r-- | embassy-nrf/src/lib.rs | 2 | ||||
-rw-r--r-- | embassy-nrf/src/qdec.rs | 222 |
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, +} |