use crate::gpio::{Analog, Pin, P1, P2, P3, P4};
use crate::pac;
use crate::ref_a::Ref;
use crate::tlv::AdcCal;
pub use crate::adc_seq::{SeqMember, SequenceError, MAX_SEQUENCE};
use crate::adc_seq;
#[derive(Clone, Copy, PartialEq, Eq)]
enum Internal {
None,
SupplyHalf,
Temperature,
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum RefSel {
Avcc,
VRef,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Resolution {
Bits8,
Bits10,
Bits12,
}
impl Resolution {
pub const fn max(self) -> u16 {
match self {
Resolution::Bits8 => 255,
Resolution::Bits10 => 1023,
Resolution::Bits12 => 4095,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ClockSource {
ModOsc,
Aclk,
Mclk,
Smclk,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum SampleTime {
Cycles4,
Cycles8,
Cycles16,
Cycles32,
Cycles64,
Cycles128,
Cycles256,
}
impl SampleTime {
const fn code(self) -> u8 {
match self {
SampleTime::Cycles4 => 0,
SampleTime::Cycles8 => 1,
SampleTime::Cycles16 => 2,
SampleTime::Cycles32 => 3,
SampleTime::Cycles64 => 4,
SampleTime::Cycles128 => 6,
SampleTime::Cycles256 => 8,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Config {
resolution: Resolution,
clock: ClockSource,
sample_time: SampleTime,
}
impl Default for Config {
fn default() -> Self {
Config {
resolution: Resolution::Bits12,
clock: ClockSource::ModOsc,
sample_time: SampleTime::Cycles32,
}
}
}
impl Config {
pub fn new() -> Self {
Self::default()
}
pub fn resolution(mut self, resolution: Resolution) -> Self {
self.resolution = resolution;
self
}
pub fn clock(mut self, clock: ClockSource) -> Self {
self.clock = clock;
self
}
pub fn sample_time(mut self, sample_time: SampleTime) -> Self {
self.sample_time = sample_time;
self
}
}
pub struct Adc {
adc: pac::Adc12,
resolution: Resolution,
}
impl Adc {
pub fn new(adc: pac::Adc12, config: Config) -> Self {
adc.adc12ctl0().modify(|_, w| w.adc12enc().clear_bit());
adc.adc12ctl0().write(|w| {
w.adc12sht0().set(config.sample_time.code());
w.adc12on().set_bit()
});
adc.adc12ctl1().write(|w| {
w.adc12shp().set_bit();
w.adc12conseq().adc12conseq_0();
match config.clock {
ClockSource::ModOsc => w.adc12ssel().adc12ssel_0(),
ClockSource::Aclk => w.adc12ssel().adc12ssel_1(),
ClockSource::Mclk => w.adc12ssel().adc12ssel_2(),
ClockSource::Smclk => w.adc12ssel().adc12ssel_3(),
}
});
adc.adc12ctl2().write(|w| match config.resolution {
Resolution::Bits8 => w.adc12res().adc12res_0(),
Resolution::Bits10 => w.adc12res().adc12res_1(),
Resolution::Bits12 => w.adc12res().adc12res_2(),
});
Adc {
adc,
resolution: config.resolution,
}
}
pub fn read<P: AdcPin>(&mut self, _pin: &mut P) -> u16 {
self.read_channel(P::CHANNEL)
}
pub fn read_vref<P: AdcPin>(&mut self, _pin: &mut P, vref: &Ref) -> u16 {
let _ = vref;
self.convert(P::CHANNEL, Internal::None, RefSel::VRef)
}
pub fn read_channel(&mut self, channel: u8) -> u16 {
self.convert(channel, Internal::None, RefSel::Avcc)
}
pub fn read_supply_half(&mut self) -> u16 {
self.convert(31, Internal::SupplyHalf, RefSel::Avcc)
}
pub fn read_supply_millivolts(&mut self, vref: &Ref) -> u32 {
let counts = self.read_supply_raw_inner();
self.to_millivolts(counts, vref) * 2
}
pub fn read_supply_raw(&mut self, vref: &Ref) -> u16 {
let _ = vref;
self.read_supply_raw_inner()
}
fn read_supply_raw_inner(&mut self) -> u16 {
self.convert(31, Internal::SupplyHalf, RefSel::VRef)
}
pub fn read_temperature_raw(&mut self) -> u16 {
self.convert(30, Internal::Temperature, RefSel::Avcc)
}
pub fn read_temperature(&mut self, vref: &Ref) -> u16 {
let _ = vref;
self.convert(30, Internal::Temperature, RefSel::VRef)
}
pub fn read_temperature_deci_celsius(&mut self, vref: &Ref, cal: &AdcCal) -> Option<i16> {
let raw = self.read_temperature(vref);
cal.temp_deci_celsius(vref.voltage(), raw)
}
pub fn to_millivolts(&self, counts: u16, vref: &Ref) -> u32 {
crate::adc_cal::counts_to_millivolts(counts, self.resolution.max(), vref.millivolts())
}
fn convert(&mut self, channel: u8, internal: Internal, refsel: RefSel) -> u16 {
self.arm(channel, internal, refsel);
while self.adc.adc12ctl1().read().adc12busy().bit_is_set() {}
self.adc.adc12mem0().read().bits()
}
fn arm(&mut self, channel: u8, internal: Internal, refsel: RefSel) {
self.program(channel, internal, refsel);
self.adc
.adc12ctl0()
.modify(|_, w| w.adc12enc().set_bit().adc12sc().set_bit());
}
fn program(&mut self, channel: u8, internal: Internal, refsel: RefSel) {
self.adc.adc12ctl0().modify(|_, w| w.adc12enc().clear_bit());
self.adc.adc12ctl3().write(|w| match internal {
Internal::None => w.adc12batmap().clear_bit().adc12tcmap().clear_bit(),
Internal::SupplyHalf => w.adc12batmap().set_bit().adc12tcmap().clear_bit(),
Internal::Temperature => w.adc12batmap().clear_bit().adc12tcmap().set_bit(),
});
self.adc.adc12mctl0().write(|w| {
match refsel {
RefSel::Avcc => w.adc12vrsel().adc12vrsel_0(), RefSel::VRef => w.adc12vrsel().adc12vrsel_1(), };
w.adc12eos().set_bit();
w.adc12inch().set(channel)
});
}
pub fn enable_conversion_interrupt(&mut self) {
self.adc.adc12ier0().modify(|_, w| w.adc12ie0().set_bit());
}
pub fn disable_conversion_interrupt(&mut self) {
self.adc.adc12ier0().modify(|_, w| w.adc12ie0().clear_bit());
}
pub fn start_conversion<P: AdcPin>(&mut self, _pin: &mut P) {
self.arm(P::CHANNEL, Internal::None, RefSel::Avcc);
}
pub fn start_channel(&mut self, channel: u8) {
self.arm(channel, Internal::None, RefSel::Avcc);
}
pub fn start_supply_half(&mut self) {
self.arm(31, Internal::SupplyHalf, RefSel::Avcc);
}
pub fn free(self) -> pac::Adc12 {
self.adc.adc12ctl0().modify(|_, w| w.adc12enc().clear_bit());
self.adc.adc12ctl0().modify(|_, w| w.adc12on().clear_bit());
self.adc
}
}
#[cfg(feature = "critical-section")]
impl Adc {
pub fn read_repeated_dma<P: AdcPin, const N: u8>(
&mut self,
_pin: &mut P,
ch: &mut crate::dma::Channel<N>,
buf: &mut [u16],
) {
self.read_repeated_dma_inner(ch, P::CHANNEL, Internal::None, RefSel::Avcc, buf);
}
pub fn read_supply_half_repeated_dma<const N: u8>(
&mut self,
ch: &mut crate::dma::Channel<N>,
buf: &mut [u16],
) {
self.read_repeated_dma_inner(ch, 31, Internal::SupplyHalf, RefSel::Avcc, buf);
}
pub fn read_temperature_repeated_dma<const N: u8>(
&mut self,
vref: &Ref,
ch: &mut crate::dma::Channel<N>,
buf: &mut [u16],
) {
let _ = vref;
self.read_repeated_dma_inner(ch, 30, Internal::Temperature, RefSel::VRef, buf);
}
fn read_repeated_dma_inner<const N: u8>(
&mut self,
ch: &mut crate::dma::Channel<N>,
channel: u8,
internal: Internal,
refsel: RefSel,
buf: &mut [u16],
) {
if buf.is_empty() {
return;
}
self.program(channel, internal, refsel);
self.adc
.adc12ctl1()
.modify(|_, w| w.adc12conseq().adc12conseq_2());
self.adc.adc12ctl0().modify(|_, w| w.adc12msc().set_bit());
let mut scratch = 0u16;
unsafe {
ch.consume_stale_trigger_word(
crate::dma::TriggerSource::Adc12,
self.adc.adc12mem0().as_ptr() as *const u16,
&mut scratch,
);
}
unsafe {
ch.arm_single_words(
crate::dma::TriggerSource::Adc12,
self.adc.adc12mem0().as_ptr() as *const u16,
crate::dma::AddrMode::Fixed,
buf.as_mut_ptr(),
crate::dma::AddrMode::Increment,
buf.len() as u16,
);
}
self.adc
.adc12ctl0()
.modify(|_, w| w.adc12enc().set_bit().adc12sc().set_bit());
ch.wait_done();
self.adc.adc12ctl0().modify(|_, w| w.adc12enc().clear_bit());
while self.adc.adc12ctl1().read().adc12busy().bit_is_set() {}
self.adc.adc12ctl0().modify(|_, w| w.adc12msc().clear_bit());
self.adc
.adc12ctl1()
.modify(|_, w| w.adc12conseq().adc12conseq_0());
let _ = self.adc.adc12mem0().read().bits();
}
}
impl Adc {
pub fn read_sequence(
&mut self,
members: &[SeqMember],
results: &mut [u16],
) -> Result<(), SequenceError> {
adc_seq::validate(members, results.len(), false)?;
self.read_sequence_inner(members, results);
Ok(())
}
pub fn read_sequence_vref(
&mut self,
members: &[SeqMember],
vref: &Ref,
results: &mut [u16],
) -> Result<(), SequenceError> {
let _ = vref;
adc_seq::validate(members, results.len(), true)?;
self.read_sequence_inner(members, results);
Ok(())
}
fn read_sequence_inner(&mut self, members: &[SeqMember], results: &mut [u16]) {
let n = members.len();
self.program_sequence(members);
self.drain_mems(n);
self.adc
.adc12ctl0()
.modify(|_, w| w.adc12enc().set_bit().adc12sc().set_bit());
let last_ifg = 1u16 << (n - 1);
while self.adc.adc12ifgr0().read().bits() & last_ifg == 0 {}
let mem0 = self.adc.adc12mem0().as_ptr() as *const u16;
for (i, slot) in results[..n].iter_mut().enumerate() {
*slot = unsafe { mem0.add(i).read_volatile() };
}
self.restore_single_conversion();
}
fn program_sequence(&mut self, members: &[SeqMember]) {
self.adc.adc12ctl0().modify(|_, w| w.adc12enc().clear_bit());
let (batmap, tcmap) = adc_seq::map_bits(members);
self.adc.adc12ctl3().write(|w| {
w.adc12batmap().bit(batmap);
w.adc12tcmap().bit(tcmap)
});
let mut words = [0u16; adc_seq::MAX_SEQUENCE];
adc_seq::encode_mctl(members, &mut words);
let mctl0 = self.adc.adc12mctl0().as_ptr();
for (i, &word) in words[..members.len()].iter().enumerate() {
unsafe { mctl0.add(i).write_volatile(word) };
}
self.adc
.adc12ctl1()
.modify(|_, w| w.adc12conseq().adc12conseq_1());
self.adc.adc12ctl0().modify(|_, w| w.adc12msc().set_bit());
}
fn drain_mems(&mut self, n: usize) {
let mem0 = self.adc.adc12mem0().as_ptr() as *const u16;
for i in 0..n {
let _ = unsafe { mem0.add(i).read_volatile() };
}
}
fn restore_single_conversion(&mut self) {
self.adc.adc12ctl0().modify(|_, w| w.adc12enc().clear_bit());
while self.adc.adc12ctl1().read().adc12busy().bit_is_set() {}
self.adc.adc12ctl0().modify(|_, w| w.adc12msc().clear_bit());
self.adc
.adc12ctl1()
.modify(|_, w| w.adc12conseq().adc12conseq_0());
}
}
#[cfg(feature = "critical-section")]
impl Adc {
const SEQ_DMA_SPIN_LIMIT: u32 = 100_000;
pub fn read_sequence_dma<const N: u8>(
&mut self,
members: &[SeqMember],
ch: &mut crate::dma::Channel<N>,
results: &mut [u16],
) -> Result<(), SequenceError> {
adc_seq::validate(members, results.len(), false)?;
self.read_sequence_dma_inner(members, ch, results)
}
pub fn read_sequence_dma_vref<const N: u8>(
&mut self,
members: &[SeqMember],
vref: &Ref,
ch: &mut crate::dma::Channel<N>,
results: &mut [u16],
) -> Result<(), SequenceError> {
let _ = vref;
adc_seq::validate(members, results.len(), true)?;
self.read_sequence_dma_inner(members, ch, results)
}
fn read_sequence_dma_inner<const N: u8>(
&mut self,
members: &[SeqMember],
ch: &mut crate::dma::Channel<N>,
results: &mut [u16],
) -> Result<(), SequenceError> {
let n = members.len();
self.program_sequence(members);
let mut scratch = 0u16;
unsafe {
ch.consume_stale_trigger_word(
crate::dma::TriggerSource::Adc12,
self.adc.adc12mem0().as_ptr() as *const u16,
&mut scratch,
);
}
self.drain_mems(n);
unsafe {
ch.arm_single_words(
crate::dma::TriggerSource::Adc12,
self.adc.adc12mem0().as_ptr() as *const u16,
crate::dma::AddrMode::Increment,
results.as_mut_ptr(),
crate::dma::AddrMode::Increment,
n as u16,
);
}
self.adc
.adc12ctl0()
.modify(|_, w| w.adc12enc().set_bit().adc12sc().set_bit());
let done = ch.wait_done_bounded(Self::SEQ_DMA_SPIN_LIMIT);
self.restore_single_conversion();
if !done {
self.drain_mems(n);
return Err(SequenceError::DmaIncomplete);
}
Ok(())
}
}
impl SeqMember {
pub fn pin<P: AdcPin>(_pin: &P) -> SeqMember {
SeqMember::channel(P::CHANNEL)
}
pub fn pin_vref<P: AdcPin>(_pin: &P) -> SeqMember {
SeqMember::channel_vref(P::CHANNEL)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Window {
low: u16,
high: u16,
}
impl Window {
pub fn new(low: u16, high: u16) -> Option<Window> {
if low > high {
return None;
}
Some(Window { low, high })
}
pub fn low(&self) -> u16 {
self.low
}
pub fn high(&self) -> u16 {
self.high
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum WindowVerdict {
Below,
Within,
Above,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct WindowFlags {
pub above: bool,
pub within: bool,
pub below: bool,
}
impl WindowFlags {
pub fn none(&self) -> bool {
!(self.above || self.within || self.below)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub struct WindowEvents {
pub above: bool,
pub within: bool,
pub below: bool,
}
impl WindowEvents {
pub fn outside() -> WindowEvents {
WindowEvents {
above: true,
within: false,
below: true,
}
}
}
impl Adc {
pub fn read_windowed<P: AdcPin>(
&mut self,
_pin: &mut P,
window: &Window,
) -> (u16, WindowVerdict) {
self.read_windowed_inner(P::CHANNEL, Internal::None, RefSel::Avcc, window)
}
pub fn read_supply_half_windowed(&mut self, window: &Window) -> (u16, WindowVerdict) {
self.read_windowed_inner(31, Internal::SupplyHalf, RefSel::Avcc, window)
}
fn read_windowed_inner(
&mut self,
channel: u8,
internal: Internal,
refsel: RefSel,
window: &Window,
) -> (u16, WindowVerdict) {
self.arm_windowed(channel, internal, refsel, window);
while self.adc.adc12ctl1().read().adc12busy().bit_is_set() {}
let counts = self.adc.adc12mem0().read().bits();
(counts, self.window_verdict())
}
pub fn start_supply_half_windowed(&mut self, window: &Window) {
self.arm_windowed(31, Internal::SupplyHalf, RefSel::Avcc, window);
}
fn arm_windowed(&mut self, channel: u8, internal: Internal, refsel: RefSel, window: &Window) {
self.clear_window_flags_owned();
self.program(channel, internal, refsel);
self.program_window(window);
self.adc
.adc12ctl0()
.modify(|_, w| w.adc12enc().set_bit().adc12sc().set_bit());
}
fn program_window(&mut self, window: &Window) {
self.adc.adc12hi().write(|w| unsafe { w.bits(window.high) });
self.adc.adc12lo().write(|w| unsafe { w.bits(window.low) });
self.adc.adc12mctl0().modify(|_, w| w.adc12winc().set_bit());
}
fn window_verdict(&self) -> WindowVerdict {
let r = self.adc.adc12ifgr2().read();
if r.adc12hiifg().bit_is_set() {
WindowVerdict::Above
} else if r.adc12loifg().bit_is_set() {
WindowVerdict::Below
} else {
WindowVerdict::Within
}
}
pub fn enable_window_interrupts(&mut self, events: WindowEvents) {
self.adc.adc12ier2().modify(|_, w| {
w.adc12hiie().bit(events.above);
w.adc12inie().bit(events.within);
w.adc12loie().bit(events.below)
});
}
pub fn disable_window_interrupts(&mut self) {
self.enable_window_interrupts(WindowEvents::default());
}
pub fn start_monitor<P: AdcPin>(&mut self, _pin: &mut P, window: &Window, events: WindowEvents) {
self.start_monitor_inner(P::CHANNEL, Internal::None, window, events);
}
pub fn start_supply_half_monitor(&mut self, window: &Window, events: WindowEvents) {
self.start_monitor_inner(31, Internal::SupplyHalf, window, events);
}
fn start_monitor_inner(
&mut self,
channel: u8,
internal: Internal,
window: &Window,
events: WindowEvents,
) {
self.clear_window_flags_owned();
self.program(channel, internal, RefSel::Avcc);
self.program_window(window);
self.adc
.adc12ctl1()
.modify(|_, w| w.adc12conseq().adc12conseq_2());
self.adc.adc12ctl0().modify(|_, w| w.adc12msc().set_bit());
self.enable_window_interrupts(events);
self.adc
.adc12ctl0()
.modify(|_, w| w.adc12enc().set_bit().adc12sc().set_bit());
}
pub fn stop_monitor(&mut self) {
self.disable_window_interrupts();
self.adc.adc12ctl0().modify(|_, w| w.adc12enc().clear_bit());
while self.adc.adc12ctl1().read().adc12busy().bit_is_set() {}
self.adc.adc12ctl0().modify(|_, w| w.adc12msc().clear_bit());
self.adc
.adc12ctl1()
.modify(|_, w| w.adc12conseq().adc12conseq_0());
let _ = self.adc.adc12mem0().read().bits();
self.clear_window_flags_owned();
}
fn clear_window_flags_owned(&mut self) {
self.adc.adc12ifgr2().modify(|_, w| {
w.adc12hiifg().clear_bit();
w.adc12inifg().clear_bit();
w.adc12loifg().clear_bit()
});
}
}
pub const IV_WINDOW_ABOVE: u16 = 0x06;
pub const IV_WINDOW_BELOW: u16 = 0x08;
pub const IV_WINDOW_WITHIN: u16 = 0x0A;
pub const IV_CONVERSION: u16 = 0x0C;
pub fn read_iv() -> u16 {
let adc = unsafe { pac::Adc12::steal() };
adc.adc12iv().read().bits()
}
pub fn window_flags() -> WindowFlags {
let adc = unsafe { pac::Adc12::steal() };
let r = adc.adc12ifgr2().read();
WindowFlags {
above: r.adc12hiifg().bit_is_set(),
within: r.adc12inifg().bit_is_set(),
below: r.adc12loifg().bit_is_set(),
}
}
pub fn clear_window_flags() {
let adc = unsafe { pac::Adc12::steal() };
adc.adc12ifgr2().modify(|_, w| {
w.adc12hiifg().clear_bit();
w.adc12inifg().clear_bit();
w.adc12loifg().clear_bit()
});
}
pub fn isr_disable_window_interrupts() {
let adc = unsafe { pac::Adc12::steal() };
adc.adc12ier2().modify(|_, w| {
w.adc12hiie().clear_bit();
w.adc12inie().clear_bit();
w.adc12loie().clear_bit()
});
}
pub fn read_result() -> u16 {
let adc = unsafe { pac::Adc12::steal() };
adc.adc12mem0().read().bits()
}
pub fn conversion_pending() -> bool {
let adc = unsafe { pac::Adc12::steal() };
adc.adc12ifgr0().read().adc12ifg0().bit_is_set()
}
mod sealed {
pub trait Sealed {}
}
pub trait AdcPin: sealed::Sealed {
const CHANNEL: u8;
}
macro_rules! adc_pins {
($($Port:ident $N:literal => $ch:literal),+ $(,)?) => {$(
impl sealed::Sealed for Pin<$Port, $N, Analog> {}
impl AdcPin for Pin<$Port, $N, Analog> {
const CHANNEL: u8 = $ch;
}
)+};
}
adc_pins! {
P1 0 => 0, P1 1 => 1, P1 2 => 2, P1 3 => 3,
P1 4 => 4, P1 5 => 5, P2 3 => 6, P2 4 => 7,
P4 0 => 8, P4 1 => 9, P4 2 => 10, P4 3 => 11,
P3 0 => 12, P3 1 => 13, P3 2 => 14, P3 3 => 15,
}