diff options
| -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 | ||||
| -rw-r--r-- | examples/nrf/src/bin/qdec.rs | 29 |
10 files changed, 274 insertions, 0 deletions
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index 689896485..c917dcdd0 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs | |||
| @@ -122,6 +122,9 @@ embassy_hal_common::peripherals! { | |||
| 122 | 122 | ||
| 123 | // TEMP | 123 | // TEMP |
| 124 | TEMP, | 124 | TEMP, |
| 125 | |||
| 126 | // QDEC | ||
| 127 | QDEC, | ||
| 125 | } | 128 | } |
| 126 | 129 | ||
| 127 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | 130 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); |
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index b3b3593bb..922b683f9 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs | |||
| @@ -125,6 +125,9 @@ embassy_hal_common::peripherals! { | |||
| 125 | 125 | ||
| 126 | // TEMP | 126 | // TEMP |
| 127 | TEMP, | 127 | TEMP, |
| 128 | |||
| 129 | // QDEC | ||
| 130 | QDEC, | ||
| 128 | } | 131 | } |
| 129 | 132 | ||
| 130 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | 133 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); |
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 7551492c3..d23ab5b39 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs | |||
| @@ -125,6 +125,9 @@ embassy_hal_common::peripherals! { | |||
| 125 | 125 | ||
| 126 | // TEMP | 126 | // TEMP |
| 127 | TEMP, | 127 | TEMP, |
| 128 | |||
| 129 | // QDEC | ||
| 130 | QDEC, | ||
| 128 | } | 131 | } |
| 129 | 132 | ||
| 130 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | 133 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); |
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 136ef4ec9..e94ddbb14 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs | |||
| @@ -123,6 +123,9 @@ embassy_hal_common::peripherals! { | |||
| 123 | 123 | ||
| 124 | // TEMP | 124 | // TEMP |
| 125 | TEMP, | 125 | TEMP, |
| 126 | |||
| 127 | // QDEC | ||
| 128 | QDEC, | ||
| 126 | } | 129 | } |
| 127 | 130 | ||
| 128 | #[cfg(feature = "nightly")] | 131 | #[cfg(feature = "nightly")] |
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index f1216cf21..fec7e10de 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs | |||
| @@ -135,6 +135,9 @@ embassy_hal_common::peripherals! { | |||
| 135 | 135 | ||
| 136 | // TEMP | 136 | // TEMP |
| 137 | TEMP, | 137 | TEMP, |
| 138 | |||
| 139 | // QDEC | ||
| 140 | QDEC, | ||
| 138 | } | 141 | } |
| 139 | 142 | ||
| 140 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | 143 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); |
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 35cf4224d..e09c77187 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs | |||
| @@ -155,6 +155,9 @@ embassy_hal_common::peripherals! { | |||
| 155 | 155 | ||
| 156 | // TEMP | 156 | // TEMP |
| 157 | TEMP, | 157 | TEMP, |
| 158 | |||
| 159 | // QDEC | ||
| 160 | QDEC, | ||
| 158 | } | 161 | } |
| 159 | 162 | ||
| 160 | #[cfg(feature = "nightly")] | 163 | #[cfg(feature = "nightly")] |
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index d20abbfbd..2e71e04b0 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs | |||
| @@ -27,6 +27,9 @@ embassy_hal_common::peripherals! { | |||
| 27 | // QSPI | 27 | // QSPI |
| 28 | QSPI, | 28 | QSPI, |
| 29 | 29 | ||
| 30 | // QDEC | ||
| 31 | QDEC, | ||
| 32 | |||
| 30 | // UARTE | 33 | // UARTE |
| 31 | UARTE0, | 34 | UARTE0, |
| 32 | UARTE1, | 35 | UARTE1, |
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 3b1809023..46234b4b5 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -73,6 +73,8 @@ pub mod nvmc; | |||
| 73 | pub mod ppi; | 73 | pub mod ppi; |
| 74 | #[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] | 74 | #[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] |
| 75 | pub mod pwm; | 75 | pub mod pwm; |
| 76 | #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340")))] | ||
| 77 | pub mod qdec; | ||
| 76 | #[cfg(feature = "nrf52840")] | 78 | #[cfg(feature = "nrf52840")] |
| 77 | pub mod qspi; | 79 | pub mod qspi; |
| 78 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] | 80 | #[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 000000000..c124ba35e --- /dev/null +++ b/embassy-nrf/src/qdec.rs | |||
| @@ -0,0 +1,222 @@ | |||
| 1 | //! Quadrature decoder interface | ||
| 2 | |||
| 3 | use crate::gpio::sealed::Pin as _; | ||
| 4 | use crate::gpio::{AnyPin, Pin as GpioPin}; | ||
| 5 | use crate::interrupt; | ||
| 6 | use crate::pac; | ||
| 7 | use crate::peripherals::QDEC; | ||
| 8 | |||
| 9 | use core::marker::PhantomData; | ||
| 10 | use core::task::Poll; | ||
| 11 | use embassy::interrupt::InterruptExt; | ||
| 12 | use embassy::util::Unborrow; | ||
| 13 | use embassy::waitqueue::AtomicWaker; | ||
| 14 | use embassy_hal_common::{drop::OnDrop, unborrow}; | ||
| 15 | use futures::future::poll_fn; | ||
| 16 | |||
| 17 | /// Quadrature decoder | ||
| 18 | pub struct Qdec<'d> { | ||
| 19 | phantom: PhantomData<&'d QDEC>, | ||
| 20 | } | ||
| 21 | |||
| 22 | #[non_exhaustive] | ||
| 23 | pub struct Config { | ||
| 24 | pub num_samples: NumSamples, | ||
| 25 | pub period: SamplePeriod, | ||
| 26 | pub led_polarity: LedPolarity, | ||
| 27 | pub debounce: bool, | ||
| 28 | pub led_pre_usecs: u16, | ||
| 29 | } | ||
| 30 | |||
| 31 | impl Default for Config { | ||
| 32 | fn default() -> Self { | ||
| 33 | Self { | ||
| 34 | num_samples: NumSamples::_1smpl, | ||
| 35 | period: SamplePeriod::_256us, | ||
| 36 | led_polarity: LedPolarity::ActiveHigh, | ||
| 37 | debounce: true, | ||
| 38 | led_pre_usecs: 0, | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | static WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 44 | |||
| 45 | impl<'d> Qdec<'d> { | ||
| 46 | pub fn new( | ||
| 47 | qdec: impl Unborrow<Target = QDEC> + 'd, | ||
| 48 | irq: impl Unborrow<Target = interrupt::QDEC> + 'd, | ||
| 49 | a: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 50 | b: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 51 | config: Config, | ||
| 52 | ) -> Self { | ||
| 53 | unborrow!(a, b); | ||
| 54 | Self::new_inner(qdec, irq, a.degrade(), b.degrade(), None, config) | ||
| 55 | } | ||
| 56 | |||
| 57 | pub fn new_with_led( | ||
| 58 | qdec: impl Unborrow<Target = QDEC> + 'd, | ||
| 59 | irq: impl Unborrow<Target = interrupt::QDEC> + 'd, | ||
| 60 | a: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 61 | b: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 62 | led: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 63 | config: Config, | ||
| 64 | ) -> Self { | ||
| 65 | unborrow!(a, b, led); | ||
| 66 | Self::new_inner( | ||
| 67 | qdec, | ||
| 68 | irq, | ||
| 69 | a.degrade(), | ||
| 70 | b.degrade(), | ||
| 71 | Some(led.degrade()), | ||
| 72 | config, | ||
| 73 | ) | ||
| 74 | } | ||
| 75 | |||
| 76 | fn new_inner( | ||
| 77 | _t: impl Unborrow<Target = QDEC> + 'd, | ||
| 78 | irq: impl Unborrow<Target = interrupt::QDEC> + 'd, | ||
| 79 | a: AnyPin, | ||
| 80 | b: AnyPin, | ||
| 81 | led: Option<AnyPin>, | ||
| 82 | config: Config, | ||
| 83 | ) -> Self { | ||
| 84 | unborrow!(irq); | ||
| 85 | let r = Self::regs(); | ||
| 86 | |||
| 87 | // Select pins. | ||
| 88 | a.conf().write(|w| w.input().connect().pull().pullup()); | ||
| 89 | b.conf().write(|w| w.input().connect().pull().pullup()); | ||
| 90 | r.psel.a.write(|w| unsafe { w.bits(a.psel_bits()) }); | ||
| 91 | r.psel.b.write(|w| unsafe { w.bits(b.psel_bits()) }); | ||
| 92 | if let Some(led_pin) = &led { | ||
| 93 | led_pin.conf().write(|w| w.dir().output()); | ||
| 94 | r.psel.led.write(|w| unsafe { w.bits(led_pin.psel_bits()) }); | ||
| 95 | } | ||
| 96 | |||
| 97 | // Enables/disable input debounce filters | ||
| 98 | r.dbfen.write(|w| match config.debounce { | ||
| 99 | true => w.dbfen().enabled(), | ||
| 100 | false => w.dbfen().disabled(), | ||
| 101 | }); | ||
| 102 | |||
| 103 | // Set LED output pin polarity | ||
| 104 | r.ledpol.write(|w| match config.led_polarity { | ||
| 105 | LedPolarity::ActiveHigh => w.ledpol().active_high(), | ||
| 106 | LedPolarity::ActiveLow => w.ledpol().active_low(), | ||
| 107 | }); | ||
| 108 | |||
| 109 | // Set time period the LED is switched ON prior to sampling (0..511 us). | ||
| 110 | r.ledpre | ||
| 111 | .write(|w| unsafe { w.ledpre().bits(config.led_pre_usecs.min(511)) }); | ||
| 112 | |||
| 113 | // Set sample period | ||
| 114 | r.sampleper.write(|w| match config.period { | ||
| 115 | SamplePeriod::_128us => w.sampleper()._128us(), | ||
| 116 | SamplePeriod::_256us => w.sampleper()._256us(), | ||
| 117 | SamplePeriod::_512us => w.sampleper()._512us(), | ||
| 118 | SamplePeriod::_1024us => w.sampleper()._1024us(), | ||
| 119 | SamplePeriod::_2048us => w.sampleper()._2048us(), | ||
| 120 | SamplePeriod::_4096us => w.sampleper()._4096us(), | ||
| 121 | SamplePeriod::_8192us => w.sampleper()._8192us(), | ||
| 122 | SamplePeriod::_16384us => w.sampleper()._16384us(), | ||
| 123 | SamplePeriod::_32ms => w.sampleper()._32ms(), | ||
| 124 | SamplePeriod::_65ms => w.sampleper()._65ms(), | ||
| 125 | SamplePeriod::_131ms => w.sampleper()._131ms(), | ||
| 126 | }); | ||
| 127 | |||
| 128 | // Enable peripheral | ||
| 129 | r.enable.write(|w| w.enable().set_bit()); | ||
| 130 | |||
| 131 | irq.disable(); | ||
| 132 | irq.set_handler(|_| { | ||
| 133 | let r = Self::regs(); | ||
| 134 | r.intenclr.write(|w| w.reportrdy().clear()); | ||
| 135 | WAKER.wake(); | ||
| 136 | }); | ||
| 137 | irq.enable(); | ||
| 138 | |||
| 139 | Self { | ||
| 140 | phantom: PhantomData, | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | /// Perform an asynchronous read of the decoder. | ||
| 145 | /// The returned future can be awaited to obtain the number of steps. | ||
| 146 | /// | ||
| 147 | /// If the future is dropped, the read is cancelled. | ||
| 148 | /// | ||
| 149 | /// # Example | ||
| 150 | /// | ||
| 151 | /// ```no_run | ||
| 152 | /// let irq = interrupt::take!(QDEC); | ||
| 153 | /// let config = qdec::Config::default(); | ||
| 154 | /// let mut q = Qdec::new(p.QDEC, p.P0_31, p.P0_30, config); | ||
| 155 | /// let delta = q.read().await; | ||
| 156 | /// ``` | ||
| 157 | pub async fn read(&mut self) -> i16 { | ||
| 158 | // In case the future is dropped, stop the task and reset events. | ||
| 159 | let on_drop = OnDrop::new(|| { | ||
| 160 | let t = Self::regs(); | ||
| 161 | t.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 162 | t.events_reportrdy.reset(); | ||
| 163 | }); | ||
| 164 | |||
| 165 | let t = Self::regs(); | ||
| 166 | t.intenset.write(|w| w.reportrdy().set()); | ||
| 167 | unsafe { t.tasks_start.write(|w| w.bits(1)) }; | ||
| 168 | unsafe { t.tasks_readclracc.write(|w| w.bits(1)) }; | ||
| 169 | |||
| 170 | let value = poll_fn(|cx| { | ||
| 171 | WAKER.register(cx.waker()); | ||
| 172 | if t.events_reportrdy.read().bits() == 0 { | ||
| 173 | return Poll::Pending; | ||
| 174 | } else { | ||
| 175 | t.events_reportrdy.reset(); | ||
| 176 | let acc = t.accread.read().bits(); | ||
| 177 | Poll::Ready(acc as i16) | ||
| 178 | } | ||
| 179 | }) | ||
| 180 | .await; | ||
| 181 | on_drop.defuse(); | ||
| 182 | value | ||
| 183 | } | ||
| 184 | |||
| 185 | fn regs() -> &'static pac::qdec::RegisterBlock { | ||
| 186 | unsafe { &*pac::QDEC::ptr() } | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 191 | pub enum SamplePeriod { | ||
| 192 | _128us, | ||
| 193 | _256us, | ||
| 194 | _512us, | ||
| 195 | _1024us, | ||
| 196 | _2048us, | ||
| 197 | _4096us, | ||
| 198 | _8192us, | ||
| 199 | _16384us, | ||
| 200 | _32ms, | ||
| 201 | _65ms, | ||
| 202 | _131ms, | ||
| 203 | } | ||
| 204 | |||
| 205 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 206 | pub enum NumSamples { | ||
| 207 | _10smpl, | ||
| 208 | _40smpl, | ||
| 209 | _80smpl, | ||
| 210 | _120smpl, | ||
| 211 | _160smpl, | ||
| 212 | _200smpl, | ||
| 213 | _240smpl, | ||
| 214 | _280smpl, | ||
| 215 | _1smpl, | ||
| 216 | } | ||
| 217 | |||
| 218 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 219 | pub enum LedPolarity { | ||
| 220 | ActiveHigh, | ||
| 221 | ActiveLow, | ||
| 222 | } | ||
diff --git a/examples/nrf/src/bin/qdec.rs b/examples/nrf/src/bin/qdec.rs new file mode 100644 index 000000000..9c670cea0 --- /dev/null +++ b/examples/nrf/src/bin/qdec.rs | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::info; | ||
| 6 | use embassy::executor::Spawner; | ||
| 7 | use embassy_nrf::{ | ||
| 8 | interrupt, | ||
| 9 | qdec::{self, Qdec}, | ||
| 10 | Peripherals, | ||
| 11 | }; | ||
| 12 | |||
| 13 | use defmt_rtt as _; // global logger | ||
| 14 | use panic_probe as _; | ||
| 15 | |||
| 16 | #[embassy::main] | ||
| 17 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 18 | let irq = interrupt::take!(QDEC); | ||
| 19 | let config = qdec::Config::default(); | ||
| 20 | let mut rotary = Qdec::new(p.QDEC, irq, p.P1_13, p.P0_12, config); | ||
| 21 | // let mut rotary = Qdec::new(p.QDEC, irq, p.P0_31, p.P0_30, config); | ||
| 22 | |||
| 23 | info!("Turn rotary encoder!"); | ||
| 24 | let mut value = 0; | ||
| 25 | loop { | ||
| 26 | value += rotary.read().await; | ||
| 27 | info!("Value: {}", value); | ||
| 28 | } | ||
| 29 | } | ||
