commit
d9e2d17625
@ -1 +0,0 @@
|
|||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
#[cfg_attr(adc_v3, path = "v3.rs")]
|
#[cfg_attr(adc_v3, path = "v3.rs")]
|
||||||
#[cfg_attr(adc_g0, path = "g0.rs")]
|
#[cfg_attr(adc_g0, path = "v3.rs")]
|
||||||
mod _version;
|
mod _version;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@ -72,6 +72,9 @@ macro_rules! impl_pin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
crate::pac::peripheral_pins!(
|
crate::pac::peripheral_pins!(
|
||||||
|
($inst:ident, adc, ADC, $pin:ident, IN0) => {
|
||||||
|
impl_pin!($inst, $pin, 0);
|
||||||
|
};
|
||||||
($inst:ident, adc, ADC, $pin:ident, IN1) => {
|
($inst:ident, adc, ADC, $pin:ident, IN1) => {
|
||||||
impl_pin!($inst, $pin, 1);
|
impl_pin!($inst, $pin, 1);
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,17 @@ use embedded_hal::blocking::delay::DelayUs;
|
|||||||
|
|
||||||
pub const VDDA_CALIB_MV: u32 = 3000;
|
pub const VDDA_CALIB_MV: u32 = 3000;
|
||||||
|
|
||||||
|
/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock
|
||||||
|
/// configuration.
|
||||||
|
unsafe fn enable() {
|
||||||
|
#[cfg(rcc_h7)]
|
||||||
|
crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
|
||||||
|
#[cfg(rcc_g0)]
|
||||||
|
crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true));
|
||||||
|
#[cfg(rcc_l4)]
|
||||||
|
crate::pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Resolution {
|
pub enum Resolution {
|
||||||
TwelveBit,
|
TwelveBit,
|
||||||
TenBit,
|
TenBit,
|
||||||
@ -43,7 +54,11 @@ pub struct Vref;
|
|||||||
impl<T: Instance> AdcPin<T> for Vref {}
|
impl<T: Instance> AdcPin<T> for Vref {}
|
||||||
impl<T: Instance> super::sealed::AdcPin<T> for Vref {
|
impl<T: Instance> super::sealed::AdcPin<T> for Vref {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
0
|
#[cfg(not(rcc_g0))]
|
||||||
|
let val = 0;
|
||||||
|
#[cfg(rcc_g0)]
|
||||||
|
let val = 13;
|
||||||
|
val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +66,11 @@ pub struct Temperature;
|
|||||||
impl<T: Instance> AdcPin<T> for Temperature {}
|
impl<T: Instance> AdcPin<T> for Temperature {}
|
||||||
impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
|
impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
17
|
#[cfg(not(rcc_g0))]
|
||||||
|
let val = 17;
|
||||||
|
#[cfg(rcc_g0)]
|
||||||
|
let val = 12;
|
||||||
|
val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,10 +78,16 @@ pub struct Vbat;
|
|||||||
impl<T: Instance> AdcPin<T> for Vbat {}
|
impl<T: Instance> AdcPin<T> for Vbat {}
|
||||||
impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
|
impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
18
|
#[cfg(not(rcc_g0))]
|
||||||
|
let val = 18;
|
||||||
|
#[cfg(rcc_g0)]
|
||||||
|
let val = 14;
|
||||||
|
val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(adc_g0))]
|
||||||
|
mod sample_time {
|
||||||
/// ADC sample time
|
/// ADC sample time
|
||||||
///
|
///
|
||||||
/// The default setting is 2.5 ADC clock cycles.
|
/// The default setting is 2.5 ADC clock cycles.
|
||||||
@ -94,7 +119,7 @@ pub enum SampleTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SampleTime {
|
impl SampleTime {
|
||||||
fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
|
pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
|
||||||
match self {
|
match self {
|
||||||
SampleTime::Cycles2_5 => crate::pac::adc::vals::SampleTime::CYCLES2_5,
|
SampleTime::Cycles2_5 => crate::pac::adc::vals::SampleTime::CYCLES2_5,
|
||||||
SampleTime::Cycles6_5 => crate::pac::adc::vals::SampleTime::CYCLES6_5,
|
SampleTime::Cycles6_5 => crate::pac::adc::vals::SampleTime::CYCLES6_5,
|
||||||
@ -113,6 +138,63 @@ impl Default for SampleTime {
|
|||||||
Self::Cycles2_5
|
Self::Cycles2_5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(adc_g0)]
|
||||||
|
mod sample_time {
|
||||||
|
/// ADC sample time
|
||||||
|
///
|
||||||
|
/// The default setting is 1.5 ADC clock cycles.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
pub enum SampleTime {
|
||||||
|
/// 1.5 ADC clock cycles
|
||||||
|
Cycles1_5 = 0b000,
|
||||||
|
|
||||||
|
/// 3.5 ADC clock cycles
|
||||||
|
Cycles3_5 = 0b001,
|
||||||
|
|
||||||
|
/// 7.5 ADC clock cycles
|
||||||
|
Cycles7_5 = 0b010,
|
||||||
|
|
||||||
|
/// 12.5 ADC clock cycles
|
||||||
|
Cycles12_5 = 0b011,
|
||||||
|
|
||||||
|
/// 19.5 ADC clock cycles
|
||||||
|
Cycles19_5 = 0b100,
|
||||||
|
|
||||||
|
/// 39.5 ADC clock cycles
|
||||||
|
Cycles39_5 = 0b101,
|
||||||
|
|
||||||
|
/// 79.5 ADC clock cycles
|
||||||
|
Cycles79_5 = 0b110,
|
||||||
|
|
||||||
|
/// 160.5 ADC clock cycles
|
||||||
|
Cycles160_5 = 0b111,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SampleTime {
|
||||||
|
pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
|
||||||
|
match self {
|
||||||
|
SampleTime::Cycles1_5 => crate::pac::adc::vals::SampleTime::CYCLES1_5,
|
||||||
|
SampleTime::Cycles3_5 => crate::pac::adc::vals::SampleTime::CYCLES3_5,
|
||||||
|
SampleTime::Cycles7_5 => crate::pac::adc::vals::SampleTime::CYCLES7_5,
|
||||||
|
SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5,
|
||||||
|
SampleTime::Cycles19_5 => crate::pac::adc::vals::SampleTime::CYCLES19_5,
|
||||||
|
SampleTime::Cycles39_5 => crate::pac::adc::vals::SampleTime::CYCLES39_5,
|
||||||
|
SampleTime::Cycles79_5 => crate::pac::adc::vals::SampleTime::CYCLES79_5,
|
||||||
|
SampleTime::Cycles160_5 => crate::pac::adc::vals::SampleTime::CYCLES160_5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SampleTime {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Cycles1_5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use sample_time::SampleTime;
|
||||||
|
|
||||||
pub struct Adc<'d, T: Instance> {
|
pub struct Adc<'d, T: Instance> {
|
||||||
sample_time: SampleTime,
|
sample_time: SampleTime,
|
||||||
@ -125,15 +207,26 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
pub fn new(_peri: impl Unborrow<Target = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
pub fn new(_peri: impl Unborrow<Target = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||||
unborrow!(_peri);
|
unborrow!(_peri);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
enable();
|
||||||
T::regs().cr().modify(|reg| {
|
T::regs().cr().modify(|reg| {
|
||||||
|
#[cfg(not(adc_g0))]
|
||||||
reg.set_deeppwd(false);
|
reg.set_deeppwd(false);
|
||||||
reg.set_advregen(true);
|
reg.set_advregen(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[cfg(adc_g0)]
|
||||||
|
T::regs().cfgr1().modify(|reg| {
|
||||||
|
reg.set_chselrmod(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
delay.delay_us(20);
|
delay.delay_us(20);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
T::regs().cr().modify(|reg| {
|
||||||
|
reg.set_adcal(true);
|
||||||
|
});
|
||||||
|
|
||||||
while T::regs().cr().read().adcal() {
|
while T::regs().cr().read().adcal() {
|
||||||
// spin
|
// spin
|
||||||
}
|
}
|
||||||
@ -229,6 +322,27 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// Perform a single conversion.
|
||||||
|
fn convert(&mut self) -> u16 {
|
||||||
|
unsafe {
|
||||||
|
T::regs().isr().modify(|reg| {
|
||||||
|
reg.set_eos(true);
|
||||||
|
reg.set_eoc(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start conversion
|
||||||
|
T::regs().cr().modify(|reg| {
|
||||||
|
reg.set_adstart(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
while !T::regs().isr().read().eos() {
|
||||||
|
// spin
|
||||||
|
}
|
||||||
|
|
||||||
|
T::regs().dr().read().0 as u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Make sure bits are off
|
// Make sure bits are off
|
||||||
@ -249,48 +363,36 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure ADC
|
// Configure ADC
|
||||||
|
#[cfg(not(rcc_g0))]
|
||||||
T::regs()
|
T::regs()
|
||||||
.cfgr()
|
.cfgr()
|
||||||
.modify(|reg| reg.set_res(self.resolution.res()));
|
.modify(|reg| reg.set_res(self.resolution.res()));
|
||||||
|
#[cfg(rcc_g0)]
|
||||||
|
T::regs()
|
||||||
|
.cfgr1()
|
||||||
|
.modify(|reg| reg.set_res(self.resolution.res()));
|
||||||
|
|
||||||
// Configure channel
|
// Configure channel
|
||||||
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
||||||
|
|
||||||
// Select channel
|
// Select channel
|
||||||
|
#[cfg(not(rcc_g0))]
|
||||||
T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
|
T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
|
||||||
|
#[cfg(rcc_g0)]
|
||||||
|
T::regs()
|
||||||
|
.chselr()
|
||||||
|
.write(|reg| reg.set_chsel(pin.channel() as u32));
|
||||||
|
|
||||||
// Start conversion
|
// Some models are affected by an erratum:
|
||||||
T::regs().isr().modify(|reg| {
|
// If we perform conversions slower than 1 kHz, the first read ADC value can be
|
||||||
reg.set_eos(true);
|
// corrupted, so we discard it and measure again.
|
||||||
reg.set_eoc(true);
|
//
|
||||||
});
|
// STM32L471xx: Section 2.7.3
|
||||||
T::regs().cr().modify(|reg| {
|
// STM32G4: Section 2.7.3
|
||||||
reg.set_adstart(true);
|
#[cfg(any(rcc_l4, rcc_g4))]
|
||||||
});
|
let _ = self.convert();
|
||||||
|
|
||||||
while !T::regs().isr().read().eos() {
|
let val = self.convert();
|
||||||
// spin
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read ADC value first time and discard it, as per errata sheet.
|
|
||||||
// The errata states that if we do conversions slower than 1 kHz, the
|
|
||||||
// first read ADC value can be corrupted, so we discard it and measure again.
|
|
||||||
|
|
||||||
let _ = T::regs().dr().read();
|
|
||||||
|
|
||||||
T::regs().isr().modify(|reg| {
|
|
||||||
reg.set_eos(true);
|
|
||||||
reg.set_eoc(true);
|
|
||||||
});
|
|
||||||
T::regs().cr().modify(|reg| {
|
|
||||||
reg.set_adstart(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
while !T::regs().isr().read().eos() {
|
|
||||||
// spin
|
|
||||||
}
|
|
||||||
|
|
||||||
let val = T::regs().dr().read().0 as u16;
|
|
||||||
|
|
||||||
T::regs().cr().modify(|reg| reg.set_addis(true));
|
T::regs().cr().modify(|reg| reg.set_addis(true));
|
||||||
|
|
||||||
@ -298,6 +400,14 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(rcc_g0)]
|
||||||
|
unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
|
||||||
|
T::regs()
|
||||||
|
.smpr()
|
||||||
|
.modify(|reg| reg.set_smp1(sample_time.sample_time()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(rcc_g0))]
|
||||||
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||||
if ch <= 9 {
|
if ch <= 9 {
|
||||||
T::regs()
|
T::regs()
|
||||||
|
@ -5,6 +5,17 @@ use core::marker::PhantomData;
|
|||||||
use embassy::util::Unborrow;
|
use embassy::util::Unborrow;
|
||||||
use embassy_hal_common::unborrow;
|
use embassy_hal_common::unborrow;
|
||||||
|
|
||||||
|
/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent DAC clock
|
||||||
|
/// configuration.
|
||||||
|
unsafe fn enable() {
|
||||||
|
#[cfg(rcc_h7)]
|
||||||
|
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
|
||||||
|
#[cfg(rcc_g0)]
|
||||||
|
crate::pac::RCC.apbenr1().modify(|w| w.set_dac1en(true));
|
||||||
|
#[cfg(rcc_l4)]
|
||||||
|
crate::pac::RCC.apb1enr1().modify(|w| w.set_dac1en(true));
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -91,6 +102,10 @@ impl<'d, T: Instance> Dac<'d, T> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
unborrow!(ch1, ch2);
|
unborrow!(ch1, ch2);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
enable();
|
||||||
|
}
|
||||||
|
|
||||||
let ch1 = ch1.degrade_optional();
|
let ch1 = ch1.degrade_optional();
|
||||||
if ch1.is_some() {
|
if ch1.is_some() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -18,10 +18,37 @@ pub const LSI_FREQ: u32 = 32_000;
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum ClockSrc {
|
pub enum ClockSrc {
|
||||||
HSE(Hertz),
|
HSE(Hertz),
|
||||||
HSI16,
|
HSI16(HSI16Prescaler),
|
||||||
LSI,
|
LSI,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum HSI16Prescaler {
|
||||||
|
NotDivided,
|
||||||
|
Div2,
|
||||||
|
Div4,
|
||||||
|
Div8,
|
||||||
|
Div16,
|
||||||
|
Div32,
|
||||||
|
Div64,
|
||||||
|
Div128,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u8> for HSI16Prescaler {
|
||||||
|
fn into(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
HSI16Prescaler::NotDivided => 0x00,
|
||||||
|
HSI16Prescaler::Div2 => 0x01,
|
||||||
|
HSI16Prescaler::Div4 => 0x02,
|
||||||
|
HSI16Prescaler::Div8 => 0x03,
|
||||||
|
HSI16Prescaler::Div16 => 0x04,
|
||||||
|
HSI16Prescaler::Div32 => 0x05,
|
||||||
|
HSI16Prescaler::Div64 => 0x06,
|
||||||
|
HSI16Prescaler::Div128 => 0x07,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Into<u8> for APBPrescaler {
|
impl Into<u8> for APBPrescaler {
|
||||||
fn into(self) -> u8 {
|
fn into(self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
@ -55,15 +82,17 @@ pub struct Config {
|
|||||||
mux: ClockSrc,
|
mux: ClockSrc,
|
||||||
ahb_pre: AHBPrescaler,
|
ahb_pre: AHBPrescaler,
|
||||||
apb_pre: APBPrescaler,
|
apb_pre: APBPrescaler,
|
||||||
|
low_power_run: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
mux: ClockSrc::HSI16,
|
mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided),
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
ahb_pre: AHBPrescaler::NotDivided,
|
||||||
apb_pre: APBPrescaler::NotDivided,
|
apb_pre: APBPrescaler::NotDivided,
|
||||||
|
low_power_run: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,6 +115,12 @@ impl Config {
|
|||||||
self.apb_pre = pre;
|
self.apb_pre = pre;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn low_power_run(mut self, on: bool) -> Self {
|
||||||
|
self.low_power_run = on;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RCC peripheral
|
/// RCC peripheral
|
||||||
@ -119,14 +154,18 @@ impl RccExt for RCC {
|
|||||||
fn freeze(self, cfgr: Config) -> Clocks {
|
fn freeze(self, cfgr: Config) -> Clocks {
|
||||||
let rcc = pac::RCC;
|
let rcc = pac::RCC;
|
||||||
let (sys_clk, sw) = match cfgr.mux {
|
let (sys_clk, sw) = match cfgr.mux {
|
||||||
ClockSrc::HSI16 => {
|
ClockSrc::HSI16(div) => {
|
||||||
// Enable HSI16
|
// Enable HSI16
|
||||||
|
let div: u8 = div.into();
|
||||||
unsafe {
|
unsafe {
|
||||||
rcc.cr().write(|w| w.set_hsion(true));
|
rcc.cr().write(|w| {
|
||||||
|
w.set_hsidiv(div);
|
||||||
|
w.set_hsion(true)
|
||||||
|
});
|
||||||
while !rcc.cr().read().hsirdy() {}
|
while !rcc.cr().read().hsirdy() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
(HSI_FREQ, 0x00)
|
(HSI_FREQ >> div, 0x00)
|
||||||
}
|
}
|
||||||
ClockSrc::HSE(freq) => {
|
ClockSrc::HSE(freq) => {
|
||||||
// Enable HSE
|
// Enable HSE
|
||||||
@ -174,6 +213,14 @@ impl RccExt for RCC {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let pwr = pac::PWR;
|
||||||
|
if cfgr.low_power_run {
|
||||||
|
assert!(sys_clk.hz() <= 2_000_000.hz());
|
||||||
|
unsafe {
|
||||||
|
pwr.cr1().modify(|w| w.set_lpr(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Clocks {
|
Clocks {
|
||||||
sys: sys_clk.hz(),
|
sys: sys_clk.hz(),
|
||||||
ahb: ahb_freq.hz(),
|
ahb: ahb_freq.hz(),
|
||||||
|
Loading…
Reference in New Issue
Block a user