use core::future::poll_fn; use core::marker::PhantomData; use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::sealed::Pin as GpioPin; use crate::gpio::{self, AnyPin, Pull}; use crate::interrupt::typelevel::Binding; use crate::interrupt::InterruptExt; use crate::peripherals::{ADC, ADC_TEMP_SENSOR}; use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt}; static WAKER: AtomicWaker = AtomicWaker::new(); #[non_exhaustive] pub struct Config {} impl Default for Config { fn default() -> Self { Self {} } } enum Source<'p> { Pin(PeripheralRef<'p, AnyPin>), TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>), } pub struct Channel<'p>(Source<'p>); impl<'p> Channel<'p> { pub fn new_pin(pin: impl Peripheral
+ 'p, pull: Pull) -> Self { into_ref!(pin); pin.pad_ctrl().modify(|w| { // manual says: // // > When using an ADC input shared with a GPIO pin, the pin’s // > digital functions must be disabled by setting IE low and OD // > high in the pin’s pad control register w.set_ie(false); w.set_od(true); w.set_pue(pull == Pull::Up); w.set_pde(pull == Pull::Down); }); Self(Source::Pin(pin.map_into())) } pub fn new_temp_sensor(s: impl Peripheral
+ 'p) -> Self {
let r = pac::ADC;
r.cs().write_set(|w| w.set_ts_en(true));
Self(Source::TempSensor(s.into_ref()))
}
fn channel(&self) -> u8 {
match &self.0 {
// this requires adc pins to be sequential and matching the adc channels,
// which is the case for rp2040
Source::Pin(p) => p._pin() - 26,
Source::TempSensor(_) => 4,
}
}
}
impl<'p> Drop for Source<'p> {
fn drop(&mut self) {
match self {
Source::Pin(p) => {
p.pad_ctrl().modify(|w| {
w.set_ie(true);
w.set_od(false);
w.set_pue(false);
w.set_pde(true);
});
}
Source::TempSensor(_) => {
pac::ADC.cs().write_clear(|w| w.set_ts_en(true));
}
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(transparent)]
pub struct Sample(u16);
impl Sample {
pub fn good(&self) -> bool {
self.0 < 0x8000
}
pub fn value(&self) -> u16 {
self.0 & !0x8000
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
ConversionFailed,
}
pub trait Mode {}
pub struct Async;
impl Mode for Async {}
pub struct Blocking;
impl Mode for Blocking {}
pub struct Adc<'d, M: Mode> {
phantom: PhantomData<(&'d ADC, M)>,
}
impl<'d, M: Mode> Drop for Adc<'d, M> {
fn drop(&mut self) {
let r = Self::regs();
// disable ADC. leaving it enabled comes with a ~150µA static
// current draw. the temperature sensor has already been disabled
// by the temperature-reading methods, so we don't need to touch that.
r.cs().write(|w| w.set_en(false));
}
}
impl<'d, M: Mode> Adc<'d, M> {
#[inline]
fn regs() -> pac::adc::Adc {
pac::ADC
}
#[inline]
fn reset() -> pac::resets::regs::Peripherals {
let mut ret = pac::resets::regs::Peripherals::default();
ret.set_adc(true);
ret
}
fn setup() {
let reset = Self::reset();
crate::reset::reset(reset);
crate::reset::unreset_wait(reset);
let r = Self::regs();
// Enable ADC
r.cs().write(|w| w.set_en(true));
// Wait for ADC ready
while !r.cs().read().ready() {}
}
pub fn blocking_read(&mut self, ch: &mut Channel) -> Result + 'd,
_irq: impl Binding ,
) -> Result<(), Error> {
let r = Self::regs();
// clear previous errors and set channel
r.cs().modify(|w| {
w.set_ainsel(ch.channel());
w.set_err_sticky(true); // clear previous errors
w.set_start_many(false);
});
// wait for previous conversions and drain fifo. an earlier batch read may have
// been cancelled, leaving the adc running.
while !r.cs().read().ready() {}
while !r.fcs().read().empty() {
r.fifo().read();
}
// set up fifo for dma
r.fcs().write(|w| {
w.set_thresh(1);
w.set_dreq_en(true);
w.set_shift(mem::size_of:: ,
) -> Result<(), Error> {
self.read_many_inner(ch, buf, false, div, dma).await
}
#[inline]
pub async fn read_many_raw(
&mut self,
ch: &mut Channel<'_>,
buf: &mut [Sample],
div: u16,
dma: impl Peripheral ,
) {
// errors are reported in individual samples
let _ = self
.read_many_inner(ch, unsafe { mem::transmute::<_, &mut [u16]>(buf) }, true, div, dma)
.await;
}
}
impl<'d> Adc<'d, Blocking> {
pub fn new_blocking(_inner: impl Peripheral + 'd, _config: Config) -> Self {
Self::setup();
Self { phantom: PhantomData }
}
}
pub struct InterruptHandler {
_empty: (),
}
impl interrupt::typelevel::Handler