diff options
| author | Henrik Alsér <[email protected]> | 2022-11-15 16:12:07 +0100 |
|---|---|---|
| committer | Henrik Alsér <[email protected]> | 2022-11-15 16:12:07 +0100 |
| commit | eb149a0bd42d7690e78e5f2b37579c1f68be613b (patch) | |
| tree | f6735a981123d6f8fd478a604db481d836e84ae5 | |
| parent | d05979c7085675c33615700f6590b1543ed69323 (diff) | |
embassy-rp: Add basic ADC module
| -rw-r--r-- | embassy-rp/src/adc.rs | 178 | ||||
| -rw-r--r-- | embassy-rp/src/lib.rs | 3 | ||||
| -rw-r--r-- | examples/rp/src/bin/adc.rs | 33 |
3 files changed, 214 insertions, 0 deletions
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs new file mode 100644 index 000000000..acef4deaf --- /dev/null +++ b/embassy-rp/src/adc.rs | |||
| @@ -0,0 +1,178 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 6 | use embassy_hal_common::into_ref; | ||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 8 | use embedded_hal_02::adc::{Channel, OneShot}; | ||
| 9 | |||
| 10 | use crate::interrupt::{self, InterruptExt}; | ||
| 11 | use crate::peripherals::ADC; | ||
| 12 | use crate::{pac, peripherals, Peripheral}; | ||
| 13 | static WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 14 | |||
| 15 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 16 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 17 | #[non_exhaustive] | ||
| 18 | pub enum Error { | ||
| 19 | // No errors for now | ||
| 20 | } | ||
| 21 | |||
| 22 | #[non_exhaustive] | ||
| 23 | pub struct Config {} | ||
| 24 | |||
| 25 | impl Default for Config { | ||
| 26 | fn default() -> Self { | ||
| 27 | Self {} | ||
| 28 | } | ||
| 29 | } | ||
| 30 | pub struct Adc<'d> { | ||
| 31 | phantom: PhantomData<&'d ADC>, | ||
| 32 | } | ||
| 33 | |||
| 34 | impl<'d> Adc<'d> { | ||
| 35 | #[inline] | ||
| 36 | fn regs() -> pac::adc::Adc { | ||
| 37 | pac::ADC | ||
| 38 | } | ||
| 39 | |||
| 40 | #[inline] | ||
| 41 | fn reset() -> pac::resets::regs::Peripherals { | ||
| 42 | let mut ret = pac::resets::regs::Peripherals::default(); | ||
| 43 | ret.set_adc(true); | ||
| 44 | ret | ||
| 45 | } | ||
| 46 | |||
| 47 | pub fn new( | ||
| 48 | _inner: impl Peripheral<P = ADC> + 'd, | ||
| 49 | irq: impl Peripheral<P = interrupt::ADC_IRQ_FIFO> + 'd, | ||
| 50 | _config: Config, | ||
| 51 | ) -> Self { | ||
| 52 | into_ref!(irq); | ||
| 53 | unsafe { | ||
| 54 | let reset = Self::reset(); | ||
| 55 | crate::reset::reset(reset); | ||
| 56 | crate::reset::unreset_wait(reset); | ||
| 57 | let r = Self::regs(); | ||
| 58 | // Enable ADC | ||
| 59 | r.cs().write(|w| w.set_en(true)); | ||
| 60 | // Wait for ADC ready | ||
| 61 | while !r.cs().read().ready() {} | ||
| 62 | } | ||
| 63 | |||
| 64 | // Setup IRQ | ||
| 65 | irq.disable(); | ||
| 66 | irq.set_handler(|_| unsafe { | ||
| 67 | let r = Self::regs(); | ||
| 68 | r.inte().modify(|w| w.set_fifo(false)); | ||
| 69 | WAKER.wake(); | ||
| 70 | }); | ||
| 71 | irq.unpend(); | ||
| 72 | irq.enable(); | ||
| 73 | |||
| 74 | Self { phantom: PhantomData } | ||
| 75 | } | ||
| 76 | |||
| 77 | async fn wait_for_ready() { | ||
| 78 | let r = Self::regs(); | ||
| 79 | unsafe { | ||
| 80 | r.inte().modify(|w| w.set_fifo(true)); | ||
| 81 | compiler_fence(Ordering::SeqCst); | ||
| 82 | poll_fn(|cx| { | ||
| 83 | WAKER.register(cx.waker()); | ||
| 84 | if r.cs().read().ready() { | ||
| 85 | return Poll::Ready(()); | ||
| 86 | } | ||
| 87 | Poll::Pending | ||
| 88 | }) | ||
| 89 | .await; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | pub async fn read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { | ||
| 94 | let r = Self::regs(); | ||
| 95 | unsafe { | ||
| 96 | r.cs().modify(|w| { | ||
| 97 | w.set_ainsel(PIN::channel()); | ||
| 98 | w.set_start_once(true) | ||
| 99 | }); | ||
| 100 | Self::wait_for_ready().await; | ||
| 101 | r.result().read().result().into() | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | pub async fn read_temperature(&mut self) -> u16 { | ||
| 106 | let r = Self::regs(); | ||
| 107 | unsafe { | ||
| 108 | r.cs().modify(|w| w.set_ts_en(true)); | ||
| 109 | if !r.cs().read().ready() { | ||
| 110 | Self::wait_for_ready().await; | ||
| 111 | } | ||
| 112 | r.cs().modify(|w| { | ||
| 113 | w.set_ainsel(4); | ||
| 114 | w.set_start_once(true) | ||
| 115 | }); | ||
| 116 | Self::wait_for_ready().await; | ||
| 117 | r.result().read().result().into() | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { | ||
| 122 | let r = Self::regs(); | ||
| 123 | let ch = PIN::channel(); | ||
| 124 | unsafe { | ||
| 125 | if ch == 4 { | ||
| 126 | r.cs().modify(|w| w.set_ts_en(true)) | ||
| 127 | } | ||
| 128 | while !r.cs().read().ready() {} | ||
| 129 | r.cs().modify(|w| { | ||
| 130 | w.set_ainsel(ch); | ||
| 131 | w.set_start_once(true) | ||
| 132 | }); | ||
| 133 | while !r.cs().read().ready() {} | ||
| 134 | r.result().read().result().into() | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | pub fn blocking_read_temperature(&mut self) -> u16 { | ||
| 139 | let r = Self::regs(); | ||
| 140 | unsafe { | ||
| 141 | r.cs().modify(|w| w.set_ts_en(true)); | ||
| 142 | while !r.cs().read().ready() {} | ||
| 143 | r.cs().modify(|w| { | ||
| 144 | w.set_ainsel(4); | ||
| 145 | w.set_start_once(true) | ||
| 146 | }); | ||
| 147 | while !r.cs().read().ready() {} | ||
| 148 | r.result().read().result().into() | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | macro_rules! impl_pin { | ||
| 154 | ($pin:ident, $channel:expr) => { | ||
| 155 | impl Channel<Adc<'static>> for peripherals::$pin { | ||
| 156 | type ID = u8; | ||
| 157 | fn channel() -> u8 { | ||
| 158 | $channel | ||
| 159 | } | ||
| 160 | } | ||
| 161 | }; | ||
| 162 | } | ||
| 163 | |||
| 164 | impl_pin!(PIN_26, 0); | ||
| 165 | impl_pin!(PIN_27, 1); | ||
| 166 | impl_pin!(PIN_28, 2); | ||
| 167 | impl_pin!(PIN_29, 3); | ||
| 168 | |||
| 169 | impl<WORD, PIN> OneShot<Adc<'static>, WORD, PIN> for Adc<'static> | ||
| 170 | where | ||
| 171 | WORD: From<u16>, | ||
| 172 | PIN: Channel<Adc<'static>, ID = u8>, | ||
| 173 | { | ||
| 174 | type Error = (); | ||
| 175 | fn read(&mut self, pin: &mut PIN) -> nb::Result<WORD, Self::Error> { | ||
| 176 | Ok(self.blocking_read(pin).into()) | ||
| 177 | } | ||
| 178 | } | ||
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index f608f1768..6c91b1adc 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -6,6 +6,7 @@ pub(crate) mod fmt; | |||
| 6 | 6 | ||
| 7 | mod intrinsics; | 7 | mod intrinsics; |
| 8 | 8 | ||
| 9 | pub mod adc; | ||
| 9 | pub mod dma; | 10 | pub mod dma; |
| 10 | pub mod gpio; | 11 | pub mod gpio; |
| 11 | pub mod i2c; | 12 | pub mod i2c; |
| @@ -98,6 +99,8 @@ embassy_hal_common::peripherals! { | |||
| 98 | RTC, | 99 | RTC, |
| 99 | 100 | ||
| 100 | FLASH, | 101 | FLASH, |
| 102 | |||
| 103 | ADC, | ||
| 101 | } | 104 | } |
| 102 | 105 | ||
| 103 | #[link_section = ".boot2"] | 106 | #[link_section = ".boot2"] |
diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs new file mode 100644 index 000000000..2a9e93732 --- /dev/null +++ b/examples/rp/src/bin/adc.rs | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::adc::{Adc, Config}; | ||
| 8 | use embassy_rp::interrupt; | ||
| 9 | use embassy_time::{Duration, Timer}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let p = embassy_rp::init(Default::default()); | ||
| 15 | let irq = interrupt::take!(ADC_IRQ_FIFO); | ||
| 16 | let mut adc = Adc::new(p.ADC, irq, Config::default()); | ||
| 17 | |||
| 18 | let mut p26 = p.PIN_26; | ||
| 19 | let mut p27 = p.PIN_27; | ||
| 20 | let mut p28 = p.PIN_28; | ||
| 21 | |||
| 22 | loop { | ||
| 23 | let level = adc.read(&mut p26).await; | ||
| 24 | info!("Pin 26 ADC: {}", level); | ||
| 25 | let level = adc.read(&mut p27).await; | ||
| 26 | info!("Pin 27 ADC: {}", level); | ||
| 27 | let level = adc.read(&mut p28).await; | ||
| 28 | info!("Pin 28 ADC: {}", level); | ||
| 29 | let temp = adc.read_temperature().await; | ||
| 30 | info!("Temp: {}", temp); | ||
| 31 | Timer::after(Duration::from_secs(1)).await; | ||
| 32 | } | ||
| 33 | } | ||
