use crate::iomuxc::adc::{Pin, prepare};
use crate::ral;
type AnyInstance = crate::AnyInstance<ral::adc::RegisterBlock>;
#[allow(non_camel_case_types)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum ClockSelect {
IPG,
IPG_2,
#[default]
ADACK,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum ClockDivision {
Div1,
#[default]
Div2,
Div4,
Div8,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConversionSpeed {
Slow,
Medium,
Fast,
VeryFast,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AveragingCount {
Avg1,
Avg4,
Avg8,
Avg16,
Avg32,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResolutionBits {
Res8,
Res10,
Res12,
}
pub use crate::PinPortIncompatibleError;
pub struct AnalogInput {
channel: u32,
}
impl AnalogInput {
pub fn channel(&self) -> u32 {
self.channel
}
}
pub struct Adc {
reg: AnyInstance,
}
impl Adc {
pub fn new<const N: u8>(
reg: ral::adc::Instance<N>,
clock: ClockSelect,
division: ClockDivision,
) -> Self {
let reg: AnyInstance = crate::into_any(reg);
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
}
fn instance(&self) -> u8 {
ral::adc::number(&*self.reg).unwrap()
}
pub fn input<P, const N: u8>(
&self,
mut pin: P,
) -> Result<AnalogInput, PinPortIncompatibleError<P>>
where
P: Pin<N>,
{
if self.instance() != N {
return Err(PinPortIncompatibleError(pin));
}
prepare(&mut pin);
Ok(AnalogInput { channel: P::INPUT })
}
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(&mut self, input: &mut AnalogInput) -> u16 {
self.read_blocking_channel(input.channel())
}
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 struct DmaSource {
adc: Adc,
channel: u32,
}
impl DmaSource {
pub fn new(adc: Adc, input: AnalogInput) -> Self {
Self {
adc,
channel: input.channel(),
}
}
pub fn without_pin(adc: Adc, channel: u32) -> Self {
Self { adc, channel }
}
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);
}
pub(crate) fn instance(&self) -> u8 {
self.adc.instance()
}
}