diff options
| author | pennae <[email protected]> | 2023-07-21 21:31:44 +0200 |
|---|---|---|
| committer | pennae <[email protected]> | 2023-08-01 18:31:28 +0200 |
| commit | b166ed6b78db0737005a65c1e444ce7563de7da3 (patch) | |
| tree | b06b0742ceb839e5739e92ea4c001617eb2f5d8c /embassy-rp/src/adc.rs | |
| parent | 54d31c98fe44533c955c494ea58dd16810367c4f (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/src/adc.rs')
| -rw-r--r-- | embassy-rp/src/adc.rs | 102 |
1 files changed, 48 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; | |||
| 10 | use crate::gpio::{self, AnyPin, Pull}; | 10 | use crate::gpio::{self, AnyPin, Pull}; |
| 11 | use crate::interrupt::typelevel::Binding; | 11 | use crate::interrupt::typelevel::Binding; |
| 12 | use crate::interrupt::InterruptExt; | 12 | use crate::interrupt::InterruptExt; |
| 13 | use crate::peripherals::ADC; | 13 | use crate::peripherals::{ADC, ADC_TEMP_SENSOR}; |
| 14 | use crate::{interrupt, pac, peripherals, Peripheral}; | 14 | use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; |
| 15 | 15 | ||
| 16 | static WAKER: AtomicWaker = AtomicWaker::new(); | 16 | static WAKER: AtomicWaker = AtomicWaker::new(); |
| 17 | 17 | ||
| @@ -24,12 +24,15 @@ impl Default for Config { | |||
| 24 | } | 24 | } |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | pub struct Pin<'p> { | 27 | enum Source<'p> { |
| 28 | pin: PeripheralRef<'p, AnyPin>, | 28 | Pin(PeripheralRef<'p, AnyPin>), |
| 29 | TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>), | ||
| 29 | } | 30 | } |
| 30 | 31 | ||
| 31 | impl<'p> Pin<'p> { | 32 | pub struct Channel<'p>(Source<'p>); |
| 32 | pub fn new(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self { | 33 | |
| 34 | impl<'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 | ||
| 55 | impl<'d> Drop for Pin<'d> { | 67 | impl<'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 | ||
| 146 | impl<'d> Adc<'d, Async> { | 152 | impl<'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 | ||
| 205 | impl<'d> Adc<'d, Blocking> { | 196 | impl<'d> Adc<'d, Blocking> { |
| @@ -230,14 +221,17 @@ pub trait AdcChannel: sealed::AdcChannel {} | |||
| 230 | pub trait AdcPin: AdcChannel + gpio::Pin {} | 221 | pub trait AdcPin: AdcChannel + gpio::Pin {} |
| 231 | 222 | ||
| 232 | macro_rules! impl_pin { | 223 | macro_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 | ||
| 240 | impl_pin!(PIN_26); | 231 | impl_pin!(PIN_26, 0); |
| 241 | impl_pin!(PIN_27); | 232 | impl_pin!(PIN_27, 1); |
| 242 | impl_pin!(PIN_28); | 233 | impl_pin!(PIN_28, 2); |
| 243 | impl_pin!(PIN_29); | 234 | impl_pin!(PIN_29, 3); |
| 235 | |||
| 236 | impl sealed::AdcChannel for peripherals::ADC_TEMP_SENSOR {} | ||
| 237 | impl AdcChannel for peripherals::ADC_TEMP_SENSOR {} | ||
