aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrik Alsér <[email protected]>2022-11-15 16:12:07 +0100
committerHenrik Alsér <[email protected]>2022-11-15 16:12:07 +0100
commiteb149a0bd42d7690e78e5f2b37579c1f68be613b (patch)
treef6735a981123d6f8fd478a604db481d836e84ae5
parentd05979c7085675c33615700f6590b1543ed69323 (diff)
embassy-rp: Add basic ADC module
-rw-r--r--embassy-rp/src/adc.rs178
-rw-r--r--embassy-rp/src/lib.rs3
-rw-r--r--examples/rp/src/bin/adc.rs33
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 @@
1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll;
5
6use embassy_hal_common::into_ref;
7use embassy_sync::waitqueue::AtomicWaker;
8use embedded_hal_02::adc::{Channel, OneShot};
9
10use crate::interrupt::{self, InterruptExt};
11use crate::peripherals::ADC;
12use crate::{pac, peripherals, Peripheral};
13static WAKER: AtomicWaker = AtomicWaker::new();
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17#[non_exhaustive]
18pub enum Error {
19 // No errors for now
20}
21
22#[non_exhaustive]
23pub struct Config {}
24
25impl Default for Config {
26 fn default() -> Self {
27 Self {}
28 }
29}
30pub struct Adc<'d> {
31 phantom: PhantomData<&'d ADC>,
32}
33
34impl<'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
153macro_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
164impl_pin!(PIN_26, 0);
165impl_pin!(PIN_27, 1);
166impl_pin!(PIN_28, 2);
167impl_pin!(PIN_29, 3);
168
169impl<WORD, PIN> OneShot<Adc<'static>, WORD, PIN> for Adc<'static>
170where
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
7mod intrinsics; 7mod intrinsics;
8 8
9pub mod adc;
9pub mod dma; 10pub mod dma;
10pub mod gpio; 11pub mod gpio;
11pub mod i2c; 12pub 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
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::adc::{Adc, Config};
8use embassy_rp::interrupt;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async 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}