aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--embassy-rp/src/adc.rs102
-rw-r--r--embassy-rp/src/lib.rs1
-rw-r--r--examples/rp/src/bin/adc.rs11
-rw-r--r--tests/rp/src/bin/adc.rs22
4 files changed, 66 insertions, 70 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
diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs
index 81a8b8340..c58695512 100644
--- a/examples/rp/src/bin/adc.rs
+++ b/examples/rp/src/bin/adc.rs
@@ -7,7 +7,7 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin}; 10use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
11use embassy_rp::bind_interrupts; 11use embassy_rp::bind_interrupts;
12use embassy_rp::gpio::Pull; 12use embassy_rp::gpio::Pull;
13use embassy_time::{Duration, Timer}; 13use embassy_time::{Duration, Timer};
@@ -22,9 +22,10 @@ async fn main(_spawner: Spawner) {
22 let p = embassy_rp::init(Default::default()); 22 let p = embassy_rp::init(Default::default());
23 let mut adc = Adc::new(p.ADC, Irqs, Config::default()); 23 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
24 24
25 let mut p26 = Pin::new(p.PIN_26, Pull::None); 25 let mut p26 = Channel::new_pin(p.PIN_26, Pull::None);
26 let mut p27 = Pin::new(p.PIN_27, Pull::None); 26 let mut p27 = Channel::new_pin(p.PIN_27, Pull::None);
27 let mut p28 = Pin::new(p.PIN_28, Pull::None); 27 let mut p28 = Channel::new_pin(p.PIN_28, Pull::None);
28 let mut ts = Channel::new_sensor(p.ADC_TEMP_SENSOR);
28 29
29 loop { 30 loop {
30 let level = adc.read(&mut p26).await.unwrap(); 31 let level = adc.read(&mut p26).await.unwrap();
@@ -33,7 +34,7 @@ async fn main(_spawner: Spawner) {
33 info!("Pin 27 ADC: {}", level); 34 info!("Pin 27 ADC: {}", level);
34 let level = adc.read(&mut p28).await.unwrap(); 35 let level = adc.read(&mut p28).await.unwrap();
35 info!("Pin 28 ADC: {}", level); 36 info!("Pin 28 ADC: {}", level);
36 let temp = adc.read_temperature().await.unwrap(); 37 let temp = adc.read(&mut ts).await.unwrap();
37 info!("Temp: {} degrees", convert_to_celsius(temp)); 38 info!("Temp: {} degrees", convert_to_celsius(temp));
38 Timer::after(Duration::from_secs(1)).await; 39 Timer::after(Duration::from_secs(1)).await;
39 } 40 }
diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs
index e659844ae..9006ce8cc 100644
--- a/tests/rp/src/bin/adc.rs
+++ b/tests/rp/src/bin/adc.rs
@@ -6,7 +6,7 @@ mod common;
6 6
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin}; 9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
10use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::Pull; 11use embassy_rp::gpio::Pull;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
@@ -22,12 +22,12 @@ async fn main(_spawner: Spawner) {
22 22
23 { 23 {
24 { 24 {
25 let mut p = Pin::new(&mut p.PIN_26, Pull::Down); 25 let mut p = Channel::new_pin(&mut p.PIN_26, Pull::Down);
26 defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); 26 defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
27 defmt::assert!(adc.read(&mut p).await.unwrap() < 0b01_0000_0000); 27 defmt::assert!(adc.read(&mut p).await.unwrap() < 0b01_0000_0000);
28 } 28 }
29 { 29 {
30 let mut p = Pin::new(&mut p.PIN_26, Pull::Up); 30 let mut p = Channel::new_pin(&mut p.PIN_26, Pull::Up);
31 defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); 31 defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
32 defmt::assert!(adc.read(&mut p).await.unwrap() > 0b11_0000_0000); 32 defmt::assert!(adc.read(&mut p).await.unwrap() > 0b11_0000_0000);
33 } 33 }
@@ -35,21 +35,21 @@ async fn main(_spawner: Spawner) {
35 // not bothering with async reads from now on 35 // not bothering with async reads from now on
36 { 36 {
37 { 37 {
38 let mut p = Pin::new(&mut p.PIN_27, Pull::Down); 38 let mut p = Channel::new_pin(&mut p.PIN_27, Pull::Down);
39 defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); 39 defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
40 } 40 }
41 { 41 {
42 let mut p = Pin::new(&mut p.PIN_27, Pull::Up); 42 let mut p = Channel::new_pin(&mut p.PIN_27, Pull::Up);
43 defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); 43 defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
44 } 44 }
45 } 45 }
46 { 46 {
47 { 47 {
48 let mut p = Pin::new(&mut p.PIN_28, Pull::Down); 48 let mut p = Channel::new_pin(&mut p.PIN_28, Pull::Down);
49 defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); 49 defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
50 } 50 }
51 { 51 {
52 let mut p = Pin::new(&mut p.PIN_28, Pull::Up); 52 let mut p = Channel::new_pin(&mut p.PIN_28, Pull::Up);
53 defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); 53 defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
54 } 54 }
55 } 55 }
@@ -57,22 +57,22 @@ async fn main(_spawner: Spawner) {
57 // gp29 is connected to vsys through a 200k/100k divider, 57 // gp29 is connected to vsys through a 200k/100k divider,
58 // adding pulls should change the value 58 // adding pulls should change the value
59 let low = { 59 let low = {
60 let mut p = Pin::new(&mut p.PIN_29, Pull::Down); 60 let mut p = Channel::new_pin(&mut p.PIN_29, Pull::Down);
61 adc.blocking_read(&mut p).unwrap() 61 adc.blocking_read(&mut p).unwrap()
62 }; 62 };
63 let none = { 63 let none = {
64 let mut p = Pin::new(&mut p.PIN_29, Pull::None); 64 let mut p = Channel::new_pin(&mut p.PIN_29, Pull::None);
65 adc.blocking_read(&mut p).unwrap() 65 adc.blocking_read(&mut p).unwrap()
66 }; 66 };
67 let up = { 67 let up = {
68 let mut p = Pin::new(&mut p.PIN_29, Pull::Up); 68 let mut p = Channel::new_pin(&mut p.PIN_29, Pull::Up);
69 adc.blocking_read(&mut p).unwrap() 69 adc.blocking_read(&mut p).unwrap()
70 }; 70 };
71 defmt::assert!(low < none); 71 defmt::assert!(low < none);
72 defmt::assert!(none < up); 72 defmt::assert!(none < up);
73 } 73 }
74 74
75 let temp = convert_to_celsius(adc.read_temperature().await.unwrap()); 75 let temp = convert_to_celsius(adc.read(&mut Channel::new_sensor(p.ADC_TEMP_SENSOR)).await.unwrap());
76 defmt::assert!(temp > 0.0); 76 defmt::assert!(temp > 0.0);
77 defmt::assert!(temp < 60.0); 77 defmt::assert!(temp < 60.0);
78 78