aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-05-12 13:40:08 +0000
committerGitHub <[email protected]>2022-05-12 13:40:08 +0000
commit45c0f1ab88edb7a635faf3bb0941d81772100da1 (patch)
tree312d4acf488d7715850fac52323ec3b34968c0ab
parent30d4d0e9d78681e16a68ff953c61b96c9863bfc6 (diff)
parent93cbd079ec1f5b8371fb4d52b00e0a404403f73d (diff)
Merge #756
756: Add async quadrature decoder for embassy-nrf r=Dirbaio a=kalkyl Thsi PR adds an async interface to the QDEC peripheral to embassy-nrf, that can be used for rotary encoders for example. Co-authored-by: Henrik Alsér <[email protected]> Co-authored-by: Henrik Alsér <[email protected]> Co-authored-by: Henrik Alsér <[email protected]>
-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.rs216
-rw-r--r--examples/nrf/src/bin/qdec.rs28
10 files changed, 267 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
127impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 130impl_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
130impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 133impl_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
130impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 133impl_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
140impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 143impl_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 865f33d70..9c298a8b0 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -74,6 +74,8 @@ pub mod nvmc;
74pub mod ppi; 74pub mod ppi;
75#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] 75#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))]
76pub mod pwm; 76pub mod pwm;
77#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340")))]
78pub mod qdec;
77#[cfg(feature = "nrf52840")] 79#[cfg(feature = "nrf52840")]
78pub mod qspi; 80pub mod qspi;
79#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 81#[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..c26815389
--- /dev/null
+++ b/embassy-nrf/src/qdec.rs
@@ -0,0 +1,216 @@
1//! Quadrature decoder interface
2
3use crate::gpio::sealed::Pin as _;
4use crate::gpio::{AnyPin, Pin as GpioPin};
5use crate::interrupt;
6use crate::pac;
7use crate::peripherals::QDEC;
8
9use core::marker::PhantomData;
10use core::task::Poll;
11use embassy::interrupt::InterruptExt;
12use embassy::util::Unborrow;
13use embassy::waitqueue::AtomicWaker;
14use embassy_hal_common::unborrow;
15use futures::future::poll_fn;
16
17/// Quadrature decoder
18pub struct Qdec<'d> {
19 phantom: PhantomData<&'d QDEC>,
20}
21
22#[non_exhaustive]
23pub 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
31impl 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
43static WAKER: AtomicWaker = AtomicWaker::new();
44
45impl<'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 // Start sampling
132 unsafe { r.tasks_start.write(|w| w.bits(1)) };
133
134 irq.disable();
135 irq.set_handler(|_| {
136 let r = Self::regs();
137 r.intenclr.write(|w| w.reportrdy().clear());
138 WAKER.wake();
139 });
140 irq.enable();
141
142 Self {
143 phantom: PhantomData,
144 }
145 }
146
147 /// Perform an asynchronous read of the decoder.
148 /// The returned future can be awaited to obtain the number of steps.
149 ///
150 /// If the future is dropped, the read is cancelled.
151 ///
152 /// # Example
153 ///
154 /// ```no_run
155 /// let irq = interrupt::take!(QDEC);
156 /// let config = qdec::Config::default();
157 /// let mut q = Qdec::new(p.QDEC, p.P0_31, p.P0_30, config);
158 /// let delta = q.read().await;
159 /// ```
160 pub async fn read(&mut self) -> i16 {
161 let t = Self::regs();
162 t.intenset.write(|w| w.reportrdy().set());
163 unsafe { t.tasks_readclracc.write(|w| w.bits(1)) };
164
165 let value = poll_fn(|cx| {
166 WAKER.register(cx.waker());
167 if t.events_reportrdy.read().bits() == 0 {
168 return Poll::Pending;
169 } else {
170 t.events_reportrdy.reset();
171 let acc = t.accread.read().bits();
172 Poll::Ready(acc as i16)
173 }
174 })
175 .await;
176 value
177 }
178
179 fn regs() -> &'static pac::qdec::RegisterBlock {
180 unsafe { &*pac::QDEC::ptr() }
181 }
182}
183
184#[derive(Debug, Eq, PartialEq, Clone, Copy)]
185pub enum SamplePeriod {
186 _128us,
187 _256us,
188 _512us,
189 _1024us,
190 _2048us,
191 _4096us,
192 _8192us,
193 _16384us,
194 _32ms,
195 _65ms,
196 _131ms,
197}
198
199#[derive(Debug, Eq, PartialEq, Clone, Copy)]
200pub enum NumSamples {
201 _10smpl,
202 _40smpl,
203 _80smpl,
204 _120smpl,
205 _160smpl,
206 _200smpl,
207 _240smpl,
208 _280smpl,
209 _1smpl,
210}
211
212#[derive(Debug, Eq, PartialEq, Clone, Copy)]
213pub enum LedPolarity {
214 ActiveHigh,
215 ActiveLow,
216}
diff --git a/examples/nrf/src/bin/qdec.rs b/examples/nrf/src/bin/qdec.rs
new file mode 100644
index 000000000..bf5b11468
--- /dev/null
+++ b/examples/nrf/src/bin/qdec.rs
@@ -0,0 +1,28 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy::executor::Spawner;
7use embassy_nrf::{
8 interrupt,
9 qdec::{self, Qdec},
10 Peripherals,
11};
12
13use defmt_rtt as _; // global logger
14use panic_probe as _;
15
16#[embassy::main]
17async fn main(_spawner: Spawner, p: Peripherals) {
18 let irq = interrupt::take!(QDEC);
19 let config = qdec::Config::default();
20 let mut rotary_enc = Qdec::new(p.QDEC, irq, p.P0_31, p.P0_30, config);
21
22 info!("Turn rotary encoder!");
23 let mut value = 0;
24 loop {
25 value += rotary_enc.read().await;
26 info!("Value: {}", value);
27 }
28}