use core::fmt;
use crate::gpio::{GpioPin, PinMode};
cfg_if::cfg_if! {
if #[cfg(any(feature = "l4x6", feature = "l5", all(feature = "h7", not(feature = "h7b3")), feature = "f302"))] {
use crate::pac::{DAC, RCC};
} else {
use crate::pac::{DAC1, RCC};
}
}
pub trait SingleChannelDac<Word> {
type Error;
fn try_set_value(&mut self, value: Word) -> Result<(), Self::Error>;
}
#[derive(Clone, Copy, Debug)]
pub enum Channel {
One,
Two,
}
#[derive(Clone, Copy, Debug)]
pub enum Bits {
EightR,
TwelveL,
TwelveR,
}
#[derive(Clone, Copy)]
pub enum Trigger {
Tim6,
Tim3_8,
Tim7,
Tim15,
Tim2,
Tim4,
Exti9,
Swtrig,
}
impl Trigger {
pub fn bits(&self) -> u8 {
match self {
Self::Tim6 => 0b000,
Self::Tim3_8 => 0b001,
Self::Tim7 => 0b010,
Self::Tim15 => 0b011,
Self::Tim2 => 0b100,
Self::Tim4 => 0b101,
Self::Exti9 => 0b110,
Self::Swtrig => 0b111,
}
}
}
cfg_if::cfg_if! {
if #[cfg(any(feature = "l4x6", feature = "l5", all(feature = "h7", not(feature = "h7b3")), feature = "f302"))] {
pub struct Dac {
regs: DAC,
channel: Channel,
bits: Bits,
vref: f32,
}
} else {
pub struct Dac {
regs: DAC1,
channel: Channel,
bits: Bits,
vref: f32,
}
}
}
macro_rules! make_impl {
($cr:ident, $d81:ident, $d12l1:ident, $d12r1:ident, $d82:ident, $d12l2:ident, $d12r2:ident) => {
impl Dac {
cfg_if::cfg_if! {
if #[cfg(any(feature = "l4x6", feature = "l5", all(feature = "h7", not(feature = "h7b3")), feature = "f302"))] {
pub fn new<P: GpioPin>(regs: DAC, pin: P, channel: Channel, bits: Bits, vref: f32) -> Self {
match pin.get_mode() {
PinMode::Analog => (),
_ => panic!("DAC pin must be configured as analog")
}
Self::new_unchecked(regs, channel, bits, vref)
}
pub fn new_unchecked(regs: DAC, channel: Channel, bits: Bits, vref: f32) -> Self {
Self {
regs,
channel,
bits,
vref,
}
}
} else {
pub fn new<P: GpioPin>(regs: DAC1, pin: P, channel: Channel, bits: Bits, vref: f32) -> Self {
match pin.get_mode() {
PinMode::Analog => (),
_ => panic!("DAC pin must be configured as analog")
}
Self::new_unchecked(regs, channel, bits, vref)
}
pub fn new_unchecked(regs: DAC1, channel: Channel, bits: Bits, vref: f32) -> Self {
Self {
regs,
channel,
bits,
vref,
}
}
}
}
pub fn enable(&mut self, rcc: &mut RCC) {
cfg_if::cfg_if! {
if #[cfg(feature = "f3")] {
rcc.apb1enr.modify(|_, w| w.dac1en().set_bit());
} else if #[cfg(any(feature = "l4", feature = "l5"))] {
rcc.apb1enr1.modify(|_, w| w.dac1en().set_bit());
}
}
match self.channel {
Channel::One => self.regs.$cr.modify(|_, w| w.en1().set_bit()),
Channel::Two => self.regs.$cr.modify(|_, w| w.en2().set_bit()),
}
}
pub fn disable(&mut self, rcc: &mut RCC) {
cfg_if::cfg_if! {
if #[cfg(feature = "f3")] {
rcc.apb1enr.modify(|_, w| w.dac1en().clear_bit());
} else if #[cfg(any(feature = "l4", feature = "l5"))] {
rcc.apb1enr1.modify(|_, w| w.dac1en().clear_bit());
}
}
match self.channel {
Channel::One => self.regs.$cr.modify(|_, w| w.en1().clear_bit()),
Channel::Two => self.regs.$cr.modify(|_, w| w.en2().clear_bit()),
}
}
pub fn set_value(&mut self, val: u32) {
match self.channel {
Channel::One => match self.bits {
Bits::EightR => self.regs.$d81.modify(|_, w| unsafe { w.bits(val) }),
Bits::TwelveL => self.regs.$d12l1.modify(|_, w| unsafe { w.bits(val) }),
Bits::TwelveR => self.regs.$d12r1.modify(|_, w| unsafe { w.bits(val) }),
},
Channel::Two => match self.bits {
Bits::EightR => self.regs.$d82.modify(|_, w| unsafe { w.bits(val) }),
Bits::TwelveL => self.regs.$d12l2.modify(|_, w| unsafe { w.bits(val) }),
Bits::TwelveR => self.regs.$d12r2.modify(|_, w| unsafe { w.bits(val) }),
},
}
}
pub fn set_voltage(&mut self, volts: f32) {
let val = match self.bits {
Bits::EightR => ((volts / self.vref) * 255.) as u32,
Bits::TwelveL => ((volts / self.vref) * 4_095.) as u32,
Bits::TwelveR => ((volts / self.vref) * 4_095.) as u32,
};
self.set_value(val);
}
#[cfg(not(feature = "l5"))]
pub fn set_trigger(&mut self, trigger: Trigger) {
match self.channel {
Channel::One => {
self.regs.$cr.modify(|_, w| w.ten1().set_bit());
self.regs
.$cr
.modify(|_, w| unsafe { w.tsel1().bits(trigger.bits()) });
}
Channel::Two => {
self.regs.$cr.modify(|_, w| w.ten2().set_bit());
self.regs
.$cr
.modify(|_, w| unsafe { w.tsel2().bits(trigger.bits()) });
}
}
}
#[cfg(not(feature = "l5"))]
pub fn trigger_lfsr(&mut self, trigger: Trigger, data: u32) {
match self.channel {
Channel::One => {
self.regs.$cr.modify(|_, w| unsafe { w.wave1().bits(0b01) });
self.regs.$cr.modify(|_, w| unsafe { w.mamp1().bits(0b01) });
}
Channel::Two => {
self.regs.$cr.modify(|_, w| unsafe { w.wave2().bits(0b01) });
self.regs.$cr.modify(|_, w| unsafe { w.mamp2().bits(0b01) });
}
}
self.set_trigger(trigger);
self.set_value(data);
}
#[cfg(not(feature = "l5"))]
pub fn trigger_triangle(&mut self, trigger: Trigger, data: u32) {
match self.channel {
Channel::One => {
self.regs.$cr.modify(|_, w| unsafe { w.wave1().bits(0b10) });
self.regs.$cr.modify(|_, w| unsafe { w.mamp1().bits(0b10) });
}
Channel::Two => {
self.regs.$cr.modify(|_, w| unsafe { w.wave2().bits(0b10) });
self.regs.$cr.modify(|_, w| unsafe { w.mamp2().bits(0b10) });
}
}
self.set_trigger(trigger);
self.set_value(data);
}
}
}
}
impl fmt::Debug for Dac {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Dac")
.field("channel", &self.channel)
.field("bits", &self.bits)
.field("vret", &self.vref)
.finish()
}
}
pub struct DacError {}
impl SingleChannelDac<u32> for Dac {
type Error = DacError;
fn try_set_value(&mut self, val: u32) -> Result<(), DacError> {
self.set_value(val);
Ok(())
}
}
#[cfg(feature = "l5")]
make_impl!(
dac_cr,
dac_dhr8r2,
dac_dhr12l2,
dac_dhr12r2,
dac_dhr8r2,
dac_dhr12l2,
dac_dhr12r2
);
#[cfg(not(feature = "l5"))]
make_impl!(cr, dhr8r1, dhr12l1, dhr12r1, dhr8r2, dhr12l2, dhr12r2);