use core::ops::Deref;
use core::{convert::TryInto, marker::PhantomData};
use cortex_m::asm;
use embedded_hal::adc::Channel;
#[track_caller]
unsafe fn unreachable_unchecked() -> ! {
#[cfg(debug_assertions)]
crate::unreachable!();
#[cfg(not(debug_assertions))]
#[allow(unused_unsafe)]
unsafe {
core::hint::unreachable_unchecked();
}
}
use crate::{
pac::{self, adc1, Interrupt},
rcc::{Clocks, Enable, AHB},
time::{duration::Microseconds, fixed_point::FixedPoint, rate::Hertz},
Switch,
};
use crate::pac::{adc1_2, adc1_2::ccr::CKMODE_A};
#[cfg(feature = "enumset")]
use enumset::{EnumSet, EnumSetType};
const MAX_ADVREGEN_STARTUP: Microseconds = Microseconds(10);
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(alias = "V_REFINT")]
pub struct VoltageInternalReference<ADC> {
_adc: PhantomData<ADC>,
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(alias = "V_BAT")]
pub struct VoltageBattery<ADC> {
_adc: PhantomData<ADC>,
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(alias = "V_TS")]
pub struct TemperatureSensor<ADC> {
_adc: PhantomData<ADC>,
}
#[allow(clippy::module_name_repetitions)]
pub struct CommonAdc<ADC> {
reg: ADC,
}
impl<ADC> CommonAdc<ADC>
where
ADC: CommonInstance,
{
pub fn new(mut common_adc: ADC, clocks: &Clocks, ahb: &mut AHB) -> Self {
common_adc.enable_clock(clocks, ahb);
Self { reg: common_adc }
}
pub unsafe fn peripheral(&mut self) -> &mut ADC {
&mut self.reg
}
}
impl<ADC> CommonAdc<ADC>
where
ADC: CommonInstance + crate::rcc::Enable,
{
pub fn free(self, _adcs: &<ADC as CommonInstance>::Childs) -> ADC {
critical_section::with(|_| {
unsafe { ADC::disable_unchecked() };
});
self.reg
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "enumset", derive(EnumSetType))]
#[cfg_attr(not(feature = "enumset"), derive(Copy, Clone, PartialEq, Eq))]
#[non_exhaustive]
pub enum Event {
#[doc(alias = "ADRDY")]
AdcReady,
#[doc(alias = "EOSMP")]
EndOfSamplingPhase,
#[doc(alias = "EOC")]
EndOfConversion,
#[doc(alias = "EOS")]
EndOfSequence,
#[doc(alias = "OVR")]
Overrun,
#[doc(alias = "JEOC")]
InjectedChannelEndOfConversion,
#[doc(alias = "JEOS")]
InjectedChannelEndOfSequence,
#[doc(alias = "AWD1")]
AnalogWatchdog1,
#[doc(alias = "AWD2")]
AnalogWatchdog2,
#[doc(alias = "AWD3")]
AnalogWatchdog3,
#[doc(alias = "JQOVF")]
InjectedContextQueueOverfow,
}
#[derive(Debug)]
pub struct Adc<ADC, State = Enabled> {
reg: ADC,
state: PhantomData<State>,
}
pub mod channel;
pub mod config;
macro_rules! sp_channel {
([$(($Pin:ident, $ADC:ident, $chan:expr)),+ $(,)*]) => {
$(
impl Channel<pac::$ADC> for $Pin<<pac::$ADC as Instance>::SharedInstance> {
type ID = channel::Id;
fn channel() -> Self::ID { $chan }
}
)+
};
}
macro_rules! sp_pins {
([$(($Pin:ident, $en:ident)),+ $(,)*]) => {
$(
impl<Common> $Pin<Common>
where
Common: CommonInstance,
{
/// Creating a type associated with the special ADC sensor, which
/// implements the [`embedded_hal::adc::Channel`] trait.
///
/// # Example
///
/// Imagine you'd like to measure the core temperature via `ADC1`.
///
/// In that case this function takes both the common ADC, e.g. [`pac::ADC1_2`], as
/// well as both associated ADCs, e.g. [`pac::ADC1`] & [`pac::ADC2`] to ensure,
/// that these ADCs are still disabled, because the internal ADC sensor can only be
/// enabled, if these ADCs are disabled, see [RM0316] 15.6.2.
///
/// Code example can be seen in [examples/adc.rs].
///
/// [examples/adc.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.10.0/examples/adc.rs
/// [RM0316]: https://www.st.com/resource/en/reference_manual/dm00094349.pdf
// FIXME(Sh3Rm4n): Soundness hole: Still mutliple sensor objects can be created.
#[inline]
pub fn new(
// Does this now expect CommonAdc or pac::ADC1_2?
common_adc: &mut CommonAdc<Common>,
// &mut adc ensures, that adc is disabled and with the shard instance the reference can be
// configured / enabled.
// As of RM0316 15.6.2: Software is allowed to write this bit only when the ADCs are
// disabled (ADCAL=0, JADSTART=0, ADSTART=0, ADSTP=0, ADDIS=0 and ADEN=0)
_adcs: &mut <Common as CommonInstance>::Childs,
) -> Self {
common_adc.reg.ccr.modify(|_, w| w.$en().enabled());
Self { _adc: PhantomData }
}
}
)+
};
}
sp_channel!([
(TemperatureSensor, ADC1, channel::Id::Sixteen),
(VoltageBattery, ADC1, channel::Id::Seventeen),
(VoltageInternalReference, ADC1, channel::Id::Eighteen),
]);
#[cfg(any(feature = "svd-f302", feature = "svd-f303", feature = "svd-f3x4"))]
sp_channel!([(VoltageInternalReference, ADC2, channel::Id::Eighteen),]);
#[cfg(feature = "svd-f303")]
sp_channel!([
(VoltageInternalReference, ADC3, channel::Id::Eighteen),
(VoltageInternalReference, ADC4, channel::Id::Eighteen),
]);
sp_pins!([
(TemperatureSensor, tsen),
(VoltageBattery, vbaten),
(VoltageInternalReference, vrefen),
]);
impl<ADC> Adc<ADC, Enabled>
where
ADC: Instance,
{
#[inline]
pub fn new(
adc: ADC,
config: impl Into<config::Config>,
clocks: &Clocks,
common_adc: &CommonAdc<<ADC as Instance>::SharedInstance>,
) -> Adc<ADC, Enabled> {
let mut adc = Adc::new_disabled(adc);
let config: config::Config = config.into();
adc.set_config(config);
adc.calibrate(clocks, common_adc);
adc.into_enabled()
}
#[doc(alias = "ADC_DR")]
#[must_use]
#[inline]
pub fn data_register(&self) -> u16 {
self.reg.dr.read().rdata().bits()
}
#[inline]
pub fn data_register_address(&self) -> u32 {
core::ptr::addr_of!(self.reg.dr) as u32
}
#[inline]
pub fn start_conversion(&mut self) {
self.reg.cr.modify(|_, w| w.adstart().start_conversion());
}
#[inline]
#[must_use]
pub fn into_oneshot(mut self) -> Adc<ADC, OneShot> {
self.stop_conversion();
while self.is_conversion_ongoing() {}
self.set_conversion_mode(config::ConversionMode::Single);
self.set_dma_mode(config::DmaMode::Disabled);
self.set_external_trigger(None);
self.disable_interrupt(Event::EndOfConversion);
self.disable_interrupt(Event::EndOfSequence);
self.set_sequence_length(config::Sequence::One);
Adc {
reg: self.reg,
state: PhantomData,
}
}
#[inline]
#[must_use]
pub fn into_disabled(self) -> Adc<ADC, Disabled> {
if self.reg.cr.read().aden().bit()
&& (self.reg.cr.read().adstart().bit() || self.reg.cr.read().jadstart().bit())
{
self.reg.cr.modify(|_, w| w.adstp().stop_conversion());
if !self.reg.cfgr.read().jauto().is_enabled() {
self.reg.cr.modify(|_, w| w.jadstp().stop_conversion());
}
while self.reg.cr.read().adstp().bit() || self.reg.cr.read().jadstp().bit() {}
}
if self.reg.cr.read().aden().is_enabled() {
self.reg.cr.modify(|_, w| w.addis().set_bit());
while self.reg.cr.read().aden().is_enabled() {}
}
Adc {
reg: self.reg,
state: PhantomData,
}
}
#[inline]
pub fn free(self) -> ADC {
self.into_disabled().reg
}
}
impl<ADC> Adc<ADC, Disabled>
where
ADC: Instance,
{
#[inline]
pub fn new_disabled(adc: ADC) -> Self {
Self {
reg: adc,
state: PhantomData,
}
}
#[inline]
#[must_use]
pub fn into_enabled(self) -> Adc<ADC, Enabled> {
if !self.reg.cr.read().aden().is_enabled() {
self.reg.cr.modify(|_, w| w.aden().enabled());
while self.reg.isr.read().adrdy().is_not_ready() {}
}
Adc {
reg: self.reg,
state: PhantomData,
}
}
#[inline]
pub fn calibrate(
&mut self,
clocks: &Clocks,
common_adc: &CommonAdc<<ADC as Instance>::SharedInstance>,
) {
self.configure_voltage_regulator(Switch::On, clocks);
self.reg
.cr
.modify(|_, w| w.adcaldif().single_ended().adcal().calibration());
while self.reg.cr.read().adcal().is_calibration() {}
let adc_cycles = 4;
let frequency = common_adc
.reg
.clock(clocks)
.unwrap_or_else(|| clocks.sysclk());
let cpu_cycles = adc_cycles * clocks.sysclk().0 / frequency.0;
asm::delay(cpu_cycles);
self.configure_voltage_regulator(Switch::Off, clocks);
}
fn configure_voltage_regulator(&mut self, toggle: impl Into<Switch>, clocks: &Clocks) {
let already_on = self.reg.cr.read().advregen().is_enabled();
let toggle = toggle.into();
self.reg.cr.modify(|_, w| w.advregen().intermediate());
self.reg.cr.modify(|_, w| {
w.advregen().variant(match toggle {
Switch::On => adc1::cr::ADVREGEN_A::Enabled,
Switch::Off => adc1::cr::ADVREGEN_A::Disabled,
})
});
if toggle == Switch::On && !already_on {
let wait = MAX_ADVREGEN_STARTUP.integer()
* clocks.sysclk().integer()
* <Microseconds as FixedPoint>::SCALING_FACTOR;
asm::delay(wait);
}
}
#[inline]
pub fn free(self) -> ADC {
self.reg
}
}
impl<ADC, State> Adc<ADC, State>
where
ADC: Instance,
{
#[inline]
pub fn overrun_mode(&self) -> config::OverrunMode {
self.reg.cfgr.read().ovrmod().variant().into()
}
#[inline]
pub fn resolution(&self) -> config::Resolution {
self.reg.cfgr.read().res().variant().into()
}
#[inline]
pub fn data_alignment(&self) -> config::DataAlignment {
self.reg.cfgr.read().align().variant().into()
}
#[inline]
pub fn external_trigger(&self) -> Option<config::ExternalTrigger> {
use adc1::cfgr::{EXTEN_A, EXTSEL_A};
use config::ExternalTrigger;
let cfgr = self.reg.cfgr.read();
match (cfgr.exten().variant(), cfgr.extsel().variant()) {
(EXTEN_A::Disabled, _) | (_, None) => None,
(edge, Some(ext)) => {
let edge = match edge {
EXTEN_A::Disabled => {
unsafe { unreachable_unchecked() }
}
EXTEN_A::RisingEdge => config::TriggerMode::RisingEdge,
EXTEN_A::FallingEdge => config::TriggerMode::FallingEdge,
EXTEN_A::BothEdges => config::TriggerMode::BothEdges,
};
Some(match ext {
EXTSEL_A::HrtimAdctrg1 => ExternalTrigger::HrtimAdcTrg1(edge),
EXTSEL_A::HrtimAdctrg3 => ExternalTrigger::HrtimAdcTrg3(edge),
EXTSEL_A::Tim1Cc1 => ExternalTrigger::Tim1Cc1(edge),
EXTSEL_A::Tim1Cc2 => ExternalTrigger::Tim1Cc2(edge),
EXTSEL_A::Tim1Cc3 => ExternalTrigger::Tim1Cc3(edge),
EXTSEL_A::Tim2Cc2 => ExternalTrigger::Tim2Cc2(edge),
EXTSEL_A::Tim3Trgo => ExternalTrigger::Tim3Trgo(edge),
EXTSEL_A::Exti11 => ExternalTrigger::Exti11(edge),
EXTSEL_A::Tim1Trgo => ExternalTrigger::Tim1Trgo(edge),
EXTSEL_A::Tim1Trgo2 => ExternalTrigger::Tim1Trgo2(edge),
EXTSEL_A::Tim2Trgo => ExternalTrigger::Tim2Trgo(edge),
EXTSEL_A::Tim6Trgo => ExternalTrigger::Tim6Trgo(edge),
EXTSEL_A::Tim15Trgo => ExternalTrigger::Tim15Trgo(edge),
EXTSEL_A::Tim3Cc4 => ExternalTrigger::Tim3Cc4(edge),
})
}
}
}
#[inline]
pub fn conversion_mode(&self) -> config::ConversionMode {
use adc1::cfgr::{CONT_A, DISCEN_A};
let cfgr = self.reg.cfgr.read();
match (
cfgr.cont().variant(),
cfgr.discen().variant(),
cfgr.discnum().bits(),
) {
(CONT_A::Single, DISCEN_A::Disabled, _) => config::ConversionMode::Single,
(CONT_A::Continuous, DISCEN_A::Disabled, _) => config::ConversionMode::Continuous,
(_, DISCEN_A::Enabled, n) => config::ConversionMode::Discontinuous(n),
}
}
#[inline]
pub fn dma_mode(&self) -> config::DmaMode {
use adc1::cfgr::{DMACFG_A, DMAEN_A};
let cfgr = self.reg.cfgr.read();
match (cfgr.dmaen().variant(), cfgr.dmacfg().variant()) {
(DMAEN_A::Disabled, _) => config::DmaMode::Disabled,
(DMAEN_A::Enabled, DMACFG_A::OneShot) => config::DmaMode::OneShot,
(DMAEN_A::Enabled, DMACFG_A::Circular) => config::DmaMode::Circular,
}
}
#[inline]
#[cfg(feature = "svd-f373")]
pub fn scan(&self) -> config::Scan {
self.reg.cr1.modify(|_, w| w.scan().variant(scan.into()));
}
pub fn config(&self) -> config::Config {
config::Config {
resolution: self.resolution(),
data_alignment: self.data_alignment(),
#[cfg(feature = "svd-f373")]
scan: self.scan(),
overrun: self.overrun_mode(),
external_trigger: self.external_trigger(),
conversion: self.conversion_mode(),
dma: self.dma_mode(),
}
}
#[inline]
pub fn is_conversion_ongoing(&self) -> bool {
self.reg.cr.read().adstart().is_active()
}
#[inline]
#[rustfmt::skip]
pub fn channel_sequence(&self, sequence: config::Sequence) -> Option<channel::Id> {
match sequence {
config::Sequence::One => self.reg.sqr1.read().sq1().bits().try_into().ok(),
config::Sequence::Two => self.reg.sqr1.read().sq2().bits().try_into().ok(),
config::Sequence::Three => self.reg.sqr1.read().sq3().bits().try_into().ok(),
config::Sequence::Four => self.reg.sqr1.read().sq4().bits().try_into().ok(),
config::Sequence::Five => self.reg.sqr2.read().sq5().bits().try_into().ok(),
config::Sequence::Six => self.reg.sqr2.read().sq6().bits().try_into().ok(),
config::Sequence::Seven => self.reg.sqr2.read().sq7().bits().try_into().ok(),
config::Sequence::Eight => self.reg.sqr2.read().sq8().bits().try_into().ok(),
config::Sequence::Nine => self.reg.sqr2.read().sq9().bits().try_into().ok(),
config::Sequence::Ten => self.reg.sqr3.read().sq10().bits().try_into().ok(),
config::Sequence::Eleven => self.reg.sqr3.read().sq11().bits().try_into().ok(),
config::Sequence::Twelve => self.reg.sqr3.read().sq12().bits().try_into().ok(),
config::Sequence::Thirteen => self.reg.sqr3.read().sq13().bits().try_into().ok(),
config::Sequence::Fourteen => self.reg.sqr3.read().sq14().bits().try_into().ok(),
config::Sequence::Fifteen => self.reg.sqr4.read().sq15().bits().try_into().ok(),
config::Sequence::Sixteen => self.reg.sqr4.read().sq16().bits().try_into().ok(),
}
}
pub fn sample_time<Pin>(&self, _pin: &Pin) -> config::SampleTime
where
Pin: Channel<ADC, ID = channel::Id>,
{
let channel = Pin::channel();
match channel {
#[cfg(feature = "gpio-f373")]
channel::Id::Zero => self.adc.smpr1.read().smp0().variant().into(),
channel::Id::One => self.reg.smpr1.read().smp1().variant().into(),
channel::Id::Two => self.reg.smpr1.read().smp2().variant().into(),
channel::Id::Three => self.reg.smpr1.read().smp3().variant().into(),
channel::Id::Four => self.reg.smpr1.read().smp4().variant().into(),
channel::Id::Five => self.reg.smpr1.read().smp5().variant().into(),
channel::Id::Six => self.reg.smpr1.read().smp6().variant().into(),
channel::Id::Seven => self.reg.smpr1.read().smp7().variant().into(),
channel::Id::Eight => self.reg.smpr1.read().smp8().variant().into(),
channel::Id::Nine => self.reg.smpr1.read().smp9().variant().into(),
channel::Id::Ten => self.reg.smpr2.read().smp10().variant().into(),
channel::Id::Eleven => self.reg.smpr2.read().smp11().variant().into(),
channel::Id::Twelve => self.reg.smpr2.read().smp12().variant().into(),
channel::Id::Thirteen => self.reg.smpr2.read().smp13().variant().into(),
channel::Id::Fourteen => self.reg.smpr2.read().smp14().variant().into(),
channel::Id::Fifteen => self.reg.smpr2.read().smp15().variant().into(),
channel::Id::Sixteen => self.reg.smpr2.read().smp16().variant().into(),
channel::Id::Seventeen => self.reg.smpr2.read().smp17().variant().into(),
channel::Id::Eighteen => self.reg.smpr2.read().smp18().variant().into(),
}
}
#[inline]
pub fn sequence_length(&self) -> config::Sequence {
match self.reg.sqr1.read().l().bits().try_into() {
Ok(seq) => seq,
Err(_) => unsafe { unreachable_unchecked() },
}
}
#[inline]
#[cfg(feature = "__disabled")]
pub fn is_injected_conversion_stopped(&self) -> bool {
self.adc.cr.read().jadstp().is_stop()
}
#[inline]
pub fn is_interrupt_configured(&self, event: Event) -> bool {
match event {
Event::AdcReady => self.reg.ier.read().adrdyie().is_enabled(),
Event::EndOfSamplingPhase => self.reg.ier.read().eosmpie().is_enabled(),
Event::EndOfConversion => self.reg.ier.read().eocie().is_enabled(),
Event::EndOfSequence => self.reg.ier.read().eosie().is_enabled(),
Event::Overrun => self.reg.ier.read().ovrie().is_enabled(),
Event::InjectedChannelEndOfConversion => self.reg.ier.read().jeocie().is_enabled(),
Event::InjectedChannelEndOfSequence => self.reg.ier.read().jeosie().is_enabled(),
Event::AnalogWatchdog1 => self.reg.ier.read().awd1ie().is_enabled(),
Event::AnalogWatchdog2 => self.reg.ier.read().awd2ie().is_enabled(),
Event::AnalogWatchdog3 => self.reg.ier.read().awd3ie().is_enabled(),
Event::InjectedContextQueueOverfow => self.reg.ier.read().jqovfie().is_enabled(),
}
}
#[cfg(feature = "enumset")]
#[cfg_attr(docsrs, doc(cfg(feature = "enumset")))]
#[inline]
pub fn configured_interrupts(&mut self) -> EnumSet<Event> {
let mut events = EnumSet::new();
for event in EnumSet::<Event>::all().iter() {
if self.is_interrupt_configured(event) {
events |= event;
}
}
events
}
#[inline]
pub fn is_event_triggered(&self, event: Event) -> bool {
let isr = self.reg.isr.read();
match event {
Event::AdcReady => isr.adrdy().is_ready(),
Event::EndOfSamplingPhase => isr.eosmp().is_ended(),
Event::EndOfConversion => isr.eoc().is_complete(),
Event::EndOfSequence => isr.eos().is_complete(),
Event::Overrun => isr.ovr().is_overrun(),
Event::InjectedChannelEndOfConversion => isr.jeoc().is_complete(),
Event::InjectedChannelEndOfSequence => isr.jeos().is_complete(),
Event::AnalogWatchdog1 => isr.awd1().is_event(),
Event::AnalogWatchdog2 => isr.awd2().is_event(),
Event::AnalogWatchdog3 => isr.awd3().is_event(),
Event::InjectedContextQueueOverfow => isr.jqovf().is_overflow(),
}
}
#[cfg(feature = "enumset")]
#[cfg_attr(docsrs, doc(cfg(feature = "enumset")))]
pub fn triggered_events(&self) -> EnumSet<Event> {
let mut events = EnumSet::new();
for event in EnumSet::<Event>::all().iter() {
if self.is_event_triggered(event) {
events |= event;
}
}
events
}
#[inline]
pub unsafe fn peripheral(&mut self) -> &mut ADC {
&mut self.reg
}
}
impl<ADC, State> Adc<ADC, State>
where
ADC: Instance,
State: Configurable,
{
pub fn set_config(&mut self, config: config::Config) {
self.set_resolution(config.resolution);
self.set_data_alignment(config.data_alignment);
#[cfg(feature = "svd-f373")]
self.set_scan(config.scan);
self.set_overrun_mode(config.overrun);
self.set_external_trigger(config.external_trigger);
self.set_conversion_mode(config.conversion);
self.set_dma_mode(config.dma);
}
#[inline]
pub fn set_overrun_mode(&mut self, mode: config::OverrunMode) {
self.reg.cfgr.modify(|_, w| w.ovrmod().variant(mode.into()));
}
#[inline]
pub fn set_resolution(&mut self, resolution: config::Resolution) {
self.reg
.cfgr
.modify(|_, w| w.res().variant(resolution.into()));
}
#[inline]
pub fn set_data_alignment(&mut self, align: config::DataAlignment) {
self.reg.cfgr.modify(|_, w| w.align().variant(align.into()));
}
#[inline]
pub fn set_external_trigger(&mut self, trigger: Option<config::ExternalTrigger>) {
self.stop_conversion();
self.reg.cfgr.modify(|_, w| {
if let Some(ext) = trigger {
w.extsel().variant(ext.into()).exten().variant(ext.into())
} else {
w.exten().disabled()
}
});
}
#[inline]
pub fn set_conversion_mode(&mut self, conversion_mode: config::ConversionMode) {
self.reg.cfgr.modify(|_, w| {
w.discen()
.variant(conversion_mode.into())
.cont()
.variant(conversion_mode.into())
});
if let config::ConversionMode::Discontinuous(n) = conversion_mode {
self.reg
.cfgr
.modify(|_, w| w.discnum().bits(if n < 0b111 { n } else { 0b111 }));
}
}
#[inline]
pub fn set_dma_mode(&mut self, dma: config::DmaMode) {
use adc1::cfgr::{DMACFG_A, DMAEN_A};
let (en, mode) = match dma {
config::DmaMode::Disabled => (DMAEN_A::Disabled, DMACFG_A::OneShot),
config::DmaMode::OneShot => (DMAEN_A::Enabled, DMACFG_A::OneShot),
config::DmaMode::Circular => (DMAEN_A::Enabled, DMACFG_A::Circular),
};
self.reg
.cfgr
.modify(|_, w| w.dmaen().variant(en).dmacfg().variant(mode));
}
#[inline]
#[cfg(feature = "svd-f373")]
pub fn set_scan(&mut self, scan: config::Scan) {
self.reg.cr1.modify(|_, w| w.scan().variant(scan.into()));
}
#[inline]
pub fn stop_conversion(&mut self) {
if self.is_conversion_ongoing() {
self.reg.cr.modify(|_, w| w.adstp().stop_conversion());
}
while self.reg.cr.read().adstp().bit_is_set() {}
}
#[inline]
pub fn set_pin_sequence_position<Pin>(&mut self, sequence: config::Sequence, _pin: &mut Pin)
where
Pin: Channel<ADC, ID = channel::Id>,
{
let channel = Pin::channel();
unsafe { self.set_channel_sequence_position(sequence, channel) };
}
#[inline]
#[rustfmt::skip]
pub unsafe fn set_channel_sequence_position(&mut self, sequence: config::Sequence, channel: channel::Id) {
self.stop_conversion();
if self.sequence_length() < sequence {
self.set_sequence_length(sequence);
}
unsafe {
match sequence {
config::Sequence::One => self.reg.sqr1.modify(|_, w| w.sq1().bits(channel.into())),
config::Sequence::Two => self.reg.sqr1.modify(|_, w| w.sq2().bits(channel.into())),
config::Sequence::Three => self.reg.sqr1.modify(|_, w| w.sq3().bits(channel.into())),
config::Sequence::Four => self.reg.sqr1.modify(|_, w| w.sq4().bits(channel.into())),
config::Sequence::Five => self.reg.sqr2.modify(|_, w| w.sq5().bits(channel.into())),
config::Sequence::Six => self.reg.sqr2.modify(|_, w| w.sq6().bits(channel.into())),
config::Sequence::Seven => self.reg.sqr2.modify(|_, w| w.sq7().bits(channel.into())),
config::Sequence::Eight => self.reg.sqr2.modify(|_, w| w.sq8().bits(channel.into())),
config::Sequence::Nine => self.reg.sqr2.modify(|_, w| w.sq9().bits(channel.into())),
config::Sequence::Ten => self.reg.sqr3.modify(|_, w| w.sq10().bits(channel.into())),
config::Sequence::Eleven => self.reg.sqr3.modify(|_, w| w.sq11().bits(channel.into())),
config::Sequence::Twelve => self.reg.sqr3.modify(|_, w| w.sq12().bits(channel.into())),
config::Sequence::Thirteen => self.reg.sqr3.modify(|_, w| w.sq13().bits(channel.into())),
config::Sequence::Fourteen => self.reg.sqr3.modify(|_, w| w.sq14().bits(channel.into())),
config::Sequence::Fifteen => self.reg.sqr4.modify(|_, w| w.sq15().bits(channel.into())),
config::Sequence::Sixteen => self.reg.sqr4.modify(|_, w| w.sq16().bits(channel.into())),
}
}
}
#[rustfmt::skip]
pub fn set_sample_time<Pin>(&mut self, _pin: &Pin, sample_time: config::SampleTime)
where
Pin: Channel<ADC, ID = channel::Id>,
{
let channel = Pin::channel();
match channel {
#[cfg(feature = "gpio-f373")]
channel::Id::Zero => self.adc.smpr1.modify(|_, w| w.smp0().variant(sample_time.into())),
channel::Id::One => self.reg.smpr1.modify(|_, w| w.smp1().variant(sample_time.into())),
channel::Id::Two => self.reg.smpr1.modify(|_, w| w.smp2().variant(sample_time.into())),
channel::Id::Three => self.reg.smpr1.modify(|_, w| w.smp3().variant(sample_time.into())),
channel::Id::Four => self.reg.smpr1.modify(|_, w| w.smp4().variant(sample_time.into())),
channel::Id::Five => self.reg.smpr1.modify(|_, w| w.smp5().variant(sample_time.into())),
channel::Id::Six => self.reg.smpr1.modify(|_, w| w.smp6().variant(sample_time.into())),
channel::Id::Seven => self.reg.smpr1.modify(|_, w| w.smp7().variant(sample_time.into())),
channel::Id::Eight => self.reg.smpr1.modify(|_, w| w.smp8().variant(sample_time.into())),
channel::Id::Nine => self.reg.smpr1.modify(|_, w| w.smp9().variant(sample_time.into())),
channel::Id::Ten => self.reg.smpr2.modify(|_, w| w.smp10().variant(sample_time.into())),
channel::Id::Eleven => self.reg.smpr2.modify(|_, w| w.smp11().variant(sample_time.into())),
channel::Id::Twelve => self.reg.smpr2.modify(|_, w| w.smp12().variant(sample_time.into())),
channel::Id::Thirteen => self.reg.smpr2.modify(|_, w| w.smp13().variant(sample_time.into())),
channel::Id::Fourteen => self.reg.smpr2.modify(|_, w| w.smp14().variant(sample_time.into())),
channel::Id::Fifteen => self.reg.smpr2.modify(|_, w| w.smp15().variant(sample_time.into())),
channel::Id::Sixteen => self.reg.smpr2.modify(|_, w| w.smp16().variant(sample_time.into())),
channel::Id::Seventeen => self.reg.smpr2.modify(|_, w| w.smp17().variant(sample_time.into())),
channel::Id::Eighteen => self.reg.smpr2.modify(|_, w| w.smp18().variant(sample_time.into())),
}
}
#[inline]
pub fn set_sequence_length(&mut self, sequence: config::Sequence) {
self.reg.sqr1.modify(|_, w| w.l().bits(sequence.into()));
}
#[inline]
#[cfg(feature = "__disabled")]
pub fn stop_injected_conversion(&mut self) {
self.adc.cr.modify(|_, w| w.jadstp().stop());
}
#[inline]
pub fn enable_interrupt(&mut self, event: Event) {
self.configure_interrupt(event, Switch::On);
}
#[inline]
pub fn disable_interrupt(&mut self, event: Event) {
self.configure_interrupt(event, Switch::Off);
}
#[inline]
pub fn configure_interrupt(&mut self, event: Event, enable: impl Into<Switch>) {
let enable: Switch = enable.into();
let enable: bool = enable.into();
match event {
Event::AdcReady => self.reg.ier.modify(|_, w| w.adrdyie().bit(enable)),
Event::EndOfSamplingPhase => self.reg.ier.modify(|_, w| w.eosmpie().bit(enable)),
Event::EndOfConversion => self.reg.ier.modify(|_, w| w.eocie().bit(enable)),
Event::EndOfSequence => self.reg.ier.modify(|_, w| w.eosie().bit(enable)),
Event::Overrun => self.reg.ier.modify(|_, w| w.ovrie().bit(enable)),
Event::InjectedChannelEndOfConversion => {
self.reg.ier.modify(|_, w| w.jeocie().bit(enable));
}
Event::InjectedChannelEndOfSequence => {
self.reg.ier.modify(|_, w| w.jeosie().bit(enable));
}
Event::AnalogWatchdog1 => self.reg.ier.modify(|_, w| w.awd1ie().bit(enable)),
Event::AnalogWatchdog2 => self.reg.ier.modify(|_, w| w.awd2ie().bit(enable)),
Event::AnalogWatchdog3 => self.reg.ier.modify(|_, w| w.awd3ie().bit(enable)),
Event::InjectedContextQueueOverfow => {
self.reg.ier.modify(|_, w| w.jqovfie().bit(enable));
}
};
}
#[cfg(feature = "enumset")]
#[cfg_attr(docsrs, doc(cfg(feature = "enumset")))]
#[inline]
pub fn configure_interrupts(&mut self, events: EnumSet<Event>) {
for event in events.complement().iter() {
self.configure_interrupt(event, false);
}
for event in events.iter() {
self.configure_interrupt(event, true);
}
}
#[inline]
pub fn clear_event(&mut self, event: Event) {
self.reg.isr.write(|w| match event {
Event::AdcReady => w.adrdy().clear(),
Event::EndOfSamplingPhase => w.eosmp().clear(),
Event::EndOfConversion => w.eoc().clear(),
Event::EndOfSequence => w.eos().clear(),
Event::Overrun => w.ovr().clear(),
Event::InjectedChannelEndOfConversion => w.jeoc().clear(),
Event::InjectedChannelEndOfSequence => w.jeos().clear(),
Event::AnalogWatchdog1 => w.awd1().clear(),
Event::AnalogWatchdog2 => w.awd2().clear(),
Event::AnalogWatchdog3 => w.awd3().clear(),
Event::InjectedContextQueueOverfow => w.jqovf().clear(),
});
}
#[inline]
pub fn clear_events(&mut self) {
self.reg.isr.write(|w| unsafe { w.bits(u32::MAX) });
}
}
impl<ADC> Adc<ADC, OneShot>
where
ADC: Instance,
{
pub fn into_enabled(self) -> Adc<ADC, Enabled> {
Adc {
reg: self.reg,
state: PhantomData,
}
}
#[inline]
pub fn free(self) -> ADC {
self.into_enabled().into_disabled().reg
}
}
impl<ADC> Adc<ADC>
where
ADC: crate::interrupts::InterruptNumber,
{
pub fn interrupt(&self) -> <ADC as crate::interrupts::InterruptNumber>::Interrupt {
<ADC as crate::interrupts::InterruptNumber>::INTERRUPT
}
}
pub trait Configurable: crate::private::Sealed {}
impl<ADC, Word, Pin> embedded_hal::adc::OneShot<ADC, Word, Pin> for Adc<ADC>
where
ADC: Instance,
Word: From<u16>,
Pin: Channel<ADC, ID = channel::Id>,
{
type Error = ();
fn read(&mut self, pin: &mut Pin) -> nb::Result<Word, Self::Error> {
let conv = self.conversion_mode();
let dma = self.dma_mode();
let ext = self.external_trigger();
self.set_conversion_mode(config::ConversionMode::Single);
self.set_dma_mode(config::DmaMode::Disabled);
self.set_external_trigger(None);
#[cfg(feature = "svd-f373")]
let scan = self.scan();
#[cfg(feature = "svd-f373")]
self.set_scan(config::Scan::Disabled);
let is_end_of_conversion_enabled = self.is_interrupt_configured(Event::EndOfConversion);
let is_end_of_sequence_enabled = self.is_interrupt_configured(Event::EndOfSequence);
self.disable_interrupt(Event::EndOfConversion);
self.disable_interrupt(Event::EndOfSequence);
let seq_len = self.sequence_length();
let old_id = self.channel_sequence(config::Sequence::One);
self.set_sequence_length(config::Sequence::One);
self.set_pin_sequence_position(config::Sequence::One, pin);
self.clear_event(Event::EndOfConversion);
self.clear_event(Event::EndOfSequence);
self.start_conversion();
while !self.is_event_triggered(Event::EndOfConversion)
&& !self.is_event_triggered(Event::EndOfSequence)
{}
self.clear_event(Event::EndOfConversion);
self.clear_event(Event::EndOfSequence);
let result = self.data_register();
if let Some(id) = old_id {
unsafe { self.set_channel_sequence_position(config::Sequence::One, id) };
}
self.set_sequence_length(seq_len);
self.configure_interrupt(Event::EndOfSequence, is_end_of_sequence_enabled);
self.configure_interrupt(Event::EndOfConversion, is_end_of_conversion_enabled);
#[cfg(feature = "svd-f373")]
self.set_scan(config::Scan::Disabled);
self.set_external_trigger(ext);
self.set_dma_mode(dma);
self.set_conversion_mode(conv);
Ok(result.into())
}
}
impl<ADC, Word, Pin> embedded_hal::adc::OneShot<ADC, Word, Pin> for Adc<ADC, OneShot>
where
ADC: Instance,
Word: From<u16>,
Pin: Channel<ADC, ID = channel::Id>,
{
type Error = ();
fn read(&mut self, _pin: &mut Pin) -> nb::Result<Word, Self::Error> {
self.reg.sqr1.modify(|_, w|
unsafe { w.sq1().bits(Pin::channel().into()) });
self.reg.isr.reset();
self.reg.cr.modify(|_, w| w.adstart().start_conversion());
while !self.reg.isr.read().eoc().is_complete() && !self.reg.isr.read().eos().is_complete() {
}
self.reg.isr.reset();
Ok(self.reg.dr.read().rdata().bits().into())
}
}
pub trait Instance: Deref<Target = adc1::RegisterBlock> + crate::private::Sealed {
type SharedInstance: CommonInstance;
}
pub trait CommonInstance: Deref<Target = adc1_2::RegisterBlock> + crate::private::Sealed {
type Childs;
#[doc(hidden)]
fn enable_clock(&mut self, clocks: &Clocks, ahb: &mut AHB);
#[doc(hidden)]
fn clock(&self, clocks: &Clocks) -> Option<Hertz>;
}
pub struct Enabled;
impl crate::private::Sealed for Enabled {}
impl Configurable for Enabled {}
pub struct Disabled;
impl crate::private::Sealed for Disabled {}
impl Configurable for Disabled {}
pub struct OneShot;
macro_rules! adc {
($(
$ADC:ident: (
$ADCX_Y:ident,
$INTERRUPT:path
),
)+) => {
$(
impl crate::private::Sealed for pac::$ADC {}
impl Instance for pac::$ADC {
type SharedInstance = pac::$ADCX_Y;
}
impl crate::interrupts::InterruptNumber for pac::$ADC {
type Interrupt = Interrupt;
const INTERRUPT: Interrupt = $INTERRUPT;
}
)+
};
([ $(($A:literal, $X:literal, $Y:literal, $INTERRUPT:path)),+ ]) => {
paste::paste! {
adc!(
$(
[<ADC $A>]: (
[<ADC $X _ $Y>],
$INTERRUPT
),
)+
);
}
};
}
macro_rules! adc_common {
($(
$ADCX_Y:ident: (
$ADC_CHILDS:ty,
$ADCXYPRES_A:ident,
$adcXYen:ident,
$adcXYpres:ident
),
)+) => {
$(
impl CommonInstance for pac::$ADCX_Y {
type Childs = $ADC_CHILDS;
fn enable_clock(&mut self, clocks: &Clocks, ahb: &mut AHB) {
pac::$ADCX_Y::enable(ahb);
if self.clock(clocks).is_none() {
self.ccr.modify(|_, w| w
.ckmode().variant(CKMODE_A::SyncDiv1)
);
};
}
fn clock(&self, clocks: &Clocks) -> Option<Hertz> {
use crate::pac::rcc::cfgr2::$ADCXYPRES_A;
use crate::pac::RCC;
let adc_pres = unsafe { &(*RCC::ptr()).cfgr2.read().$adcXYpres() };
Some(match clocks.pllclk() {
Some(pllclk) if !adc_pres.is_no_clock() => {
pllclk
/ match adc_pres.variant() {
Some($ADCXYPRES_A::Div1) => 1,
Some($ADCXYPRES_A::Div2) => 2,
Some($ADCXYPRES_A::Div4) => 4,
Some($ADCXYPRES_A::Div6) => 6,
Some($ADCXYPRES_A::Div8) => 8,
Some($ADCXYPRES_A::Div10) => 10,
Some($ADCXYPRES_A::Div12) => 12,
Some($ADCXYPRES_A::Div16) => 16,
Some($ADCXYPRES_A::Div32) => 32,
Some($ADCXYPRES_A::Div64) => 64,
Some($ADCXYPRES_A::Div128) => 128,
Some($ADCXYPRES_A::Div256) => 256,
Some($ADCXYPRES_A::NoClock) | None => 1,
}
}
_ => {
clocks.sysclk()
/ match self.ccr.read().ckmode().variant() {
CKMODE_A::SyncDiv1 => 1,
CKMODE_A::SyncDiv2 => 2,
CKMODE_A::SyncDiv4 => 4,
CKMODE_A::Asynchronous => return None,
}
}
})
}
}
)+
};
([ $(($X:literal, $Y:literal)),+ ]) => {
paste::paste! {
adc_common!(
$(
[<ADC $X _ $Y>]: (
(pac::[<ADC $X>], pac::[<ADC $Y>]),
[<ADC $X $Y PRES_A>],
[<adc $X $Y en>],
[<adc $X $Y pres>]
),
)+
);
}
};
([ $(($X:literal, $Y:literal, $ADC:ident)),+ ]) => {
paste::paste! {
adc_common!(
$(
$ADC: (
(pac::[<ADC $X>], pac::[<ADC $Y>]),
[<ADC $X $Y PRES_A>],
[<adc $X $Y en>],
[<adc $X $Y pres>]
),
)+
);
}
};
([ $(($A:literal, $X:literal, $Y:literal)),+ ]) => {
paste::paste! {
adc_common!(
$(
[<ADC $X _ $Y>]: (
pac::[<ADC $A>],
[<ADC $X PRES_A>],
[<adc $X en>],
[<adc $X pres>]
),
)+
);
}
};
}
cfg_if::cfg_if! {
if #[cfg(feature = "svd-f301")] {
adc_common!([(1, 1, 2)]);
adc!([(1, 1, 2, Interrupt::ADC1_IRQ)]);
} else {
adc_common!([(1, 2)]);
adc!([(1, 1, 2, Interrupt::ADC1_2)]);
}
}
#[cfg(any(feature = "svd-f302", feature = "svd-f303", feature = "svd-f3x4"))]
adc!([(2, 1, 2, Interrupt::ADC1_2)]);
cfg_if::cfg_if! {
if #[cfg(feature = "svd-f303")] {
adc_common!([(3, 4)]);
adc!([(3, 3, 4, Interrupt::ADC3), (4, 3, 4, Interrupt::ADC4)]);
}
}