use crate::iomuxc::adc::{prepare, Pin};
use crate::ral;
#[cfg(feature = "eh02-unproven")]
use eh02::adc::{Channel, OneShot};
#[allow(non_camel_case_types)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum ClockSelect {
IPG,
IPG_2,
#[default]
ADACK,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum ClockDivision {
Div1,
#[default]
Div2,
Div4,
Div8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConversionSpeed {
Slow,
Medium,
Fast,
VeryFast,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AveragingCount {
Avg1,
Avg4,
Avg8,
Avg16,
Avg32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResolutionBits {
Res8,
Res10,
Res12,
}
pub struct AnalogInput<P, const N: u8> {
pin: P,
}
#[cfg(feature = "eh02-unproven")]
impl<P, const N: u8> Channel<Adc<N>> for AnalogInput<P, N>
where
P: Pin<N>,
{
type ID = u16;
fn channel() -> Self::ID {
<P as Pin<N>>::INPUT as u16
}
}
impl<P, const N: u8> AnalogInput<P, N>
where
P: Pin<N>,
{
pub fn new(mut pin: P) -> Self {
prepare(&mut pin);
Self { pin }
}
pub fn release(self) -> P {
self.pin
}
}
pub struct Adc<const N: u8> {
reg: ral::adc::Instance<N>,
}
impl<const N: u8> Adc<N> {
pub fn new(reg: ral::adc::Instance<N>, clock: ClockSelect, division: ClockDivision) -> Self {
ral::modify_reg!(ral::adc, reg, GC, ADACKEN: match clock {
ClockSelect::ADACK => ADACKEN_1,
_ => ADACKEN_0
});
ral::modify_reg!(ral::adc, reg, CFG,
ADICLK: match clock {
ClockSelect::IPG => ADICLK_0,
ClockSelect::IPG_2 => ADICLK_1,
ClockSelect::ADACK => ADICLK_3
},
ADIV: match division {
ClockDivision::Div1 => ADIV_0,
ClockDivision::Div2 => ADIV_1,
ClockDivision::Div4 => ADIV_2,
ClockDivision::Div8 => ADIV_3
},
ADHSC: ADHSC_1
);
let mut inst = Self { reg };
inst.set_resolution(ResolutionBits::Res10);
inst.set_low_power_mode(false);
inst.set_averaging(AveragingCount::Avg32);
inst.set_conversion_speed(ConversionSpeed::Slow);
inst.calibrate();
inst.set_averaging(AveragingCount::Avg4);
inst.set_conversion_speed(ConversionSpeed::Medium);
inst
}
pub fn set_resolution(&mut self, bits: ResolutionBits) {
ral::modify_reg!(ral::adc, self.reg, CFG, MODE: match bits {
ResolutionBits::Res8 => MODE_0,
ResolutionBits::Res10 => MODE_1,
ResolutionBits::Res12 => MODE_2
});
}
pub fn set_averaging(&mut self, avg: AveragingCount) {
ral::modify_reg!(ral::adc, self.reg, GC, AVGE: match avg {
AveragingCount::Avg1 => AVGE_0,
_ => AVGE_1
});
ral::modify_reg!(ral::adc, self.reg, CFG, AVGS: match avg {
AveragingCount::Avg32 => AVGS_3,
AveragingCount::Avg16 => AVGS_2,
AveragingCount::Avg8 => AVGS_1,
_ => AVGS_0,
});
}
pub fn set_conversion_speed(&mut self, conversion_speed: ConversionSpeed) {
ral::modify_reg!(ral::adc, self.reg, CFG,
ADSTS: match conversion_speed {
ConversionSpeed::Slow => ADSTS_3,
ConversionSpeed::Medium => ADSTS_1,
ConversionSpeed::Fast => ADSTS_3,
ConversionSpeed::VeryFast => ADSTS_0
},
ADLSMP: match conversion_speed {
ConversionSpeed::Slow => ADLSMP_1,
ConversionSpeed::Medium => ADLSMP_1,
ConversionSpeed::Fast => ADLSMP_0,
ConversionSpeed::VeryFast => ADLSMP_0
}
);
}
pub fn set_low_power_mode(&mut self, state: bool) {
ral::modify_reg!(ral::adc, self.reg, CFG, ADLPC: if state { ADLPC_1 } else { ADLPC_0 });
}
pub fn calibrate(&mut self) {
ral::modify_reg!(ral::adc, self.reg, GC, CAL: 0b1);
while (ral::read_reg!(ral::adc, self.reg, CAL, CAL_CODE) != 0) {}
}
pub fn read_blocking<P>(&mut self, _: &mut AnalogInput<P, N>) -> u16
where
P: Pin<N>,
{
self.read_blocking_channel(P::INPUT)
}
pub fn read_blocking_channel(&mut self, channel: u32) -> u16 {
assert!(channel < 16);
ral::modify_reg!(ral::adc, self.reg, HC0, |_| channel);
while (ral::read_reg!(ral::adc, self.reg, HS, COCO0) == 0) {}
ral::read_reg!(ral::adc, self.reg, R0) as u16
}
pub fn release(self) -> ral::adc::Instance<N> {
self.reg
}
}
#[cfg(feature = "eh02-unproven")]
impl<W, P, const N: u8> OneShot<Adc<N>, W, AnalogInput<P, N>> for Adc<N>
where
W: From<u16>,
P: Pin<N>,
{
type Error = core::convert::Infallible;
fn read(&mut self, _pin: &mut AnalogInput<P, N>) -> nb::Result<W, Self::Error> {
Ok(Adc::<N>::read_blocking(self, _pin).into())
}
}
pub struct DmaSource<P, const N: u8> {
adc: Adc<N>,
channel: u32,
_pin: P,
}
impl<P, const N: u8> DmaSource<AnalogInput<P, N>, N>
where
P: Pin<N>,
{
pub fn new(adc: Adc<N>, pin: AnalogInput<P, N>) -> Self {
Self {
adc,
_pin: pin,
channel: P::INPUT,
}
}
}
impl<const N: u8> DmaSource<(), N> {
pub fn without_pin(adc: Adc<N>, channel: u32) -> Self {
Self {
adc,
_pin: (),
channel,
}
}
}
impl<P, const N: u8> DmaSource<P, N> {
pub fn r0(&self) -> *const ral::RORegister<u32> {
core::ptr::addr_of!(self.adc.reg.R0)
}
pub fn enable_dma(&mut self) {
ral::modify_reg!(ral::adc, self.adc.reg, GC, ADCO: 1, DMAEN: 1);
ral::modify_reg!(ral::adc, self.adc.reg, HC0, |_| self.channel);
}
pub fn disable_dma(&mut self) {
ral::modify_reg!(ral::adc, self.adc.reg, GC, ADCO: 0, DMAEN: 0);
}
}
#[cfg(doctest)]
struct Adc1Pin2Mismatch;
#[cfg(doctest)]
struct Adc2Pin2;
#[cfg(doctest)]
struct Adc2Pin1Mismatch;