embassy-rp: Add basic ADC module
This commit is contained in:
		
							parent
							
								
									d05979c708
								
							
						
					
					
						commit
						eb149a0bd4
					
				
							
								
								
									
										178
									
								
								embassy-rp/src/adc.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								embassy-rp/src/adc.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					use core::future::poll_fn;
 | 
				
			||||||
 | 
					use core::marker::PhantomData;
 | 
				
			||||||
 | 
					use core::sync::atomic::{compiler_fence, Ordering};
 | 
				
			||||||
 | 
					use core::task::Poll;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use embassy_hal_common::into_ref;
 | 
				
			||||||
 | 
					use embassy_sync::waitqueue::AtomicWaker;
 | 
				
			||||||
 | 
					use embedded_hal_02::adc::{Channel, OneShot};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::interrupt::{self, InterruptExt};
 | 
				
			||||||
 | 
					use crate::peripherals::ADC;
 | 
				
			||||||
 | 
					use crate::{pac, peripherals, Peripheral};
 | 
				
			||||||
 | 
					static WAKER: AtomicWaker = AtomicWaker::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
				
			||||||
 | 
					#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
				
			||||||
 | 
					#[non_exhaustive]
 | 
				
			||||||
 | 
					pub enum Error {
 | 
				
			||||||
 | 
					    // No errors for now
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[non_exhaustive]
 | 
				
			||||||
 | 
					pub struct Config {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for Config {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self {}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					pub struct Adc<'d> {
 | 
				
			||||||
 | 
					    phantom: PhantomData<&'d ADC>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'d> Adc<'d> {
 | 
				
			||||||
 | 
					    #[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
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn new(
 | 
				
			||||||
 | 
					        _inner: impl Peripheral<P = ADC> + 'd,
 | 
				
			||||||
 | 
					        irq: impl Peripheral<P = interrupt::ADC_IRQ_FIFO> + 'd,
 | 
				
			||||||
 | 
					        _config: Config,
 | 
				
			||||||
 | 
					    ) -> Self {
 | 
				
			||||||
 | 
					        into_ref!(irq);
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            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() {}
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Setup IRQ
 | 
				
			||||||
 | 
					        irq.disable();
 | 
				
			||||||
 | 
					        irq.set_handler(|_| unsafe {
 | 
				
			||||||
 | 
					            let r = Self::regs();
 | 
				
			||||||
 | 
					            r.inte().modify(|w| w.set_fifo(false));
 | 
				
			||||||
 | 
					            WAKER.wake();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        irq.unpend();
 | 
				
			||||||
 | 
					        irq.enable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Self { phantom: PhantomData }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn wait_for_ready() {
 | 
				
			||||||
 | 
					        let r = Self::regs();
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            r.inte().modify(|w| w.set_fifo(true));
 | 
				
			||||||
 | 
					            compiler_fence(Ordering::SeqCst);
 | 
				
			||||||
 | 
					            poll_fn(|cx| {
 | 
				
			||||||
 | 
					                WAKER.register(cx.waker());
 | 
				
			||||||
 | 
					                if r.cs().read().ready() {
 | 
				
			||||||
 | 
					                    return Poll::Ready(());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Poll::Pending
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 {
 | 
				
			||||||
 | 
					        let r = Self::regs();
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            r.cs().modify(|w| {
 | 
				
			||||||
 | 
					                w.set_ainsel(PIN::channel());
 | 
				
			||||||
 | 
					                w.set_start_once(true)
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            Self::wait_for_ready().await;
 | 
				
			||||||
 | 
					            r.result().read().result().into()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn read_temperature(&mut self) -> u16 {
 | 
				
			||||||
 | 
					        let r = Self::regs();
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            r.cs().modify(|w| w.set_ts_en(true));
 | 
				
			||||||
 | 
					            if !r.cs().read().ready() {
 | 
				
			||||||
 | 
					                Self::wait_for_ready().await;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            r.cs().modify(|w| {
 | 
				
			||||||
 | 
					                w.set_ainsel(4);
 | 
				
			||||||
 | 
					                w.set_start_once(true)
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            Self::wait_for_ready().await;
 | 
				
			||||||
 | 
					            r.result().read().result().into()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 {
 | 
				
			||||||
 | 
					        let r = Self::regs();
 | 
				
			||||||
 | 
					        let ch = PIN::channel();
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            if ch == 4 {
 | 
				
			||||||
 | 
					                r.cs().modify(|w| w.set_ts_en(true))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            while !r.cs().read().ready() {}
 | 
				
			||||||
 | 
					            r.cs().modify(|w| {
 | 
				
			||||||
 | 
					                w.set_ainsel(ch);
 | 
				
			||||||
 | 
					                w.set_start_once(true)
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            while !r.cs().read().ready() {}
 | 
				
			||||||
 | 
					            r.result().read().result().into()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn blocking_read_temperature(&mut self) -> u16 {
 | 
				
			||||||
 | 
					        let r = Self::regs();
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            r.cs().modify(|w| w.set_ts_en(true));
 | 
				
			||||||
 | 
					            while !r.cs().read().ready() {}
 | 
				
			||||||
 | 
					            r.cs().modify(|w| {
 | 
				
			||||||
 | 
					                w.set_ainsel(4);
 | 
				
			||||||
 | 
					                w.set_start_once(true)
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            while !r.cs().read().ready() {}
 | 
				
			||||||
 | 
					            r.result().read().result().into()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! impl_pin {
 | 
				
			||||||
 | 
					    ($pin:ident, $channel:expr) => {
 | 
				
			||||||
 | 
					        impl Channel<Adc<'static>> for peripherals::$pin {
 | 
				
			||||||
 | 
					            type ID = u8;
 | 
				
			||||||
 | 
					            fn channel() -> u8 {
 | 
				
			||||||
 | 
					                $channel
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl_pin!(PIN_26, 0);
 | 
				
			||||||
 | 
					impl_pin!(PIN_27, 1);
 | 
				
			||||||
 | 
					impl_pin!(PIN_28, 2);
 | 
				
			||||||
 | 
					impl_pin!(PIN_29, 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<WORD, PIN> OneShot<Adc<'static>, WORD, PIN> for Adc<'static>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    WORD: From<u16>,
 | 
				
			||||||
 | 
					    PIN: Channel<Adc<'static>, ID = u8>,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type Error = ();
 | 
				
			||||||
 | 
					    fn read(&mut self, pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
 | 
				
			||||||
 | 
					        Ok(self.blocking_read(pin).into())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -6,6 +6,7 @@ pub(crate) mod fmt;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
mod intrinsics;
 | 
					mod intrinsics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod adc;
 | 
				
			||||||
pub mod dma;
 | 
					pub mod dma;
 | 
				
			||||||
pub mod gpio;
 | 
					pub mod gpio;
 | 
				
			||||||
pub mod i2c;
 | 
					pub mod i2c;
 | 
				
			||||||
@ -98,6 +99,8 @@ embassy_hal_common::peripherals! {
 | 
				
			|||||||
    RTC,
 | 
					    RTC,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FLASH,
 | 
					    FLASH,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ADC,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[link_section = ".boot2"]
 | 
					#[link_section = ".boot2"]
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										33
									
								
								examples/rp/src/bin/adc.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								examples/rp/src/bin/adc.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![no_main]
 | 
				
			||||||
 | 
					#![feature(type_alias_impl_trait)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use defmt::*;
 | 
				
			||||||
 | 
					use embassy_executor::Spawner;
 | 
				
			||||||
 | 
					use embassy_rp::adc::{Adc, Config};
 | 
				
			||||||
 | 
					use embassy_rp::interrupt;
 | 
				
			||||||
 | 
					use embassy_time::{Duration, Timer};
 | 
				
			||||||
 | 
					use {defmt_rtt as _, panic_probe as _};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[embassy_executor::main]
 | 
				
			||||||
 | 
					async fn main(_spawner: Spawner) {
 | 
				
			||||||
 | 
					    let p = embassy_rp::init(Default::default());
 | 
				
			||||||
 | 
					    let irq = interrupt::take!(ADC_IRQ_FIFO);
 | 
				
			||||||
 | 
					    let mut adc = Adc::new(p.ADC, irq, Config::default());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut p26 = p.PIN_26;
 | 
				
			||||||
 | 
					    let mut p27 = p.PIN_27;
 | 
				
			||||||
 | 
					    let mut p28 = p.PIN_28;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        let level = adc.read(&mut p26).await;
 | 
				
			||||||
 | 
					        info!("Pin 26 ADC: {}", level);
 | 
				
			||||||
 | 
					        let level = adc.read(&mut p27).await;
 | 
				
			||||||
 | 
					        info!("Pin 27 ADC: {}", level);
 | 
				
			||||||
 | 
					        let level = adc.read(&mut p28).await;
 | 
				
			||||||
 | 
					        info!("Pin 28 ADC: {}", level);
 | 
				
			||||||
 | 
					        let temp = adc.read_temperature().await;
 | 
				
			||||||
 | 
					        info!("Temp: {}", temp);
 | 
				
			||||||
 | 
					        Timer::after(Duration::from_secs(1)).await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user