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.
This commit is contained in:
parent
54d31c98fe
commit
b166ed6b78
@ -10,8 +10,8 @@ use crate::gpio::sealed::Pin as GpioPin;
|
|||||||
use crate::gpio::{self, AnyPin, Pull};
|
use crate::gpio::{self, AnyPin, Pull};
|
||||||
use crate::interrupt::typelevel::Binding;
|
use crate::interrupt::typelevel::Binding;
|
||||||
use crate::interrupt::InterruptExt;
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::peripherals::ADC;
|
use crate::peripherals::{ADC, ADC_TEMP_SENSOR};
|
||||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
|
||||||
|
|
||||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
|
|
||||||
@ -24,12 +24,15 @@ impl Default for Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pin<'p> {
|
enum Source<'p> {
|
||||||
pin: PeripheralRef<'p, AnyPin>,
|
Pin(PeripheralRef<'p, AnyPin>),
|
||||||
|
TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p> Pin<'p> {
|
pub struct Channel<'p>(Source<'p>);
|
||||||
pub fn new(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self {
|
|
||||||
|
impl<'p> Channel<'p> {
|
||||||
|
pub fn new_pin(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
pin.pad_ctrl().modify(|w| {
|
pin.pad_ctrl().modify(|w| {
|
||||||
// manual says:
|
// manual says:
|
||||||
@ -42,24 +45,40 @@ impl<'p> Pin<'p> {
|
|||||||
w.set_pue(pull == Pull::Up);
|
w.set_pue(pull == Pull::Up);
|
||||||
w.set_pde(pull == Pull::Down);
|
w.set_pde(pull == Pull::Down);
|
||||||
});
|
});
|
||||||
Self { pin: pin.map_into() }
|
Self(Source::Pin(pin.map_into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_sensor(s: impl Peripheral<P = ADC_TEMP_SENSOR> + '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 {
|
fn channel(&self) -> u8 {
|
||||||
// this requires adc pins to be sequential and matching the adc channels,
|
match &self.0 {
|
||||||
// which is the case for rp2040
|
// this requires adc pins to be sequential and matching the adc channels,
|
||||||
self.pin._pin() - 26
|
// which is the case for rp2040
|
||||||
|
Source::Pin(p) => p._pin() - 26,
|
||||||
|
Source::TempSensor(_) => 4,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> Drop for Pin<'d> {
|
impl<'p> Drop for Source<'p> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.pin.pad_ctrl().modify(|w| {
|
match self {
|
||||||
w.set_ie(true);
|
Source::Pin(p) => {
|
||||||
w.set_od(false);
|
p.pad_ctrl().modify(|w| {
|
||||||
w.set_pue(false);
|
w.set_ie(true);
|
||||||
w.set_pde(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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,10 +134,10 @@ impl<'d, M: Mode> Adc<'d, M> {
|
|||||||
while !r.cs().read().ready() {}
|
while !r.cs().read().ready() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sample_blocking(channel: u8) -> Result<u16, Error> {
|
pub fn blocking_read(&mut self, ch: &mut Channel) -> Result<u16, Error> {
|
||||||
let r = Self::regs();
|
let r = Self::regs();
|
||||||
r.cs().modify(|w| {
|
r.cs().modify(|w| {
|
||||||
w.set_ainsel(channel);
|
w.set_ainsel(ch.channel());
|
||||||
w.set_start_once(true);
|
w.set_start_once(true);
|
||||||
w.set_err(true);
|
w.set_err(true);
|
||||||
});
|
});
|
||||||
@ -128,19 +147,6 @@ impl<'d, M: Mode> Adc<'d, M> {
|
|||||||
false => Ok(r.result().read().result().into()),
|
false => Ok(r.result().read().result().into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_read(&mut self, pin: &mut Pin) -> Result<u16, Error> {
|
|
||||||
Self::sample_blocking(pin.channel())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blocking_read_temperature(&mut self) -> Result<u16, Error> {
|
|
||||||
let r = Self::regs();
|
|
||||||
r.cs().modify(|w| w.set_ts_en(true));
|
|
||||||
while !r.cs().read().ready() {}
|
|
||||||
let result = Self::sample_blocking(4);
|
|
||||||
r.cs().modify(|w| w.set_ts_en(false));
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> Adc<'d, Async> {
|
impl<'d> Adc<'d, Async> {
|
||||||
@ -172,10 +178,10 @@ impl<'d> Adc<'d, Async> {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn sample_async(channel: u8) -> Result<u16, Error> {
|
pub async fn read(&mut self, ch: &mut Channel<'_>) -> Result<u16, Error> {
|
||||||
let r = Self::regs();
|
let r = Self::regs();
|
||||||
r.cs().modify(|w| {
|
r.cs().modify(|w| {
|
||||||
w.set_ainsel(channel);
|
w.set_ainsel(ch.channel());
|
||||||
w.set_start_once(true);
|
w.set_start_once(true);
|
||||||
w.set_err(true);
|
w.set_err(true);
|
||||||
});
|
});
|
||||||
@ -185,21 +191,6 @@ impl<'d> Adc<'d, Async> {
|
|||||||
false => Ok(r.result().read().result().into()),
|
false => Ok(r.result().read().result().into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read(&mut self, pin: &mut Pin<'_>) -> Result<u16, Error> {
|
|
||||||
Self::sample_async(pin.channel()).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn read_temperature(&mut self) -> Result<u16, Error> {
|
|
||||||
let r = Self::regs();
|
|
||||||
r.cs().modify(|w| w.set_ts_en(true));
|
|
||||||
if !r.cs().read().ready() {
|
|
||||||
Self::wait_for_ready().await;
|
|
||||||
}
|
|
||||||
let result = Self::sample_async(4).await;
|
|
||||||
r.cs().modify(|w| w.set_ts_en(false));
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> Adc<'d, Blocking> {
|
impl<'d> Adc<'d, Blocking> {
|
||||||
@ -230,14 +221,17 @@ pub trait AdcChannel: sealed::AdcChannel {}
|
|||||||
pub trait AdcPin: AdcChannel + gpio::Pin {}
|
pub trait AdcPin: AdcChannel + gpio::Pin {}
|
||||||
|
|
||||||
macro_rules! impl_pin {
|
macro_rules! impl_pin {
|
||||||
($pin:ident) => {
|
($pin:ident, $channel:expr) => {
|
||||||
impl sealed::AdcChannel for peripherals::$pin {}
|
impl sealed::AdcChannel for peripherals::$pin {}
|
||||||
impl AdcChannel for peripherals::$pin {}
|
impl AdcChannel for peripherals::$pin {}
|
||||||
impl AdcPin for peripherals::$pin {}
|
impl AdcPin for peripherals::$pin {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_pin!(PIN_26);
|
impl_pin!(PIN_26, 0);
|
||||||
impl_pin!(PIN_27);
|
impl_pin!(PIN_27, 1);
|
||||||
impl_pin!(PIN_28);
|
impl_pin!(PIN_28, 2);
|
||||||
impl_pin!(PIN_29);
|
impl_pin!(PIN_29, 3);
|
||||||
|
|
||||||
|
impl sealed::AdcChannel for peripherals::ADC_TEMP_SENSOR {}
|
||||||
|
impl AdcChannel for peripherals::ADC_TEMP_SENSOR {}
|
||||||
|
@ -183,6 +183,7 @@ embassy_hal_internal::peripherals! {
|
|||||||
FLASH,
|
FLASH,
|
||||||
|
|
||||||
ADC,
|
ADC,
|
||||||
|
ADC_TEMP_SENSOR,
|
||||||
|
|
||||||
CORE1,
|
CORE1,
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin};
|
use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
|
||||||
use embassy_rp::bind_interrupts;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::gpio::Pull;
|
use embassy_rp::gpio::Pull;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
@ -22,9 +22,10 @@ async fn main(_spawner: Spawner) {
|
|||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
let mut adc = Adc::new(p.ADC, Irqs, Config::default());
|
let mut adc = Adc::new(p.ADC, Irqs, Config::default());
|
||||||
|
|
||||||
let mut p26 = Pin::new(p.PIN_26, Pull::None);
|
let mut p26 = Channel::new_pin(p.PIN_26, Pull::None);
|
||||||
let mut p27 = Pin::new(p.PIN_27, Pull::None);
|
let mut p27 = Channel::new_pin(p.PIN_27, Pull::None);
|
||||||
let mut p28 = Pin::new(p.PIN_28, Pull::None);
|
let mut p28 = Channel::new_pin(p.PIN_28, Pull::None);
|
||||||
|
let mut ts = Channel::new_sensor(p.ADC_TEMP_SENSOR);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let level = adc.read(&mut p26).await.unwrap();
|
let level = adc.read(&mut p26).await.unwrap();
|
||||||
@ -33,7 +34,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
info!("Pin 27 ADC: {}", level);
|
info!("Pin 27 ADC: {}", level);
|
||||||
let level = adc.read(&mut p28).await.unwrap();
|
let level = adc.read(&mut p28).await.unwrap();
|
||||||
info!("Pin 28 ADC: {}", level);
|
info!("Pin 28 ADC: {}", level);
|
||||||
let temp = adc.read_temperature().await.unwrap();
|
let temp = adc.read(&mut ts).await.unwrap();
|
||||||
info!("Temp: {} degrees", convert_to_celsius(temp));
|
info!("Temp: {} degrees", convert_to_celsius(temp));
|
||||||
Timer::after(Duration::from_secs(1)).await;
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ mod common;
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin};
|
use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
|
||||||
use embassy_rp::bind_interrupts;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::gpio::Pull;
|
use embassy_rp::gpio::Pull;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
@ -22,12 +22,12 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let mut p = Pin::new(&mut p.PIN_26, Pull::Down);
|
let mut p = Channel::new_pin(&mut p.PIN_26, Pull::Down);
|
||||||
defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
|
defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
|
||||||
defmt::assert!(adc.read(&mut p).await.unwrap() < 0b01_0000_0000);
|
defmt::assert!(adc.read(&mut p).await.unwrap() < 0b01_0000_0000);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut p = Pin::new(&mut p.PIN_26, Pull::Up);
|
let mut p = Channel::new_pin(&mut p.PIN_26, Pull::Up);
|
||||||
defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
|
defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
|
||||||
defmt::assert!(adc.read(&mut p).await.unwrap() > 0b11_0000_0000);
|
defmt::assert!(adc.read(&mut p).await.unwrap() > 0b11_0000_0000);
|
||||||
}
|
}
|
||||||
@ -35,21 +35,21 @@ async fn main(_spawner: Spawner) {
|
|||||||
// not bothering with async reads from now on
|
// not bothering with async reads from now on
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let mut p = Pin::new(&mut p.PIN_27, Pull::Down);
|
let mut p = Channel::new_pin(&mut p.PIN_27, Pull::Down);
|
||||||
defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
|
defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut p = Pin::new(&mut p.PIN_27, Pull::Up);
|
let mut p = Channel::new_pin(&mut p.PIN_27, Pull::Up);
|
||||||
defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
|
defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let mut p = Pin::new(&mut p.PIN_28, Pull::Down);
|
let mut p = Channel::new_pin(&mut p.PIN_28, Pull::Down);
|
||||||
defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
|
defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut p = Pin::new(&mut p.PIN_28, Pull::Up);
|
let mut p = Channel::new_pin(&mut p.PIN_28, Pull::Up);
|
||||||
defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
|
defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,22 +57,22 @@ async fn main(_spawner: Spawner) {
|
|||||||
// gp29 is connected to vsys through a 200k/100k divider,
|
// gp29 is connected to vsys through a 200k/100k divider,
|
||||||
// adding pulls should change the value
|
// adding pulls should change the value
|
||||||
let low = {
|
let low = {
|
||||||
let mut p = Pin::new(&mut p.PIN_29, Pull::Down);
|
let mut p = Channel::new_pin(&mut p.PIN_29, Pull::Down);
|
||||||
adc.blocking_read(&mut p).unwrap()
|
adc.blocking_read(&mut p).unwrap()
|
||||||
};
|
};
|
||||||
let none = {
|
let none = {
|
||||||
let mut p = Pin::new(&mut p.PIN_29, Pull::None);
|
let mut p = Channel::new_pin(&mut p.PIN_29, Pull::None);
|
||||||
adc.blocking_read(&mut p).unwrap()
|
adc.blocking_read(&mut p).unwrap()
|
||||||
};
|
};
|
||||||
let up = {
|
let up = {
|
||||||
let mut p = Pin::new(&mut p.PIN_29, Pull::Up);
|
let mut p = Channel::new_pin(&mut p.PIN_29, Pull::Up);
|
||||||
adc.blocking_read(&mut p).unwrap()
|
adc.blocking_read(&mut p).unwrap()
|
||||||
};
|
};
|
||||||
defmt::assert!(low < none);
|
defmt::assert!(low < none);
|
||||||
defmt::assert!(none < up);
|
defmt::assert!(none < up);
|
||||||
}
|
}
|
||||||
|
|
||||||
let temp = convert_to_celsius(adc.read_temperature().await.unwrap());
|
let temp = convert_to_celsius(adc.read(&mut Channel::new_sensor(p.ADC_TEMP_SENSOR)).await.unwrap());
|
||||||
defmt::assert!(temp > 0.0);
|
defmt::assert!(temp > 0.0);
|
||||||
defmt::assert!(temp < 60.0);
|
defmt::assert!(temp < 60.0);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user