use cortex_m::asm;
use embedded_hal::adc::{Channel, OneShot};
use crate::{pac::RCC, traits::ClockCfg};
use paste::paste;
#[cfg(any(feature = "f301", feature = "f302", feature = "f303",))]
use crate::pac::{ADC1, ADC1_2};
#[cfg(any(feature = "f302", feature = "f303",))]
use crate::pac::ADC2;
#[cfg(any(feature = "f303",))]
use crate::pac::{ADC3, ADC3_4, ADC4};
#[cfg(any(feature = "l4", feature = "l5"))]
use crate::pac::ADC_COMMON;
#[cfg(any(
feature = "l4x3",
feature = "h743",
feature = "h743v",
feature = "h747cm4",
feature = "h747cm7",
feature = "h753",
feature = "h753v",
feature = "h7b3",
))]
use crate::pac::ADC1;
#[cfg(any(feature = "l4x1", feature = "l4x2", feature = "l4x5", feature = "l4x6",))]
use crate::pac::{ADC1, ADC2};
#[cfg(any(feature = "l4x5", feature = "l4x6"))]
use crate::pac::ADC3;
#[cfg(feature = "l5")]
use crate::pac::ADC;
const MAX_ADVREGEN_STARTUP_US: u32 = 10;
#[allow(non_snake_case)]
pub mod AdcChannel {
pub struct C1;
pub struct C2;
pub struct C3;
pub struct C4;
pub struct C5;
pub struct C6;
pub struct C7;
pub struct C8;
pub struct C9;
pub struct C10;
pub struct C11;
pub struct C12;
pub struct C13;
pub struct C14;
pub struct C15;
pub struct C16;
pub struct C17;
pub struct C18;
}
#[derive(Clone, Copy)]
enum AdcNum {
One,
Two,
Three,
Four,
}
pub struct Adc<ADC> {
regs: ADC,
ckmode: ClockMode,
operation_mode: Option<OperationMode>,
}
pub enum SampleTime {
T1,
T2,
T4,
T7,
T19,
T61,
T181,
T601,
}
impl Default for SampleTime {
fn default() -> Self {
SampleTime::T1
}
}
impl SampleTime {
fn bitcode(&self) -> u8 {
match self {
SampleTime::T1 => 0b000,
SampleTime::T2 => 0b001,
SampleTime::T4 => 0b010,
SampleTime::T7 => 0b011,
SampleTime::T19 => 0b100,
SampleTime::T61 => 0b101,
SampleTime::T181 => 0b110,
SampleTime::T601 => 0b111,
}
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum OperationMode {
OneShot,
}
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum ClockMode {
ASYNC = 0b00,
SyncDiv1 = 0b01,
SyncDiv2 = 0b10,
SyncDiv4 = 0b11,
}
impl Default for ClockMode {
fn default() -> Self {
Self::SyncDiv2
}
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Align {
Right = 0,
Left = 1,
}
impl Default for Align {
fn default() -> Self {
Align::Right
}
}
macro_rules! hal {
($ADC:ident, $ADC_COMMON:ident, $adc:ident, $adc_num:expr) => {
impl Adc<$ADC> {
paste! {
pub fn [<new_ $adc _unchecked>]<C: ClockCfg>(
regs: $ADC,
adc_common : &mut $ADC_COMMON,
ckmode: ClockMode,
clocks: &C,
rcc: &mut RCC,
) -> Self {
let mut this_adc = Self {
regs,
ckmode,
operation_mode: None,
};
if !(this_adc.clocks_welldefined(clocks)) {
panic!("Clock settings not well defined");
}
if !(this_adc.enable_clock(adc_common, rcc)){
panic!("Clock already enabled with a different setting");
}
this_adc.set_align(Align::default());
asm::delay(ckmode as u32 * 4);
this_adc.enable();
this_adc
}
}
fn enable_clock(&self, common_regs: &mut $ADC_COMMON, rcc: &mut RCC) -> bool {
cfg_if::cfg_if! {
if #[cfg(any(feature = "f3"))] {
match $adc_num {
AdcNum::One | AdcNum::Two => {
#[cfg(any(feature = "f301"))]
if rcc.ahbenr.read().adc1en().is_enabled() {
return (common_regs.ccr.read().ckmode().bits() == self.ckmode as u8);
}
#[cfg(any(feature = "f301"))]
rcc.ahbenr.modify(|_, w| w.adc1en().set_bit());
#[cfg(not(any(feature = "f301")))]
if rcc.ahbenr.read().adc12en().is_enabled() {
return (common_regs.ccr.read().ckmode().bits() == self.ckmode as u8);
}
#[cfg(not(any(feature = "f301")))]
rcc.ahbenr.modify(|_, w| w.adc12en().set_bit());
}
AdcNum::Three | AdcNum::Four => {
#[cfg(not(any(feature = "f301", feature = "f302")))]
if rcc.ahbenr.read().adc34en().is_enabled() {
return (common_regs.ccr.read().ckmode().bits() == self.ckmode as u8);
}
#[cfg(not(any(feature = "f301", feature = "f302")))]
rcc.ahbenr.modify(|_, w| w.adc34en().set_bit());
}
}
} else {
if rcc.ahb2enr.read().adcen().bit_is_set() {
return (common_regs.ccr.read().ckmode().bits() == self.ckmode as u8);
}
rcc.ahb2enr.modify(|_, w| w.adcen().set_bit());
}
}
common_regs.ccr.modify(|_, w| unsafe { w
.ckmode().bits(self.ckmode as u8)
});
true
}
fn clocks_welldefined<C: ClockCfg>(&self, clocks: &C) -> bool {
if (self.ckmode == ClockMode::SyncDiv1) {
clocks.hclk() == clocks.sysclk()
} else {
true
}
}
pub fn setup_oneshot(&mut self) {
self.regs.cr.modify(|_, w| w.adstp().set_bit());
self.regs.isr.modify(|_, w| w.ovr().clear_bit());
self.regs.cfgr.modify(|_, w| w
.cont().clear_bit()
.ovrmod().clear_bit()
);
self.set_sequence_len(1);
self.operation_mode = Some(OperationMode::OneShot);
}
fn set_sequence_len(&mut self, len: u8) {
if len - 1 >= 16 {
panic!("ADC sequence length must be in 1..=16")
}
cfg_if::cfg_if! {
if #[cfg(any(feature = "l4x1", feature = "l4x2", feature = "l4x3", feature = "l4x5"))] {
self.regs.sqr1.modify(|_, w| unsafe { w.l3().bits(len - 1) });
} else {
self.regs.sqr1.modify(|_, w| unsafe { w.l().bits(len - 1) });
}
}
}
fn set_align(&self, align: Align) {
self.regs.cfgr.modify(|_, w| w.align().bit(align as u8 != 0));
}
fn enable(&mut self) {
self.regs.cr.modify(|_, w| w.aden().set_bit());
while self.regs.isr.read().adrdy().bit_is_clear() {}
}
fn disable(&mut self) {
self.regs.cr.modify(|_, w| w.addis().set_bit());
}
fn calibrate<C: ClockCfg>(&mut self, clocks: &C) {
let enabled;
cfg_if::cfg_if! {
if #[cfg(feature = "f3")] {
enabled = self.regs.cr.read().advregen().bits() == 1;
} else {
enabled = self.regs.cr.read().advregen().bit_is_set();
}
}
if !enabled {
self.advregen_enable();
self.wait_advregen_startup(clocks);
}
self.disable();
self.regs.cr.modify(|_, w| w
.adcaldif().clear_bit()
.adcal().set_bit());
while self.regs.cr.read().adcal().bit_is_set() {}
}
fn advregen_enable(&mut self){
cfg_if::cfg_if! {
if #[cfg(feature = "f3")] {
self.regs.cr.modify(|_, w| w.advregen().intermediate());
self.regs.cr.modify(|_, w| w.advregen().enabled());
} else {
self.regs.cr.modify(|_, w| w.advregen().set_bit());
}
}
}
fn wait_advregen_startup<C: ClockCfg>(&self, clocks: &C) {
let mut delay = (MAX_ADVREGEN_STARTUP_US * 1_000_000) / clocks.sysclk();
if delay < 2 {
delay = 2;
}
asm::delay(delay);
}
fn convert_one(&mut self, chan: u8) -> u16 {
self.ensure_oneshot();
self.set_chan_smps(chan, SampleTime::default());
self.select_single_chan(chan);
self.regs.cr.modify(|_, w| w.adstart().set_bit());
while self.regs.isr.read().eos().bit_is_clear() {}
self.regs.isr.modify(|_, w| w.eos().set_bit());
return self.regs.dr.read().bits() as u16;
}
fn ensure_oneshot(&mut self) {
if self.operation_mode != Some(OperationMode::OneShot) {
self.setup_oneshot();
}
}
fn select_single_chan(&self, chan: u8) {
self.regs.sqr1.modify(|_, w|
unsafe { w.sq1().bits(chan) }
);
}
fn set_chan_smps(&self, chan: u8, smp: SampleTime) {
unsafe {
match chan {
1 => self.regs.smpr1.modify(|_, w| w.smp1().bits(smp.bitcode())),
2 => self.regs.smpr1.modify(|_, w| w.smp2().bits(smp.bitcode())),
3 => self.regs.smpr1.modify(|_, w| w.smp3().bits(smp.bitcode())),
4 => self.regs.smpr1.modify(|_, w| w.smp4().bits(smp.bitcode())),
5 => self.regs.smpr1.modify(|_, w| w.smp5().bits(smp.bitcode())),
6 => self.regs.smpr1.modify(|_, w| w.smp6().bits(smp.bitcode())),
7 => self.regs.smpr1.modify(|_, w| w.smp7().bits(smp.bitcode())),
8 => self.regs.smpr1.modify(|_, w| w.smp8().bits(smp.bitcode())),
9 => self.regs.smpr1.modify(|_, w| w.smp9().bits(smp.bitcode())),
11 => self.regs.smpr2.modify(|_, w| w.smp10().bits(smp.bitcode())),
12 => self.regs.smpr2.modify(|_, w| w.smp12().bits(smp.bitcode())),
13 => self.regs.smpr2.modify(|_, w| w.smp13().bits(smp.bitcode())),
14 => self.regs.smpr2.modify(|_, w| w.smp14().bits(smp.bitcode())),
15 => self.regs.smpr2.modify(|_, w| w.smp15().bits(smp.bitcode())),
16 => self.regs.smpr2.modify(|_, w| w.smp16().bits(smp.bitcode())),
17 => self.regs.smpr2.modify(|_, w| w.smp17().bits(smp.bitcode())),
18 => self.regs.smpr2.modify(|_, w| w.smp18().bits(smp.bitcode())),
_ => unreachable!(),
};
}
}
}
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_one(PIN::channel());
return Ok(res.into());
}
}
impl Channel<$ADC> for AdcChannel::C1 {
type ID = u8;
fn channel() -> u8 { 1 }
}
impl Channel<$ADC> for AdcChannel::C2 {
type ID = u8;
fn channel() -> u8 { 2 }
}
impl Channel<$ADC> for AdcChannel::C3 {
type ID = u8;
fn channel() -> u8 { 3}
}
impl Channel<$ADC> for AdcChannel::C4 {
type ID = u8;
fn channel() -> u8 { 4 }
}
impl Channel<$ADC> for AdcChannel::C5 {
type ID = u8;
fn channel() -> u8 { 5 }
}
impl Channel<$ADC> for AdcChannel::C6 {
type ID = u8;
fn channel() -> u8 { 6 }
}
impl Channel<$ADC> for AdcChannel::C7 {
type ID = u8;
fn channel() -> u8 { 7 }
}
impl Channel<$ADC> for AdcChannel::C8 {
type ID = u8;
fn channel() -> u8 { 8 }
}
impl Channel<$ADC> for AdcChannel::C9 {
type ID = u8;
fn channel() -> u8 { 9 }
}
impl Channel<$ADC> for AdcChannel::C10 {
type ID = u8;
fn channel() -> u8 { 10 }
}
impl Channel<$ADC> for AdcChannel::C11 {
type ID = u8;
fn channel() -> u8 { 11 }
}
impl Channel<$ADC> for AdcChannel::C12 {
type ID = u8;
fn channel() -> u8 { 12 }
}
impl Channel<$ADC> for AdcChannel::C13 {
type ID = u8;
fn channel() -> u8 { 13 }
}
impl Channel<$ADC> for AdcChannel::C14 {
type ID = u8;
fn channel() -> u8 { 14 }
}
impl Channel<$ADC> for AdcChannel::C15 {
type ID = u8;
fn channel() -> u8 { 15 }
}
impl Channel<$ADC> for AdcChannel::C16 {
type ID = u8;
fn channel() -> u8 { 16 }
}
impl Channel<$ADC> for AdcChannel::C17 {
type ID = u8;
fn channel() -> u8 { 17 }
}
impl Channel<$ADC> for AdcChannel::C18 {
type ID = u8;
fn channel() -> u8 { 18 }
}
}
}
#[cfg(any(feature = "f301", feature = "f302", feature = "f303",))]
hal!(ADC1, ADC1_2, adc1, AdcNum::One);
#[cfg(any(feature = "f302", feature = "f303",))]
hal!(ADC2, ADC1_2, adc2, AdcNum::Two);
#[cfg(any(feature = "f303"))]
hal!(ADC3, ADC3_4, adc3, AdcNum::Three);
#[cfg(any(feature = "f303"))]
hal!(ADC4, ADC3_4, adc4, AdcNum::Four);
#[cfg(any(
feature = "l4x1",
feature = "l4x2",
feature = "l4x3",
feature = "l4x5",
feature = "l4x6",
))]
hal!(ADC1, ADC_COMMON, adc1, AdcNum::One);
#[cfg(any(feature = "l4x1", feature = "l4x2", feature = "l4x5", feature = "l4x6",))]
hal!(ADC2, ADC_COMMON, adc2, AdcNum::Two);
#[cfg(any(feature = "l4x5", feature = "l4x6",))]
hal!(ADC3, ADC_COMMON, adc3, AdcNum::Three);
cfg_if::cfg_if! {
if #[cfg(any(
feature = "l5",
))] {
hal!(ADC, ADC_COMMON, adc, AdcNum:One);
}
}
#[cfg(any(
feature = "h743",
feature = "h743v",
feature = "h747cm4",
feature = "h747cm7",
feature = "h753",
feature = "h753v",
feature = "h7b3",
))]
hal!(ADC1, ADC1, adc1, AdcNum::One);