diff options
| -rw-r--r-- | embassy-rp/src/adc.rs | 225 | ||||
| -rw-r--r-- | embassy-rp/src/gpio.rs | 2 | ||||
| -rw-r--r-- | examples/rp/src/bin/adc.rs | 17 | ||||
| -rw-r--r-- | tests/rp/src/bin/adc.rs | 86 |
4 files changed, 237 insertions, 93 deletions
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 699a0d61d..dfa1b877a 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs | |||
| @@ -3,22 +3,17 @@ use core::marker::PhantomData; | |||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | 3 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 6 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 7 | use embedded_hal_02::adc::{Channel, OneShot}; | ||
| 8 | 8 | ||
| 9 | use crate::gpio::Pin; | 9 | use crate::gpio::sealed::Pin as GpioPin; |
| 10 | use crate::gpio::{self, AnyPin, Pull}; | ||
| 10 | use crate::interrupt::typelevel::Binding; | 11 | use crate::interrupt::typelevel::Binding; |
| 11 | use crate::interrupt::InterruptExt; | 12 | use crate::interrupt::InterruptExt; |
| 12 | use crate::peripherals::ADC; | 13 | use crate::peripherals::ADC; |
| 13 | use crate::{interrupt, pac, peripherals, Peripheral}; | 14 | use crate::{interrupt, pac, peripherals, Peripheral}; |
| 14 | static WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 15 | 15 | ||
| 16 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 16 | static WAKER: AtomicWaker = AtomicWaker::new(); |
| 17 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 18 | #[non_exhaustive] | ||
| 19 | pub enum Error { | ||
| 20 | // No errors for now | ||
| 21 | } | ||
| 22 | 17 | ||
| 23 | #[non_exhaustive] | 18 | #[non_exhaustive] |
| 24 | pub struct Config {} | 19 | pub struct Config {} |
| @@ -28,11 +23,65 @@ impl Default for Config { | |||
| 28 | Self {} | 23 | Self {} |
| 29 | } | 24 | } |
| 30 | } | 25 | } |
| 31 | pub struct Adc<'d> { | 26 | |
| 32 | phantom: PhantomData<&'d ADC>, | 27 | pub struct Pin<'p> { |
| 28 | pin: PeripheralRef<'p, AnyPin>, | ||
| 29 | } | ||
| 30 | |||
| 31 | impl<'p> Pin<'p> { | ||
| 32 | pub fn new(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self { | ||
| 33 | into_ref!(pin); | ||
| 34 | pin.pad_ctrl().modify(|w| { | ||
| 35 | // manual says: | ||
| 36 | // | ||
| 37 | // > When using an ADC input shared with a GPIO pin, the pin’s | ||
| 38 | // > digital functions must be disabled by setting IE low and OD | ||
| 39 | // > high in the pin’s pad control register | ||
| 40 | w.set_ie(false); | ||
| 41 | w.set_od(true); | ||
| 42 | w.set_pue(pull == Pull::Up); | ||
| 43 | w.set_pde(pull == Pull::Down); | ||
| 44 | }); | ||
| 45 | Self { pin: pin.map_into() } | ||
| 46 | } | ||
| 47 | |||
| 48 | fn channel(&self) -> u8 { | ||
| 49 | // this requires adc pins to be sequential and matching the adc channels, | ||
| 50 | // which is the case for rp2040 | ||
| 51 | self.pin._pin() - 26 | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | impl<'d> Drop for Pin<'d> { | ||
| 56 | fn drop(&mut self) { | ||
| 57 | self.pin.pad_ctrl().modify(|w| { | ||
| 58 | w.set_ie(true); | ||
| 59 | w.set_od(false); | ||
| 60 | w.set_pue(false); | ||
| 61 | w.set_pde(true); | ||
| 62 | }); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||
| 67 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 68 | pub enum Error { | ||
| 69 | ConversionFailed, | ||
| 70 | } | ||
| 71 | |||
| 72 | pub trait Mode {} | ||
| 73 | |||
| 74 | pub struct Async; | ||
| 75 | impl Mode for Async {} | ||
| 76 | |||
| 77 | pub struct Blocking; | ||
| 78 | impl Mode for Blocking {} | ||
| 79 | |||
| 80 | pub struct Adc<'d, M: Mode> { | ||
| 81 | phantom: PhantomData<(&'d ADC, M)>, | ||
| 33 | } | 82 | } |
| 34 | 83 | ||
| 35 | impl<'d> Adc<'d> { | 84 | impl<'d, M: Mode> Adc<'d, M> { |
| 36 | #[inline] | 85 | #[inline] |
| 37 | fn regs() -> pac::adc::Adc { | 86 | fn regs() -> pac::adc::Adc { |
| 38 | pac::ADC | 87 | pac::ADC |
| @@ -45,11 +94,7 @@ impl<'d> Adc<'d> { | |||
| 45 | ret | 94 | ret |
| 46 | } | 95 | } |
| 47 | 96 | ||
| 48 | pub fn new( | 97 | fn setup() { |
| 49 | _inner: impl Peripheral<P = ADC> + 'd, | ||
| 50 | _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>, | ||
| 51 | _config: Config, | ||
| 52 | ) -> Self { | ||
| 53 | let reset = Self::reset(); | 98 | let reset = Self::reset(); |
| 54 | crate::reset::reset(reset); | 99 | crate::reset::reset(reset); |
| 55 | crate::reset::unreset_wait(reset); | 100 | crate::reset::unreset_wait(reset); |
| @@ -58,6 +103,43 @@ impl<'d> Adc<'d> { | |||
| 58 | r.cs().write(|w| w.set_en(true)); | 103 | r.cs().write(|w| w.set_en(true)); |
| 59 | // Wait for ADC ready | 104 | // Wait for ADC ready |
| 60 | while !r.cs().read().ready() {} | 105 | while !r.cs().read().ready() {} |
| 106 | } | ||
| 107 | |||
| 108 | fn sample_blocking(channel: u8) -> Result<u16, Error> { | ||
| 109 | let r = Self::regs(); | ||
| 110 | r.cs().modify(|w| { | ||
| 111 | w.set_ainsel(channel); | ||
| 112 | w.set_start_once(true); | ||
| 113 | w.set_err(true); | ||
| 114 | }); | ||
| 115 | while !r.cs().read().ready() {} | ||
| 116 | match r.cs().read().err() { | ||
| 117 | true => Err(Error::ConversionFailed), | ||
| 118 | false => Ok(r.result().read().result().into()), | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | pub fn blocking_read(&mut self, pin: &mut Pin) -> Result<u16, Error> { | ||
| 123 | Self::sample_blocking(pin.channel()) | ||
| 124 | } | ||
| 125 | |||
| 126 | pub fn blocking_read_temperature(&mut self) -> Result<u16, Error> { | ||
| 127 | let r = Self::regs(); | ||
| 128 | r.cs().modify(|w| w.set_ts_en(true)); | ||
| 129 | while !r.cs().read().ready() {} | ||
| 130 | let result = Self::sample_blocking(4); | ||
| 131 | r.cs().modify(|w| w.set_ts_en(false)); | ||
| 132 | result | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | impl<'d> Adc<'d, Async> { | ||
| 137 | pub fn new( | ||
| 138 | _inner: impl Peripheral<P = ADC> + 'd, | ||
| 139 | _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>, | ||
| 140 | _config: Config, | ||
| 141 | ) -> Self { | ||
| 142 | Self::setup(); | ||
| 61 | 143 | ||
| 62 | // Setup IRQ | 144 | // Setup IRQ |
| 63 | interrupt::ADC_IRQ_FIFO.unpend(); | 145 | interrupt::ADC_IRQ_FIFO.unpend(); |
| @@ -80,102 +162,77 @@ impl<'d> Adc<'d> { | |||
| 80 | .await; | 162 | .await; |
| 81 | } | 163 | } |
| 82 | 164 | ||
| 83 | pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { | 165 | async fn sample_async(channel: u8) -> Result<u16, Error> { |
| 84 | let r = Self::regs(); | 166 | let r = Self::regs(); |
| 85 | // disable pull-down and pull-up resistors | ||
| 86 | // pull-down resistors are enabled by default | ||
| 87 | pin.pad_ctrl().modify(|w| { | ||
| 88 | w.set_ie(true); | ||
| 89 | let (pu, pd) = (false, false); | ||
| 90 | w.set_pue(pu); | ||
| 91 | w.set_pde(pd); | ||
| 92 | }); | ||
| 93 | r.cs().modify(|w| { | 167 | r.cs().modify(|w| { |
| 94 | w.set_ainsel(PIN::channel()); | 168 | w.set_ainsel(channel); |
| 95 | w.set_start_once(true) | 169 | w.set_start_once(true); |
| 170 | w.set_err(true); | ||
| 96 | }); | 171 | }); |
| 97 | Self::wait_for_ready().await; | 172 | Self::wait_for_ready().await; |
| 98 | r.result().read().result().into() | 173 | match r.cs().read().err() { |
| 174 | true => Err(Error::ConversionFailed), | ||
| 175 | false => Ok(r.result().read().result().into()), | ||
| 176 | } | ||
| 99 | } | 177 | } |
| 100 | 178 | ||
| 101 | pub async fn read_temperature(&mut self) -> u16 { | 179 | pub async fn read(&mut self, pin: &mut Pin<'_>) -> Result<u16, Error> { |
| 180 | Self::sample_async(pin.channel()).await | ||
| 181 | } | ||
| 182 | |||
| 183 | pub async fn read_temperature(&mut self) -> Result<u16, Error> { | ||
| 102 | let r = Self::regs(); | 184 | let r = Self::regs(); |
| 103 | r.cs().modify(|w| w.set_ts_en(true)); | 185 | r.cs().modify(|w| w.set_ts_en(true)); |
| 104 | if !r.cs().read().ready() { | 186 | if !r.cs().read().ready() { |
| 105 | Self::wait_for_ready().await; | 187 | Self::wait_for_ready().await; |
| 106 | } | 188 | } |
| 107 | r.cs().modify(|w| { | 189 | let result = Self::sample_async(4).await; |
| 108 | w.set_ainsel(4); | 190 | r.cs().modify(|w| w.set_ts_en(false)); |
| 109 | w.set_start_once(true) | 191 | result |
| 110 | }); | ||
| 111 | Self::wait_for_ready().await; | ||
| 112 | r.result().read().result().into() | ||
| 113 | } | 192 | } |
| 193 | } | ||
| 114 | 194 | ||
| 115 | pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { | 195 | impl<'d> Adc<'d, Blocking> { |
| 116 | let r = Self::regs(); | 196 | pub fn new_blocking(_inner: impl Peripheral<P = ADC> + 'd, _config: Config) -> Self { |
| 117 | pin.pad_ctrl().modify(|w| { | 197 | Self::setup(); |
| 118 | w.set_ie(true); | ||
| 119 | let (pu, pd) = (false, false); | ||
| 120 | w.set_pue(pu); | ||
| 121 | w.set_pde(pd); | ||
| 122 | }); | ||
| 123 | r.cs().modify(|w| { | ||
| 124 | w.set_ainsel(PIN::channel()); | ||
| 125 | w.set_start_once(true) | ||
| 126 | }); | ||
| 127 | while !r.cs().read().ready() {} | ||
| 128 | r.result().read().result().into() | ||
| 129 | } | ||
| 130 | 198 | ||
| 131 | pub fn blocking_read_temperature(&mut self) -> u16 { | 199 | Self { phantom: PhantomData } |
| 132 | let r = Self::regs(); | ||
| 133 | r.cs().modify(|w| w.set_ts_en(true)); | ||
| 134 | while !r.cs().read().ready() {} | ||
| 135 | r.cs().modify(|w| { | ||
| 136 | w.set_ainsel(4); | ||
| 137 | w.set_start_once(true) | ||
| 138 | }); | ||
| 139 | while !r.cs().read().ready() {} | ||
| 140 | r.result().read().result().into() | ||
| 141 | } | 200 | } |
| 142 | } | 201 | } |
| 143 | 202 | ||
| 144 | macro_rules! impl_pin { | ||
| 145 | ($pin:ident, $channel:expr) => { | ||
| 146 | impl Channel<Adc<'static>> for peripherals::$pin { | ||
| 147 | type ID = u8; | ||
| 148 | fn channel() -> u8 { | ||
| 149 | $channel | ||
| 150 | } | ||
| 151 | } | ||
| 152 | }; | ||
| 153 | } | ||
| 154 | |||
| 155 | pub struct InterruptHandler { | 203 | pub struct InterruptHandler { |
| 156 | _empty: (), | 204 | _empty: (), |
| 157 | } | 205 | } |
| 158 | 206 | ||
| 159 | impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler { | 207 | impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler { |
| 160 | unsafe fn on_interrupt() { | 208 | unsafe fn on_interrupt() { |
| 161 | let r = Adc::regs(); | 209 | let r = Adc::<Async>::regs(); |
| 162 | r.inte().write(|w| w.set_fifo(false)); | 210 | r.inte().write(|w| w.set_fifo(false)); |
| 163 | WAKER.wake(); | 211 | WAKER.wake(); |
| 164 | } | 212 | } |
| 165 | } | 213 | } |
| 166 | 214 | ||
| 215 | mod sealed { | ||
| 216 | pub trait AdcPin: crate::gpio::sealed::Pin { | ||
| 217 | fn channel(&mut self) -> u8; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | pub trait AdcPin: sealed::AdcPin + gpio::Pin {} | ||
| 222 | |||
| 223 | macro_rules! impl_pin { | ||
| 224 | ($pin:ident, $channel:expr) => { | ||
| 225 | impl sealed::AdcPin for peripherals::$pin { | ||
| 226 | fn channel(&mut self) -> u8 { | ||
| 227 | $channel | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | impl AdcPin for peripherals::$pin {} | ||
| 232 | }; | ||
| 233 | } | ||
| 234 | |||
| 167 | impl_pin!(PIN_26, 0); | 235 | impl_pin!(PIN_26, 0); |
| 168 | impl_pin!(PIN_27, 1); | 236 | impl_pin!(PIN_27, 1); |
| 169 | impl_pin!(PIN_28, 2); | 237 | impl_pin!(PIN_28, 2); |
| 170 | impl_pin!(PIN_29, 3); | 238 | impl_pin!(PIN_29, 3); |
| 171 | |||
| 172 | impl<WORD, PIN> OneShot<Adc<'static>, WORD, PIN> for Adc<'static> | ||
| 173 | where | ||
| 174 | WORD: From<u16>, | ||
| 175 | PIN: Channel<Adc<'static>, ID = u8> + Pin, | ||
| 176 | { | ||
| 177 | type Error = (); | ||
| 178 | fn read(&mut self, pin: &mut PIN) -> nb::Result<WORD, Self::Error> { | ||
| 179 | Ok(self.blocking_read(pin).into()) | ||
| 180 | } | ||
| 181 | } | ||
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index f8048a4dd..d18fb909c 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs | |||
| @@ -41,7 +41,7 @@ impl From<Level> for bool { | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | /// Represents a pull setting for an input. | 43 | /// Represents a pull setting for an input. |
| 44 | #[derive(Debug, Eq, PartialEq)] | 44 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] |
| 45 | pub enum Pull { | 45 | pub enum Pull { |
| 46 | None, | 46 | None, |
| 47 | Up, | 47 | Up, |
diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs index 7c2ca19f7..65069cde1 100644 --- a/examples/rp/src/bin/adc.rs +++ b/examples/rp/src/bin/adc.rs | |||
| @@ -4,8 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_rp::adc::{Adc, Config, InterruptHandler}; | 7 | use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin}; |
| 8 | use embassy_rp::bind_interrupts; | 8 | use embassy_rp::bind_interrupts; |
| 9 | use embassy_rp::gpio::Pull; | ||
| 9 | use embassy_time::{Duration, Timer}; | 10 | use embassy_time::{Duration, Timer}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 12 | ||
| @@ -18,18 +19,18 @@ async fn main(_spawner: Spawner) { | |||
| 18 | let p = embassy_rp::init(Default::default()); | 19 | let p = embassy_rp::init(Default::default()); |
| 19 | let mut adc = Adc::new(p.ADC, Irqs, Config::default()); | 20 | let mut adc = Adc::new(p.ADC, Irqs, Config::default()); |
| 20 | 21 | ||
| 21 | let mut p26 = p.PIN_26; | 22 | let mut p26 = Pin::new(p.PIN_26, Pull::None); |
| 22 | let mut p27 = p.PIN_27; | 23 | let mut p27 = Pin::new(p.PIN_27, Pull::None); |
| 23 | let mut p28 = p.PIN_28; | 24 | let mut p28 = Pin::new(p.PIN_28, Pull::None); |
| 24 | 25 | ||
| 25 | loop { | 26 | loop { |
| 26 | let level = adc.read(&mut p26).await; | 27 | let level = adc.read(&mut p26).await.unwrap(); |
| 27 | info!("Pin 26 ADC: {}", level); | 28 | info!("Pin 26 ADC: {}", level); |
| 28 | let level = adc.read(&mut p27).await; | 29 | let level = adc.read(&mut p27).await.unwrap(); |
| 29 | info!("Pin 27 ADC: {}", level); | 30 | info!("Pin 27 ADC: {}", level); |
| 30 | let level = adc.read(&mut p28).await; | 31 | let level = adc.read(&mut p28).await.unwrap(); |
| 31 | info!("Pin 28 ADC: {}", level); | 32 | info!("Pin 28 ADC: {}", level); |
| 32 | let temp = adc.read_temperature().await; | 33 | let temp = adc.read_temperature().await.unwrap(); |
| 33 | info!("Temp: {} degrees", convert_to_celsius(temp)); | 34 | info!("Temp: {} degrees", convert_to_celsius(temp)); |
| 34 | Timer::after(Duration::from_secs(1)).await; | 35 | Timer::after(Duration::from_secs(1)).await; |
| 35 | } | 36 | } |
diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs new file mode 100644 index 000000000..e659844ae --- /dev/null +++ b/tests/rp/src/bin/adc.rs | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin}; | ||
| 10 | use embassy_rp::bind_interrupts; | ||
| 11 | use embassy_rp::gpio::Pull; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | ADC_IRQ_FIFO => InterruptHandler; | ||
| 16 | }); | ||
| 17 | |||
| 18 | #[embassy_executor::main] | ||
| 19 | async fn main(_spawner: Spawner) { | ||
| 20 | let mut p = embassy_rp::init(Default::default()); | ||
| 21 | let mut adc = Adc::new(p.ADC, Irqs, Config::default()); | ||
| 22 | |||
| 23 | { | ||
| 24 | { | ||
| 25 | let mut p = Pin::new(&mut p.PIN_26, Pull::Down); | ||
| 26 | defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); | ||
| 27 | defmt::assert!(adc.read(&mut p).await.unwrap() < 0b01_0000_0000); | ||
| 28 | } | ||
| 29 | { | ||
| 30 | let mut p = Pin::new(&mut p.PIN_26, Pull::Up); | ||
| 31 | defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); | ||
| 32 | defmt::assert!(adc.read(&mut p).await.unwrap() > 0b11_0000_0000); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | // not bothering with async reads from now on | ||
| 36 | { | ||
| 37 | { | ||
| 38 | let mut p = Pin::new(&mut p.PIN_27, Pull::Down); | ||
| 39 | defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); | ||
| 40 | } | ||
| 41 | { | ||
| 42 | let mut p = Pin::new(&mut p.PIN_27, Pull::Up); | ||
| 43 | defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | { | ||
| 47 | { | ||
| 48 | let mut p = Pin::new(&mut p.PIN_28, Pull::Down); | ||
| 49 | defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); | ||
| 50 | } | ||
| 51 | { | ||
| 52 | let mut p = Pin::new(&mut p.PIN_28, Pull::Up); | ||
| 53 | defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | { | ||
| 57 | // gp29 is connected to vsys through a 200k/100k divider, | ||
| 58 | // adding pulls should change the value | ||
| 59 | let low = { | ||
| 60 | let mut p = Pin::new(&mut p.PIN_29, Pull::Down); | ||
| 61 | adc.blocking_read(&mut p).unwrap() | ||
| 62 | }; | ||
| 63 | let none = { | ||
| 64 | let mut p = Pin::new(&mut p.PIN_29, Pull::None); | ||
| 65 | adc.blocking_read(&mut p).unwrap() | ||
| 66 | }; | ||
| 67 | let up = { | ||
| 68 | let mut p = Pin::new(&mut p.PIN_29, Pull::Up); | ||
| 69 | adc.blocking_read(&mut p).unwrap() | ||
| 70 | }; | ||
| 71 | defmt::assert!(low < none); | ||
| 72 | defmt::assert!(none < up); | ||
| 73 | } | ||
| 74 | |||
| 75 | let temp = convert_to_celsius(adc.read_temperature().await.unwrap()); | ||
| 76 | defmt::assert!(temp > 0.0); | ||
| 77 | defmt::assert!(temp < 60.0); | ||
| 78 | |||
| 79 | info!("Test OK"); | ||
| 80 | cortex_m::asm::bkpt(); | ||
| 81 | } | ||
| 82 | |||
| 83 | fn convert_to_celsius(raw_temp: u16) -> f32 { | ||
| 84 | // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet | ||
| 85 | 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721 as f32 | ||
| 86 | } | ||
