use core::marker::PhantomData;
use crate::gpio::{Analog, Pin};
use crate::pac;
use crate::rcu::Rcu;
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Hysteresis {
None = 0b00,
Low = 0b01,
Medium = 0b10,
High = 0b11,
}
pub trait InvertingInput {
const MSEL: u8;
}
pub struct VrefintQuarter;
pub struct VrefintHalf;
pub struct VrefintThreeQuarters;
pub struct Vrefint;
impl InvertingInput for VrefintQuarter {
const MSEL: u8 = 0b000;
}
impl InvertingInput for VrefintHalf {
const MSEL: u8 = 0b001;
}
impl InvertingInput for VrefintThreeQuarters {
const MSEL: u8 = 0b010;
}
impl InvertingInput for Vrefint {
const MSEL: u8 = 0b011;
}
impl InvertingInput for Pin<'A', 4, Analog> {
const MSEL: u8 = 0b100;
}
impl InvertingInput for Pin<'A', 5, Analog> {
const MSEL: u8 = 0b101;
}
impl InvertingInput for Pin<'A', 0, Analog> {
const MSEL: u8 = 0b110;
}
impl InvertingInput for Pin<'A', 2, Analog> {
const MSEL: u8 = 0b111;
}
pub trait NonInvertingInput {
const SW: bool;
}
impl NonInvertingInput for Pin<'A', 1, Analog> {
const SW: bool = false;
}
impl NonInvertingInput for (Pin<'A', 1, Analog>, Pin<'A', 4, Analog>) {
const SW: bool = true;
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum OutputSel {
None = 0b000,
Timer0Break = 0b001,
Timer0Ch0 = 0b010,
Timer0OcpreClr = 0b011,
Timer2Ch0 = 0b110,
Timer2OcpreClr = 0b111,
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Speed {
High = 0b00,
Medium = 0b01,
Low = 0b10,
VeryLow = 0b11,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Polarity {
NotInverted = 0,
Inverted = 1,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[must_use]
pub struct CmpConfig {
speed: Speed,
hysteresis: Hysteresis,
output_sel: OutputSel,
polarity: Polarity,
}
impl CmpConfig {
pub const fn new(speed: Speed) -> Self {
Self {
speed,
hysteresis: Hysteresis::None,
output_sel: OutputSel::None,
polarity: Polarity::NotInverted,
}
}
pub const fn hysteresis(mut self, hysteresis: Hysteresis) -> Self {
self.hysteresis = hysteresis;
self
}
pub const fn output_sel(mut self, output_sel: OutputSel) -> Self {
self.output_sel = output_sel;
self
}
pub const fn polarity(mut self, polarity: Polarity) -> Self {
self.polarity = polarity;
self
}
}
pub struct Unlocked;
pub struct Locked;
pub struct Cmp<POS, INV> {
cmp: pac::Cmp,
pos: POS,
inv: INV,
}
pub struct CmpRunning<POS, INV, LOCKED = Unlocked> {
cmp: pac::Cmp,
pos: POS,
inv: INV,
_locked: PhantomData<LOCKED>,
}
impl<POS: NonInvertingInput, INV: InvertingInput> Cmp<POS, INV> {
pub fn new(rcu: &mut Rcu, cmp: pac::Cmp, pos: POS, inv: INV, config: CmpConfig) -> Self {
rcu.enable_cfgcmp();
let mut cmp = Self { cmp, pos, inv };
cmp.apply_config(config);
cmp
}
pub fn release(self) -> (pac::Cmp, POS, INV) {
(self.cmp, self.pos, self.inv)
}
fn apply_config(&mut self, config: CmpConfig) {
self.cmp.cs().modify(|_, w| {
let w = w.cmphst().bits(config.hysteresis as u8);
let w = w.cmposel().bits(config.output_sel as u8);
let w = w.cmpm().bits(config.speed as u8);
let w = w.cmppl().bit(config.polarity == Polarity::Inverted);
let w = unsafe { w.cmpmsel().bits(INV::MSEL) };
w.cmpsw().bit(POS::SW)
});
}
pub fn enable(self) -> CmpRunning<POS, INV, Unlocked> {
self.cmp.cs().modify(|_, w| w.cmpen().set_bit());
CmpRunning {
cmp: self.cmp,
pos: self.pos,
inv: self.inv,
_locked: PhantomData,
}
}
}
impl<POS, INV> CmpRunning<POS, INV, Unlocked> {
pub fn disable(self) -> Cmp<POS, INV> {
self.cmp.cs().modify(|_, w| w.cmpen().clear_bit());
Cmp {
cmp: self.cmp,
pos: self.pos,
inv: self.inv,
}
}
pub fn lock(self) -> CmpRunning<POS, INV, Locked> {
self.cmp.cs().modify(|_, w| w.cmplk().set_bit());
CmpRunning {
cmp: self.cmp,
pos: self.pos,
inv: self.inv,
_locked: PhantomData,
}
}
}
impl<POS, INV, LOCKED> CmpRunning<POS, INV, LOCKED> {
pub fn output(&self) -> bool {
self.cmp.cs().read().cmpo().bit_is_set()
}
}