aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-07-21 21:31:44 +0200
committerpennae <[email protected]>2023-08-01 18:31:28 +0200
commitb166ed6b78db0737005a65c1e444ce7563de7da3 (patch)
treeb06b0742ceb839e5739e92ea4c001617eb2f5d8c /embassy-rp
parent54d31c98fe44533c955c494ea58dd16810367c4f (diff)
rp: generalize adc inputs from pins to channels
this lets us treat pins and the temperature sensor uniformly using the same interface. uniformity in turn lets us add more adc features without combinatorial explosion of methods and types needed to handle them all.
Diffstat (limited to 'embassy-rp')
-rw-r--r--embassy-rp/src/adc.rs102
-rw-r--r--embassy-rp/src/lib.rs1
2 files changed, 49 insertions, 54 deletions
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index 38b323ec9..2824d893c 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -10,8 +10,8 @@ use crate::gpio::sealed::Pin as GpioPin;
10use crate::gpio::{self, AnyPin, Pull}; 10use crate::gpio::{self, AnyPin, Pull};
11use crate::interrupt::typelevel::Binding; 11use crate::interrupt::typelevel::Binding;
12use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
13use crate::peripherals::ADC; 13use crate::peripherals::{ADC, ADC_TEMP_SENSOR};
14use crate::{interrupt, pac, peripherals, Peripheral}; 14use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
15 15
16static WAKER: AtomicWaker = AtomicWaker::new(); 16static WAKER: AtomicWaker = AtomicWaker::new();
17 17
@@ -24,12 +24,15 @@ impl Default for Config {
24 } 24 }
25} 25}
26 26
27pub struct Pin<'p> { 27enum Source<'p> {
28 pin: PeripheralRef<'p, AnyPin>, 28 Pin(PeripheralRef<'p, AnyPin>),
29 TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>),
29} 30}
30 31
31impl<'p> Pin<'p> { 32pub struct Channel<'p>(Source<'p>);
32 pub fn new(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self { 33
34impl<'p> Channel<'p> {
35 pub fn new_pin(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self {
33 into_ref!(pin); 36 into_ref!(pin);
34 pin.pad_ctrl().modify(|w| { 37 pin.pad_ctrl().modify(|w| {
35 // manual says: 38 // manual says:
@@ -42,24 +45,40 @@ impl<'p> Pin<'p> {
42 w.set_pue(pull == Pull::Up); 45 w.set_pue(pull == Pull::Up);
43 w.set_pde(pull == Pull::Down); 46 w.set_pde(pull == Pull::Down);
44 }); 47 });
45 Self { pin: pin.map_into() } 48 Self(Source::Pin(pin.map_into()))
49 }
50
51 pub fn new_sensor(s: impl Peripheral<P = ADC_TEMP_SENSOR> + 'p) -> Self {
52 let r = pac::ADC;
53 r.cs().write_set(|w| w.set_ts_en(true));
54 Self(Source::TempSensor(s.into_ref()))
46 } 55 }
47 56
48 fn channel(&self) -> u8 { 57 fn channel(&self) -> u8 {
49 // this requires adc pins to be sequential and matching the adc channels, 58 match &self.0 {
50 // which is the case for rp2040 59 // this requires adc pins to be sequential and matching the adc channels,
51 self.pin._pin() - 26 60 // which is the case for rp2040
61 Source::Pin(p) => p._pin() - 26,
62 Source::TempSensor(_) => 4,
63 }
52 } 64 }
53} 65}
54 66
55impl<'d> Drop for Pin<'d> { 67impl<'p> Drop for Source<'p> {
56 fn drop(&mut self) { 68 fn drop(&mut self) {
57 self.pin.pad_ctrl().modify(|w| { 69 match self {
58 w.set_ie(true); 70 Source::Pin(p) => {
59 w.set_od(false); 71 p.pad_ctrl().modify(|w| {
60 w.set_pue(false); 72 w.set_ie(true);
61 w.set_pde(true); 73 w.set_od(false);
62 }); 74 w.set_pue(false);
75 w.set_pde(true);
76 });
77 }
78 Source::TempSensor(_) => {
79 pac::ADC.cs().write_clear(|w| w.set_ts_en(true));
80 }
81 }
63 } 82 }
64} 83}
65 84
@@ -115,10 +134,10 @@ impl<'d, M: Mode> Adc<'d, M> {
115 while !r.cs().read().ready() {} 134 while !r.cs().read().ready() {}
116 } 135 }
117 136
118 fn sample_blocking(channel: u8) -> Result<u16, Error> { 137 pub fn blocking_read(&mut self, ch: &mut Channel) -> Result<u16, Error> {
119 let r = Self::regs(); 138 let r = Self::regs();
120 r.cs().modify(|w| { 139 r.cs().modify(|w| {
121 w.set_ainsel(channel); 140 w.set_ainsel(ch.channel());
122 w.set_start_once(true); 141 w.set_start_once(true);
123 w.set_err(true); 142 w.set_err(true);
124 }); 143 });
@@ -128,19 +147,6 @@ impl<'d, M: Mode> Adc<'d, M> {
128 false => Ok(r.result().read().result().into()), 147 false => Ok(r.result().read().result().into()),
129 } 148 }
130 } 149 }
131
132 pub fn blocking_read(&mut self, pin: &mut Pin) -> Result<u16, Error> {
133 Self::sample_blocking(pin.channel())
134 }
135
136 pub fn blocking_read_temperature(&mut self) -> Result<u16, Error> {
137 let r = Self::regs();
138 r.cs().modify(|w| w.set_ts_en(true));
139 while !r.cs().read().ready() {}
140 let result = Self::sample_blocking(4);
141 r.cs().modify(|w| w.set_ts_en(false));
142 result
143 }
144} 150}
145 151
146impl<'d> Adc<'d, Async> { 152impl<'d> Adc<'d, Async> {
@@ -172,10 +178,10 @@ impl<'d> Adc<'d, Async> {
172 .await; 178 .await;
173 } 179 }
174 180
175 async fn sample_async(channel: u8) -> Result<u16, Error> { 181 pub async fn read(&mut self, ch: &mut Channel<'_>) -> Result<u16, Error> {
176 let r = Self::regs(); 182 let r = Self::regs();
177 r.cs().modify(|w| { 183 r.cs().modify(|w| {
178 w.set_ainsel(channel); 184 w.set_ainsel(ch.channel());
179 w.set_start_once(true); 185 w.set_start_once(true);
180 w.set_err(true); 186 w.set_err(true);
181 }); 187 });
@@ -185,21 +191,6 @@ impl<'d> Adc<'d, Async> {
185 false => Ok(r.result().read().result().into()), 191 false => Ok(r.result().read().result().into()),
186 } 192 }
187 } 193 }
188
189 pub async fn read(&mut self, pin: &mut Pin<'_>) -> Result<u16, Error> {
190 Self::sample_async(pin.channel()).await
191 }
192
193 pub async fn read_temperature(&mut self) -> Result<u16, Error> {
194 let r = Self::regs();
195 r.cs().modify(|w| w.set_ts_en(true));
196 if !r.cs().read().ready() {
197 Self::wait_for_ready().await;
198 }
199 let result = Self::sample_async(4).await;
200 r.cs().modify(|w| w.set_ts_en(false));
201 result
202 }
203} 194}
204 195
205impl<'d> Adc<'d, Blocking> { 196impl<'d> Adc<'d, Blocking> {
@@ -230,14 +221,17 @@ pub trait AdcChannel: sealed::AdcChannel {}
230pub trait AdcPin: AdcChannel + gpio::Pin {} 221pub trait AdcPin: AdcChannel + gpio::Pin {}
231 222
232macro_rules! impl_pin { 223macro_rules! impl_pin {
233 ($pin:ident) => { 224 ($pin:ident, $channel:expr) => {
234 impl sealed::AdcChannel for peripherals::$pin {} 225 impl sealed::AdcChannel for peripherals::$pin {}
235 impl AdcChannel for peripherals::$pin {} 226 impl AdcChannel for peripherals::$pin {}
236 impl AdcPin for peripherals::$pin {} 227 impl AdcPin for peripherals::$pin {}
237 }; 228 };
238} 229}
239 230
240impl_pin!(PIN_26); 231impl_pin!(PIN_26, 0);
241impl_pin!(PIN_27); 232impl_pin!(PIN_27, 1);
242impl_pin!(PIN_28); 233impl_pin!(PIN_28, 2);
243impl_pin!(PIN_29); 234impl_pin!(PIN_29, 3);
235
236impl sealed::AdcChannel for peripherals::ADC_TEMP_SENSOR {}
237impl AdcChannel for peripherals::ADC_TEMP_SENSOR {}
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 45156458d..49bd3533e 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -183,6 +183,7 @@ embassy_hal_internal::peripherals! {
183 FLASH, 183 FLASH,
184 184
185 ADC, 185 ADC,
186 ADC_TEMP_SENSOR,
186 187
187 CORE1, 188 CORE1,
188 189