#![macro_use]
use embassy_hal_internal::{into_ref, PeripheralRef};
use crate::pac::opamp::vals::*;
use crate::Peripheral;
#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub enum OpAmpGain {
Mul1,
Mul2,
Mul4,
Mul8,
Mul16,
}
#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub enum OpAmpSpeed {
Normal,
HighSpeed,
}
#[cfg(opamp_g4)]
impl From<OpAmpSpeed> for crate::pac::opamp::vals::Opahsm {
fn from(v: OpAmpSpeed) -> Self {
match v {
OpAmpSpeed::Normal => crate::pac::opamp::vals::Opahsm::NORMAL,
OpAmpSpeed::HighSpeed => crate::pac::opamp::vals::Opahsm::HIGH_SPEED,
}
}
}
pub struct OpAmpOutput<'d, T: Instance> {
_inner: &'d OpAmp<'d, T>,
}
#[cfg(opamp_g4)]
pub struct OpAmpInternalOutput<'d, T: Instance> {
_inner: &'d OpAmp<'d, T>,
}
pub struct OpAmp<'d, T: Instance> {
_inner: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> OpAmp<'d, T> {
pub fn new(opamp: impl Peripheral<P = T> + 'd, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self {
into_ref!(opamp);
#[cfg(opamp_g4)]
T::regs().csr().modify(|w| {
w.set_opahsm(speed.into());
});
Self { _inner: opamp }
}
pub fn buffer_ext(
&mut self,
in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>,
out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin>,
gain: OpAmpGain,
) -> OpAmpOutput<'_, T> {
into_ref!(in_pin);
into_ref!(out_pin);
in_pin.set_as_analog();
out_pin.set_as_analog();
let (vm_sel, pga_gain) = match gain {
OpAmpGain::Mul1 => (0b11, 0b00),
OpAmpGain::Mul2 => (0b10, 0b00),
OpAmpGain::Mul4 => (0b10, 0b01),
OpAmpGain::Mul8 => (0b10, 0b10),
OpAmpGain::Mul16 => (0b10, 0b11),
};
T::regs().csr().modify(|w| {
w.set_vp_sel(VpSel::from_bits(in_pin.channel()));
w.set_vm_sel(VmSel::from_bits(vm_sel));
w.set_pga_gain(PgaGain::from_bits(pga_gain));
#[cfg(opamp_g4)]
w.set_opaintoen(Opaintoen::OUTPUT_PIN);
w.set_opampen(true);
});
OpAmpOutput { _inner: self }
}
#[cfg(opamp_g4)]
pub fn buffer_dac(
&mut self,
out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin>,
) -> OpAmpOutput<'_, T> {
into_ref!(out_pin);
out_pin.set_as_analog();
T::regs().csr().modify(|w| {
use crate::pac::opamp::vals::*;
w.set_vm_sel(VmSel::OUTPUT);
w.set_vp_sel(VpSel::DAC3_CH1);
w.set_opaintoen(Opaintoen::OUTPUT_PIN);
w.set_opampen(true);
});
OpAmpOutput { _inner: self }
}
#[cfg(opamp_g4)]
pub fn buffer_int(
&mut self,
pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>,
gain: OpAmpGain,
) -> OpAmpInternalOutput<'_, T> {
into_ref!(pin);
pin.set_as_analog();
let (vm_sel, pga_gain) = match gain {
OpAmpGain::Mul1 => (0b11, 0b00),
OpAmpGain::Mul2 => (0b10, 0b00),
OpAmpGain::Mul4 => (0b10, 0b01),
OpAmpGain::Mul8 => (0b10, 0b10),
OpAmpGain::Mul16 => (0b10, 0b11),
};
T::regs().csr().modify(|w| {
use crate::pac::opamp::vals::*;
w.set_vp_sel(VpSel::from_bits(pin.channel()));
w.set_vm_sel(VmSel::from_bits(vm_sel));
w.set_pga_gain(PgaGain::from_bits(pga_gain));
w.set_opaintoen(Opaintoen::ADCCHANNEL);
w.set_opampen(true);
});
OpAmpInternalOutput { _inner: self }
}
}
impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> {
fn drop(&mut self) {
T::regs().csr().modify(|w| {
w.set_opampen(false);
});
}
}
#[cfg(opamp_g4)]
impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> {
fn drop(&mut self) {
T::regs().csr().modify(|w| {
w.set_opampen(false);
});
}
}
pub(crate) trait SealedInstance {
fn regs() -> crate::pac::opamp::Opamp;
}
pub(crate) trait SealedNonInvertingPin<T: Instance> {
fn channel(&self) -> u8;
}
pub(crate) trait SealedInvertingPin<T: Instance> {
#[allow(unused)]
fn channel(&self) -> u8;
}
pub(crate) trait SealedOutputPin<T: Instance> {}
#[allow(private_bounds)]
pub trait Instance: SealedInstance + 'static {}
#[allow(private_bounds)]
pub trait NonInvertingPin<T: Instance>: SealedNonInvertingPin<T> {}
#[allow(private_bounds)]
pub trait InvertingPin<T: Instance>: SealedInvertingPin<T> {}
#[allow(private_bounds)]
pub trait OutputPin<T: Instance>: SealedOutputPin<T> {}
macro_rules! impl_opamp_external_output {
($inst:ident, $adc:ident, $ch:expr) => {
foreach_adc!(
($adc, $common_inst:ident, $adc_clock:ident) => {
impl<'d> crate::adc::SealedAdcChannel<crate::peripherals::$adc>
for OpAmpOutput<'d, crate::peripherals::$inst>
{
fn channel(&self) -> u8 {
$ch
}
}
impl<'d> crate::adc::AdcChannel<crate::peripherals::$adc>
for OpAmpOutput<'d, crate::peripherals::$inst>
{
}
};
);
};
}
foreach_peripheral!(
(opamp, OPAMP1) => {
impl_opamp_external_output!(OPAMP1, ADC1, 3);
};
(opamp, OPAMP2) => {
impl_opamp_external_output!(OPAMP2, ADC2, 3);
};
(opamp, OPAMP3) => {
impl_opamp_external_output!(OPAMP3, ADC1, 12);
impl_opamp_external_output!(OPAMP3, ADC3, 1);
};
(opamp, OPAMP4) => {
impl_opamp_external_output!(OPAMP4, ADC1, 11);
impl_opamp_external_output!(OPAMP4, ADC4, 3);
};
(opamp, OPAMP5) => {
impl_opamp_external_output!(OPAMP5, ADC5, 1);
};
(opamp, OPAMP6) => {
impl_opamp_external_output!(OPAMP6, ADC1, 14);
impl_opamp_external_output!(OPAMP6, ADC2, 14);
};
);
#[cfg(opamp_g4)]
macro_rules! impl_opamp_internal_output {
($inst:ident, $adc:ident, $ch:expr) => {
foreach_adc!(
($adc, $common_inst:ident, $adc_clock:ident) => {
impl<'d> crate::adc::SealedAdcChannel<crate::peripherals::$adc>
for OpAmpInternalOutput<'d, crate::peripherals::$inst>
{
fn channel(&self) -> u8 {
$ch
}
}
impl<'d> crate::adc::AdcChannel<crate::peripherals::$adc>
for OpAmpInternalOutput<'d, crate::peripherals::$inst>
{
}
};
);
};
}
#[cfg(opamp_g4)]
foreach_peripheral!(
(opamp, OPAMP1) => {
impl_opamp_internal_output!(OPAMP1, ADC1, 13);
};
(opamp, OPAMP2) => {
impl_opamp_internal_output!(OPAMP2, ADC2, 16);
};
(opamp, OPAMP3) => {
impl_opamp_internal_output!(OPAMP3, ADC2, 18);
impl_opamp_internal_output!(OPAMP3, ADC3, 13);
};
(opamp, OPAMP4) => {
impl_opamp_internal_output!(OPAMP4, ADC5, 5);
};
(opamp, OPAMP5) => {
impl_opamp_internal_output!(OPAMP5, ADC5, 3);
};
(opamp, OPAMP6) => {
impl_opamp_internal_output!(OPAMP6, ADC4, 17);
impl_opamp_internal_output!(OPAMP6, ADC3, 17);
};
);
foreach_peripheral! {
(opamp, $inst:ident) => {
impl SealedInstance for crate::peripherals::$inst {
fn regs() -> crate::pac::opamp::Opamp {
crate::pac::$inst
}
}
impl Instance for crate::peripherals::$inst {
}
};
}
#[allow(unused_macros)]
macro_rules! impl_opamp_vp_pin {
($inst:ident, $pin:ident, $ch:expr) => {
impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {}
impl crate::opamp::SealedNonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {
fn channel(&self) -> u8 {
$ch
}
}
};
}
#[allow(unused_macros)]
macro_rules! impl_opamp_vout_pin {
($inst:ident, $pin:ident) => {
impl crate::opamp::OutputPin<peripherals::$inst> for crate::peripherals::$pin {}
impl crate::opamp::SealedOutputPin<peripherals::$inst> for crate::peripherals::$pin {}
};
}