use core::marker::PhantomData;
use embedded_hal_0_2::adc::{Channel, OneShot};
use crate::{
dma,
gpio::{
bank0::{Gpio26, Gpio27, Gpio28, Gpio29},
AnyPin, DynBankId, DynPinId, Function, OutputEnableOverride, Pin, PullType, ValidFunction,
},
pac::{dma::ch::ch_ctrl_trig::TREQ_SEL_A, ADC, RESETS},
resets::SubsystemReset,
typelevel::Sealed,
};
const TEMPERATURE_SENSOR_CHANNEL: u8 = 4;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InvalidPinError;
pub struct AdcPin<P>
where
P: AnyPin,
{
pin: P,
saved_output_disable: bool,
saved_input_enable: bool,
}
impl<P> AdcPin<P>
where
P: AnyPin,
{
pub fn new(pin: P) -> Result<Self, InvalidPinError> {
let pin_id = pin.borrow().id();
if (26..=29).contains(&pin_id.num) && pin_id.bank == DynBankId::Bank0 {
let mut p = pin.into();
let (od, ie) = (p.get_output_disable(), p.get_input_enable());
p.set_output_enable_override(OutputEnableOverride::Disable);
p.set_input_enable(false);
Ok(Self {
pin: P::from(p),
saved_output_disable: od,
saved_input_enable: ie,
})
} else {
Err(InvalidPinError)
}
}
pub fn release(self) -> P {
let mut p = self.pin.into();
p.set_output_disable(self.saved_output_disable);
p.set_input_enable(self.saved_input_enable);
P::from(p)
}
pub fn channel(&self) -> u8 {
let pin_id = self.pin.borrow().id();
pin_id.num - 26
}
}
pub trait AdcChannel: Sealed {
fn channel(&self) -> u8;
}
impl<P: AnyPin> Sealed for AdcPin<P> {}
impl<P: AnyPin> AdcChannel for AdcPin<P> {
fn channel(&self) -> u8 {
self.channel()
}
}
impl Sealed for TempSense {}
impl AdcChannel for TempSense {
fn channel(&self) -> u8 {
TEMPERATURE_SENSOR_CHANNEL
}
}
macro_rules! channel {
($pin:ident, $channel:expr) => {
impl<F: Function, M: PullType> Channel<Adc> for AdcPin<Pin<$pin, F, M>>
where
$pin: crate::gpio::ValidFunction<F>,
{
type ID = u8;
fn channel() -> u8 {
$channel
}
}
};
}
channel!(Gpio26, 0);
channel!(Gpio27, 1);
channel!(Gpio28, 2);
channel!(Gpio29, 3);
impl<F: Function, M: PullType> Channel<Adc> for AdcPin<Pin<DynPinId, F, M>>
where
DynPinId: crate::gpio::ValidFunction<F>,
{
type ID = (); fn channel() {}
}
pub struct TempSense {
__private: (),
}
impl Channel<Adc> for TempSense {
type ID = u8;
fn channel() -> u8 {
TEMPERATURE_SENSOR_CHANNEL
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
ConversionFailed,
}
pub struct Adc {
device: ADC,
}
impl Adc {
pub fn new(device: ADC, resets: &mut RESETS) -> Self {
device.reset_bring_down(resets);
device.reset_bring_up(resets);
device.cs().write(|w| w.en().set_bit());
while !device.cs().read().ready().bit_is_set() {}
Self { device }
}
pub fn free(self) -> ADC {
self.device
}
pub fn read_single(&self) -> Result<u16, Error> {
let result = self.device.result().read().result().bits();
let is_err = self.device.cs().read().err().bit_is_set();
if is_err {
Err(Error::ConversionFailed)
} else {
Ok(result)
}
}
#[deprecated(
note = "This method may panic, use `take_temp_sensor()` instead.",
since = "0.9.0"
)]
pub fn enable_temp_sensor(&mut self) -> TempSense {
self.take_temp_sensor()
.expect("Temp sensor is already enabled.")
}
pub fn take_temp_sensor(&mut self) -> Option<TempSense> {
let mut disabled = false;
self.device.cs().modify(|r, w| {
disabled = r.ts_en().bit_is_clear();
w.ts_en().set_bit()
});
disabled.then_some(TempSense { __private: () })
}
pub fn disable_temp_sensor(&mut self, _: TempSense) {
self.device.cs().modify(|_, w| w.ts_en().clear_bit());
}
pub fn build_fifo(&mut self) -> AdcFifoBuilder<'_, u16> {
AdcFifoBuilder {
adc: self,
marker: PhantomData,
}
}
pub fn free_running(&mut self, pin: &dyn AdcChannel) {
self.device.cs().modify(|_, w| {
unsafe {
w.ainsel().bits(pin.channel());
}
w.start_many().set_bit();
w
});
}
pub fn stop(&mut self) {
self.device.cs().modify(|_, w| w.start_many().clear_bit());
}
fn inner_read(&mut self, chan: u8) -> Result<u16, Error> {
self.wait_ready();
self.device
.cs()
.modify(|_, w| unsafe { w.ainsel().bits(chan).start_once().set_bit() });
self.wait_ready();
self.read_single()
}
pub fn wait_ready(&self) {
while !self.is_ready_or_free_running() {
core::hint::spin_loop();
}
}
fn is_ready_or_free_running(&self) -> bool {
let cs = self.device.cs().read();
cs.ready().bit_is_set() || cs.start_many().bit_is_set()
}
pub fn is_ready(&self) -> bool {
self.device.cs().read().ready().bit_is_set()
}
pub fn read<SRC>(&mut self, pin: &mut SRC) -> Result<u16, Error>
where
SRC: AdcChannel,
{
let chan = pin.channel();
self.inner_read(chan)
}
}
impl<WORD, SRC> OneShot<Adc, WORD, SRC> for Adc
where
WORD: From<u16>,
SRC: Channel<Adc, ID = u8>,
{
type Error = Error;
fn read(&mut self, _pin: &mut SRC) -> nb::Result<WORD, Self::Error> {
let chan = SRC::channel();
Ok(self.inner_read(chan)?.into())
}
}
impl<WORD, F, M> OneShot<Adc, WORD, AdcPin<Pin<DynPinId, F, M>>> for Adc
where
WORD: From<u16>,
F: Function,
M: PullType,
DynPinId: ValidFunction<F>,
AdcPin<Pin<DynPinId, F, M>>: Channel<Adc, ID = ()>,
{
type Error = Error;
fn read(&mut self, pin: &mut AdcPin<Pin<DynPinId, F, M>>) -> nb::Result<WORD, Self::Error> {
Ok(self.inner_read(pin.channel())?.into())
}
}
pub struct AdcFifoBuilder<'a, Word> {
adc: &'a mut Adc,
marker: PhantomData<Word>,
}
impl<'a, Word> AdcFifoBuilder<'a, Word> {
pub fn clock_divider(self, int: u16, frac: u8) -> Self {
self.adc
.device
.div()
.modify(|_, w| unsafe { w.int().bits(int).frac().bits(frac) });
self
}
pub fn set_channel<P: AdcChannel>(self, pin: &mut P) -> Self {
self.adc
.device
.cs()
.modify(|_, w| unsafe { w.ainsel().bits(pin.channel()) });
self
}
pub fn round_robin<T: Into<RoundRobin>>(self, selected_channels: T) -> Self {
let RoundRobin(bits) = selected_channels.into();
self.adc
.device
.cs()
.modify(|_, w| unsafe { w.rrobin().bits(bits as u16) });
self
}
pub fn enable_interrupt(self, threshold: u8) -> Self {
self.adc.device.inte().modify(|_, w| w.fifo().set_bit());
self.adc
.device
.fcs()
.modify(|_, w| unsafe { w.thresh().bits(threshold) });
self
}
pub fn shift_8bit(self) -> AdcFifoBuilder<'a, u8> {
self.adc.device.fcs().modify(|_, w| w.shift().set_bit());
AdcFifoBuilder {
adc: self.adc,
marker: PhantomData,
}
}
pub fn enable_dma(self) -> Self {
self.adc
.device
.fcs()
.modify(|_, w| unsafe { w.dreq_en().set_bit().thresh().bits(1) });
self
}
pub fn start(self) -> AdcFifo<'a, Word> {
self.adc
.device
.fcs()
.modify(|_, w| w.en().set_bit().err().set_bit());
self.adc.device.cs().modify(|_, w| w.start_many().set_bit());
AdcFifo {
adc: self.adc,
marker: PhantomData,
}
}
pub fn start_paused(self) -> AdcFifo<'a, Word> {
self.adc
.device
.fcs()
.modify(|_, w| w.en().set_bit().err().set_bit());
self.adc
.device
.cs()
.modify(|_, w| w.start_many().clear_bit());
AdcFifo {
adc: self.adc,
marker: PhantomData,
}
}
#[deprecated(note = "Use `start_paused()` instead.", since = "0.10.0")]
pub fn prepare(self) -> AdcFifo<'a, Word> {
self.start_paused()
}
}
pub struct AdcFifo<'a, Word> {
adc: &'a mut Adc,
marker: PhantomData<Word>,
}
impl<'a, Word> AdcFifo<'a, Word> {
#[allow(clippy::len_without_is_empty)]
pub fn len(&mut self) -> u8 {
self.adc.device.fcs().read().level().bits()
}
pub fn is_over(&mut self) -> bool {
let over = self.adc.device.fcs().read().over().bit();
if over {
self.adc
.device
.fcs()
.modify(|_, w| w.over().clear_bit_by_one());
}
over
}
pub fn is_under(&mut self) -> bool {
let under = self.adc.device.fcs().read().under().bit();
if under {
self.adc
.device
.fcs()
.modify(|_, w| w.under().clear_bit_by_one());
}
under
}
pub fn read_single(&mut self) -> Result<u16, Error> {
self.adc.read_single()
}
pub fn is_paused(&mut self) -> bool {
self.adc.device.cs().read().start_many().bit_is_clear()
}
pub fn pause(&mut self) {
self.adc
.device
.cs()
.modify(|_, w| w.start_many().clear_bit());
}
pub fn resume(&mut self) {
self.adc.device.cs().modify(|_, w| w.start_many().set_bit());
}
pub fn clear(&mut self) {
while self.len() > 0 {
let _ = self.read_from_fifo();
}
}
pub fn stop(mut self) -> &'a mut Adc {
self.adc
.device
.cs()
.modify(|_, w| unsafe { w.start_many().clear_bit().rrobin().bits(0).ainsel().bits(0) });
self.adc.device.inte().modify(|_, w| w.fifo().clear_bit());
while self.adc.device.cs().read().ready().bit_is_clear() {}
self.clear();
self.adc
.device
.fcs()
.modify(|_, w| unsafe { w.en().clear_bit().thresh().bits(0).dreq_en().clear_bit() });
self.adc
.device
.div()
.modify(|_, w| unsafe { w.int().bits(0).frac().bits(0) });
self.adc
}
pub fn wait_for_interrupt(&mut self) {
while self.adc.device.intr().read().fifo().bit_is_clear() {}
}
fn read_from_fifo(&mut self) -> Result<u16, Error> {
let read = self.adc.device.fifo().read();
if read.err().bit_is_set() {
Err(Error::ConversionFailed)
} else {
Ok(read.val().bits())
}
}
pub fn dma_read_target(&self) -> DmaReadTarget<Word> {
DmaReadTarget(self.adc.device.fifo().as_ptr() as u32, PhantomData)
}
pub fn trigger(&mut self) {
self.adc.device.cs().modify(|_, w| w.start_once().set_bit());
}
pub fn is_ready(&self) -> bool {
self.adc.device.cs().read().ready().bit_is_set()
}
}
impl AdcFifo<'_, u16> {
pub fn read(&mut self) -> Result<u16, Error> {
self.read_from_fifo()
}
}
impl AdcFifo<'_, u8> {
pub fn read(&mut self) -> Result<u8, Error> {
Ok(self.read_from_fifo()? as u8)
}
}
pub struct DmaReadTarget<Word>(u32, PhantomData<Word>);
unsafe impl<Word> dma::ReadTarget for DmaReadTarget<Word> {
type ReceivedWord = Word;
fn rx_treq() -> Option<u8> {
Some(TREQ_SEL_A::ADC.into())
}
fn rx_address_count(&self) -> (u32, u32) {
(self.0, u32::MAX)
}
fn rx_increment(&self) -> bool {
false
}
}
impl<Word> dma::EndlessReadTarget for DmaReadTarget<Word> {}
pub struct RoundRobin(u8);
impl<PIN: AdcChannel> From<&PIN> for RoundRobin {
fn from(pin: &PIN) -> Self {
Self(1 << pin.channel())
}
}
impl<A, B> From<(&A, &B)> for RoundRobin
where
A: AdcChannel,
B: AdcChannel,
{
fn from(pins: (&A, &B)) -> Self {
Self((1 << pins.0.channel()) | (1 << pins.1.channel()))
}
}
impl<A, B, C> From<(&A, &B, &C)> for RoundRobin
where
A: AdcChannel,
B: AdcChannel,
C: AdcChannel,
{
fn from(pins: (&A, &B, &C)) -> Self {
Self((1 << pins.0.channel()) | (1 << pins.1.channel()) | (1 << pins.2.channel()))
}
}
impl<A, B, C, D> From<(&A, &B, &C, &D)> for RoundRobin
where
A: AdcChannel,
B: AdcChannel,
C: AdcChannel,
D: AdcChannel,
{
fn from(pins: (&A, &B, &C, &D)) -> Self {
Self(
(1 << pins.0.channel())
| (1 << pins.1.channel())
| (1 << pins.2.channel())
| (1 << pins.3.channel()),
)
}
}
impl<A, B, C, D, E> From<(&A, &B, &C, &D, &E)> for RoundRobin
where
A: AdcChannel,
B: AdcChannel,
C: AdcChannel,
D: AdcChannel,
E: AdcChannel,
{
fn from(pins: (&A, &B, &C, &D, &E)) -> Self {
Self(
(1 << pins.0.channel())
| (1 << pins.1.channel())
| (1 << pins.2.channel())
| (1 << pins.3.channel())
| (1 << pins.4.channel()),
)
}
}