#![allow(dead_code)]
use crate::rcc::{Clocks, Enable, Reset, APB2};
use crate::gpio::{self, Analog};
use crate::pac::{ADC1, ADC2, ADC3, ADC_COMMON};
use cortex_m::asm::delay;
use fugit::HertzU32 as Hertz;
use embedded_hal::adc::{Channel, OneShot};
#[derive(Clone, Copy, Debug, PartialEq)]
#[allow(non_camel_case_types)]
pub enum SampleTime {
T_3,
T_15,
T_28,
T_56,
T_84,
T_112,
T_144,
T_480,
}
impl Default for SampleTime {
fn default() -> Self {
SampleTime::T_56
}
}
impl From<SampleTime> for u8 {
fn from(val: SampleTime) -> Self {
use SampleTime::*;
match val {
T_3 => 0,
T_15 => 1,
T_28 => 2,
T_56 => 3,
T_84 => 4,
T_112 => 5,
T_144 => 6,
T_480 => 7,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Align {
Right,
Left,
}
impl Default for Align {
fn default() -> Self {
Align::Right
}
}
impl From<Align> for bool {
fn from(val: Align) -> Self {
match val {
Align::Right => false,
Align::Left => true,
}
}
}
macro_rules! adc_pins {
($ADC:ident, $($pin:ty => $chan:literal),+ $(,)*) => {
$(
impl Channel<$ADC> for $pin {
type ID = u8;
fn channel() -> u8 { $chan }
}
)+
};
}
adc_pins!(ADC1,
gpio::PA0<Analog> => 0,
gpio::PA1<Analog> => 1,
gpio::PA2<Analog> => 2,
gpio::PA3<Analog> => 3,
gpio::PA4<Analog> => 4,
gpio::PA5<Analog> => 5,
gpio::PA6<Analog> => 6,
gpio::PA7<Analog> => 7,
gpio::PB0<Analog> => 8,
gpio::PB1<Analog> => 9,
gpio::PC0<Analog> => 10,
gpio::PC1<Analog> => 11,
gpio::PC2<Analog> => 12,
gpio::PC3<Analog> => 13,
gpio::PC4<Analog> => 14,
gpio::PC5<Analog> => 15,
);
adc_pins!(ADC2,
gpio::PA0<Analog> => 0,
gpio::PA1<Analog> => 1,
gpio::PA2<Analog> => 2,
gpio::PA3<Analog> => 3,
gpio::PA4<Analog> => 4,
gpio::PA5<Analog> => 5,
gpio::PA6<Analog> => 6,
gpio::PA7<Analog> => 7,
gpio::PB0<Analog> => 8,
gpio::PB1<Analog> => 9,
gpio::PC0<Analog> => 10,
gpio::PC1<Analog> => 11,
gpio::PC2<Analog> => 12,
gpio::PC3<Analog> => 13,
gpio::PC4<Analog> => 14,
gpio::PC5<Analog> => 15,
);
adc_pins!(ADC3,
gpio::PA0<Analog> => 0,
gpio::PA1<Analog> => 1,
gpio::PA2<Analog> => 2,
gpio::PA3<Analog> => 3,
gpio::PF6<Analog> => 4,
gpio::PF7<Analog> => 5,
gpio::PF8<Analog> => 6,
gpio::PF9<Analog> => 7,
gpio::PF10<Analog> => 8,
gpio::PF3<Analog> => 9,
gpio::PC0<Analog> => 10,
gpio::PC1<Analog> => 11,
gpio::PC2<Analog> => 12,
gpio::PC3<Analog> => 13,
gpio::PF4<Analog> => 14,
gpio::PF5<Analog> => 15,
);
pub struct Adc<ADC> {
rb: ADC,
sample_time: SampleTime,
align: Align,
sysclk: Hertz,
}
#[derive(Copy, Clone, Debug, PartialEq, Default)]
pub struct StoredConfig(SampleTime, Align);
macro_rules! adc_hal {
( $ADC:ident, $adc:ident) => {
impl Adc<$ADC> {
pub fn $adc(
adc: $ADC,
apb2: &mut APB2,
clocks: &Clocks,
nb_resolution_bits: u8,
reset: bool,
) -> Self {
let mut s = Self {
rb: adc,
sample_time: SampleTime::default(),
align: Align::default(),
sysclk: clocks.sysclk(),
};
<$ADC>::enable(apb2);
if reset {
s.power_down();
<$ADC>::reset(apb2);
}
s.setup_oneshot();
s.resolution(nb_resolution_bits);
s.power_up();
s
}
pub fn save_cfg(&mut self) -> StoredConfig {
StoredConfig(self.sample_time, self.align)
}
pub fn restore_cfg(&mut self, cfg: StoredConfig) {
self.sample_time = cfg.0;
self.align = cfg.1;
}
pub fn default_cfg(&mut self) -> StoredConfig {
let cfg = self.save_cfg();
self.sample_time = SampleTime::default();
self.align = Align::default();
cfg
}
pub fn set_sample_time(&mut self, t_samp: SampleTime) {
self.sample_time = t_samp;
}
pub fn set_align(&mut self, align: Align) {
self.align = align;
}
pub fn max_sample(&self) -> u16 {
match self.align {
Align::Left => u16::max_value(),
Align::Right => (1 << 12) - 1,
}
}
#[inline(always)]
pub fn set_external_trigger(&mut self, trigger: crate::pac::adc1::cr2::EXTSEL_A) {
self.rb.cr2.modify(|_, w| w.extsel().variant(trigger))
}
fn power_up(&mut self) {
self.rb.cr2.modify(|_, w| w.adon().set_bit());
delay(self.sysclk.raw() / 800_000);
}
fn power_down(&mut self) {
self.rb.cr2.modify(|_, w| w.adon().clear_bit());
}
fn setup_oneshot(&mut self) {
self.rb
.cr2
.modify(|_, w| w.cont().clear_bit().swstart().set_bit());
self.rb
.cr1
.modify(|_, w| w.scan().clear_bit().discen().set_bit());
self.rb.sqr1.modify(|_, w| w.l().bits(0b0));
}
fn resolution(&mut self, resol_bits: u8) {
match resol_bits {
12 => self.rb.cr1.modify(|_, w| w.res().bits(0b00)),
10 => self.rb.cr1.modify(|_, w| w.res().bits(0b01)),
8 => self.rb.cr1.modify(|_, w| w.res().bits(0b10)),
6 => self.rb.cr1.modify(|_, w| w.res().bits(0b11)),
_ => self.rb.cr1.modify(|_, w| w.res().bits(0b00)),
}
}
fn set_channel_sample_time(&mut self, chan: u8, sample_time: SampleTime) {
self.rb.smpr2.modify(|r, w| unsafe {
w.bits((r.bits() & !0x07) | ((sample_time as u32) & 0x07))
});
match chan {
0..=9 => {
self.rb.smpr2.modify(|r, w| unsafe {
w.bits(
(r.bits() & !(0x07 << (chan * 3)))
| (((sample_time as u32) & 0x07) << (chan * 3)),
)
})
}
10..=18 => {
self.rb.smpr1.modify(|r, w| unsafe {
w.bits(
(r.bits() & !(0x07 << ((chan - 10) * 3)))
| (((sample_time as u32) & 0x07) << ((chan - 10) * 3)),
)
})
}
_ => unreachable!(),
}
}
fn set_regular_sequence(&mut self, channels: &[u8]) {
let len = channels.len();
let bits = channels
.iter()
.take(6)
.enumerate()
.fold(0u32, |s, (i, c)| s | ((*c as u32) << (i * 5)));
self.rb.sqr3.write(|w| unsafe { w.bits(bits) });
if len > 6 {
let bits = channels
.iter()
.skip(6)
.take(6)
.enumerate()
.fold(0u32, |s, (i, c)| s | ((*c as u32) << (i * 5)));
self.rb.sqr2.write(|w| unsafe { w.bits(bits) });
}
if len > 12 {
let bits = channels
.iter()
.skip(12)
.take(4)
.enumerate()
.fold(0u32, |s, (i, c)| s | ((*c as u32) << (i * 5)));
self.rb.sqr1.write(|w| unsafe { w.bits(bits) });
}
self.rb.sqr1.modify(|_, w| w.l().bits((len - 1) as u8));
}
fn set_continuous_mode(&mut self, continuous: bool) {
self.rb.cr2.modify(|_, w| w.cont().bit(continuous));
}
fn set_discontinuous_mode(&mut self, channels_count: Option<u8>) {
self.rb.cr1.modify(|_, w| match channels_count {
Some(count) => w.discen().set_bit().discnum().bits(count),
None => w.discen().clear_bit(),
});
}
fn convert(&mut self, chan: u8) -> u16 {
self.rb.dr.read().data().bits();
self.set_channel_sample_time(chan, self.sample_time);
self.rb.sqr3.modify(|_, w| unsafe { w.sq1().bits(chan) });
self.rb
.cr2
.modify(|_, w| w.swstart().set_bit().align().bit(self.align.into()));
while self.rb.cr2.read().swstart().bit_is_set() {}
while self.rb.sr.read().eoc().bit_is_clear() {}
let res = self.rb.dr.read().data().bits();
res
}
pub fn release(mut self, apb2: &mut APB2) -> $ADC {
self.power_down();
<$ADC>::disable(apb2);
self.rb
}
}
impl ChannelTimeSequence for Adc<$ADC> {
#[inline(always)]
fn set_channel_sample_time(&mut self, chan: u8, sample_time: SampleTime) {
self.set_channel_sample_time(chan, sample_time);
}
#[inline(always)]
fn set_regular_sequence(&mut self, channels: &[u8]) {
self.set_regular_sequence(channels);
}
#[inline(always)]
fn set_continuous_mode(&mut self, continuous: bool) {
self.set_continuous_mode(continuous);
}
#[inline(always)]
fn set_discontinuous_mode(&mut self, channels: Option<u8>) {
self.set_discontinuous_mode(channels);
}
}
impl<WORD, PIN> OneShot<$ADC, WORD, PIN> for Adc<$ADC>
where
WORD: From<u16>,
PIN: Channel<$ADC, ID = u8>,
{
type Error = ();
fn read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
let res = self.convert(PIN::channel());
Ok(res.into())
}
}
};
}
impl Adc<ADC1> {
pub fn read_vref(&mut self, adc_common: &ADC_COMMON) -> u16 {
let tsv_off = if adc_common.ccr.read().tsvrefe().bit_is_clear() {
adc_common.ccr.modify(|_, w| w.vbate().clear_bit());
adc_common.ccr.modify(|_, w| w.tsvrefe().set_bit());
delay(self.sysclk.raw() / 80_000);
true
} else {
false
};
let val = self.convert(17u8);
if tsv_off {
adc_common.ccr.modify(|_, w| w.tsvrefe().clear_bit());
}
val
}
pub fn bits_to_voltage(&mut self, adc_common: &ADC_COMMON, data: u16) -> u16 {
let v_chan = (data as u32) * 1210 / (self.read_vref(adc_common) as u32);
v_chan as u16
}
}
adc_hal!(ADC1, adc1);
adc_hal!(ADC2, adc2);
adc_hal!(ADC3, adc3);
pub trait ChannelTimeSequence {
fn set_channel_sample_time(&mut self, chan: u8, sample_time: SampleTime);
fn set_regular_sequence(&mut self, channels: &[u8]);
fn set_continuous_mode(&mut self, continuous: bool);
fn set_discontinuous_mode(&mut self, channels_count: Option<u8>);
}
pub trait SetChannels<PINS>: ChannelTimeSequence {
fn set_samples(&mut self);
fn set_sequence(&mut self);
}