Merge pull request #2246 from CaptainMaso/adc_f3_v1_1
stm32: add ADC f3_v1_1
This commit is contained in:
commit
a9ec623622
14 changed files with 572 additions and 32 deletions
|
@ -58,7 +58,7 @@ rand_core = "0.6.3"
|
||||||
sdio-host = "0.5.0"
|
sdio-host = "0.5.0"
|
||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7117ad49c06fa00c388130a34977e029910083bd" }
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-019a5da1c47c092c199bc39a7f84fb444f2adcdf" }
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
|
@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7117ad49c06fa00c388130a34977e029910083bd", default-features = false, features = ["metadata"]}
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-019a5da1c47c092c199bc39a7f84fb444f2adcdf", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -930,6 +930,10 @@ fn main() {
|
||||||
} else if pin.signal.starts_with("INN") {
|
} else if pin.signal.starts_with("INN") {
|
||||||
// TODO handle in the future when embassy supports differential measurements
|
// TODO handle in the future when embassy supports differential measurements
|
||||||
None
|
None
|
||||||
|
} else if pin.signal.starts_with("IN") && pin.signal.ends_with("b") {
|
||||||
|
// we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63
|
||||||
|
let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix("b").unwrap();
|
||||||
|
Some(32u8 + signal.parse::<u8>().unwrap())
|
||||||
} else if pin.signal.starts_with("IN") {
|
} else if pin.signal.starts_with("IN") {
|
||||||
Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap())
|
Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -148,7 +148,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||||
reg.set_cont(false);
|
reg.set_cont(false);
|
||||||
reg.set_exttrig(true);
|
reg.set_exttrig(true);
|
||||||
reg.set_swstart(false);
|
reg.set_swstart(false);
|
||||||
reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART);
|
reg.set_extsel(7); // SWSTART
|
||||||
});
|
});
|
||||||
|
|
||||||
// Configure the channel to sample
|
// Configure the channel to sample
|
||||||
|
|
413
embassy-stm32/src/adc/f3_v1_1.rs
Normal file
413
embassy-stm32/src/adc/f3_v1_1.rs
Normal file
|
@ -0,0 +1,413 @@
|
||||||
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_futures::yield_now;
|
||||||
|
use embassy_hal_internal::into_ref;
|
||||||
|
use embassy_time::Instant;
|
||||||
|
|
||||||
|
use super::Resolution;
|
||||||
|
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||||
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
|
use crate::time::Hertz;
|
||||||
|
use crate::{interrupt, Peripheral};
|
||||||
|
|
||||||
|
const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ;
|
||||||
|
|
||||||
|
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||||
|
pub const ADC_MAX: u32 = (1 << 12) - 1;
|
||||||
|
pub const VREF_INT: u32 = 1230;
|
||||||
|
|
||||||
|
pub enum AdcPowerMode {
|
||||||
|
AlwaysOn,
|
||||||
|
DelayOff,
|
||||||
|
IdleOff,
|
||||||
|
DelayIdleOff,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Prescaler {
|
||||||
|
Div1,
|
||||||
|
Div2,
|
||||||
|
Div3,
|
||||||
|
Div4,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupt handler.
|
||||||
|
pub struct InterruptHandler<T: Instance> {
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
if T::regs().sr().read().eoc() {
|
||||||
|
T::regs().cr1().modify(|w| w.set_eocie(false));
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
T::state().waker.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_vref<T: Instance>(op: i8) {
|
||||||
|
static VREF_STATUS: core::sync::atomic::AtomicU8 = core::sync::atomic::AtomicU8::new(0);
|
||||||
|
|
||||||
|
if op > 0 {
|
||||||
|
if VREF_STATUS.fetch_add(1, core::sync::atomic::Ordering::SeqCst) == 0 {
|
||||||
|
T::regs().ccr().modify(|w| w.set_tsvrefe(true));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if VREF_STATUS.fetch_sub(1, core::sync::atomic::Ordering::SeqCst) == 1 {
|
||||||
|
T::regs().ccr().modify(|w| w.set_tsvrefe(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Vref<T: Instance>(core::marker::PhantomData<T>);
|
||||||
|
impl<T: Instance> AdcPin<T> for Vref<T> {}
|
||||||
|
impl<T: Instance> super::sealed::AdcPin<T> for Vref<T> {
|
||||||
|
fn channel(&self) -> u8 {
|
||||||
|
17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> Vref<T> {
|
||||||
|
/// The value that vref would be if vdda was at 3000mv
|
||||||
|
pub fn calibrated_value(&self) -> u16 {
|
||||||
|
crate::pac::VREFINTCAL.data().read().value()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration {
|
||||||
|
let vref_val = adc.read(self).await;
|
||||||
|
Calibration {
|
||||||
|
vref_cal: self.calibrated_value(),
|
||||||
|
vref_val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Calibration {
|
||||||
|
vref_cal: u16,
|
||||||
|
vref_val: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Calibration {
|
||||||
|
/// The millivolts that the calibration value was measured at
|
||||||
|
pub const CALIBRATION_UV: u32 = 3_000_000;
|
||||||
|
|
||||||
|
/// Returns the measured VddA in microvolts (uV)
|
||||||
|
pub fn vdda_uv(&self) -> u32 {
|
||||||
|
(Self::CALIBRATION_UV * self.vref_cal as u32) / self.vref_val as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the measured VddA as an f32
|
||||||
|
pub fn vdda_f32(&self) -> f32 {
|
||||||
|
(Self::CALIBRATION_UV as f32 / 1_000.0) * (self.vref_cal as f32 / self.vref_val as f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a calibrated voltage value as in microvolts (uV)
|
||||||
|
pub fn cal_uv(&self, raw: u16, resolution: super::Resolution) -> u32 {
|
||||||
|
(self.vdda_uv() / resolution.to_max_count()) * raw as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a calibrated voltage value as an f32
|
||||||
|
pub fn cal_f32(&self, raw: u16, resolution: super::Resolution) -> f32 {
|
||||||
|
raw as f32 * self.vdda_f32() / resolution.to_max_count() as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> Drop for Vref<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
update_vref::<T>(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Temperature<T: Instance>(core::marker::PhantomData<T>);
|
||||||
|
impl<T: Instance> AdcPin<T> for Temperature<T> {}
|
||||||
|
impl<T: Instance> super::sealed::AdcPin<T> for Temperature<T> {
|
||||||
|
fn channel(&self) -> u8 {
|
||||||
|
16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> Drop for Temperature<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
update_vref::<T>(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> Adc<'d, T> {
|
||||||
|
pub fn new(
|
||||||
|
adc: impl Peripheral<P = T> + 'd,
|
||||||
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(adc);
|
||||||
|
|
||||||
|
T::enable_and_reset();
|
||||||
|
|
||||||
|
//let r = T::regs();
|
||||||
|
//r.cr2().write(|w| w.set_align(true));
|
||||||
|
|
||||||
|
T::Interrupt::unpend();
|
||||||
|
unsafe {
|
||||||
|
T::Interrupt::enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { adc }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn freq() -> Hertz {
|
||||||
|
let div = T::regs().ccr().read().adcpre() + 1;
|
||||||
|
ADC_FREQ / div as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_resolution(&mut self, res: Resolution) {
|
||||||
|
let was_on = Self::is_on();
|
||||||
|
if was_on {
|
||||||
|
self.stop_adc().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
T::regs().cr1().modify(|w| w.set_res(res.into()));
|
||||||
|
|
||||||
|
if was_on {
|
||||||
|
self.start_adc().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolution(&self) -> Resolution {
|
||||||
|
match T::regs().cr1().read().res() {
|
||||||
|
crate::pac::adc::vals::Res::TWELVEBIT => Resolution::TwelveBit,
|
||||||
|
crate::pac::adc::vals::Res::TENBIT => Resolution::TenBit,
|
||||||
|
crate::pac::adc::vals::Res::EIGHTBIT => Resolution::EightBit,
|
||||||
|
crate::pac::adc::vals::Res::SIXBIT => Resolution::SixBit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_vref(&self) -> Vref<T> {
|
||||||
|
update_vref::<T>(1);
|
||||||
|
|
||||||
|
Vref(core::marker::PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_temperature(&self) -> Temperature<T> {
|
||||||
|
T::regs().ccr().modify(|w| w.set_tsvrefe(true));
|
||||||
|
|
||||||
|
Temperature::<T>(core::marker::PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform a single conversion.
|
||||||
|
async fn convert(&mut self) -> u16 {
|
||||||
|
let was_on = Self::is_on();
|
||||||
|
|
||||||
|
if !was_on {
|
||||||
|
self.start_adc().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.wait_sample_ready().await;
|
||||||
|
|
||||||
|
T::regs().sr().write(|_| {});
|
||||||
|
T::regs().cr1().modify(|w| {
|
||||||
|
w.set_eocie(true);
|
||||||
|
w.set_scan(false);
|
||||||
|
});
|
||||||
|
T::regs().cr2().modify(|w| {
|
||||||
|
w.set_swstart(true);
|
||||||
|
w.set_cont(false);
|
||||||
|
}); // swstart cleared by HW
|
||||||
|
|
||||||
|
let res = poll_fn(|cx| {
|
||||||
|
T::state().waker.register(cx.waker());
|
||||||
|
|
||||||
|
if T::regs().sr().read().eoc() {
|
||||||
|
let res = T::regs().dr().read().rdata();
|
||||||
|
Poll::Ready(res)
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if !was_on {
|
||||||
|
self.stop_adc().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn is_on() -> bool {
|
||||||
|
T::regs().sr().read().adons() || T::regs().cr2().read().adon()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn start_adc(&self) {
|
||||||
|
//defmt::trace!("Turn ADC on");
|
||||||
|
T::regs().cr2().modify(|w| w.set_adon(true));
|
||||||
|
//defmt::trace!("Waiting for ADC to turn on");
|
||||||
|
|
||||||
|
let mut t = Instant::now();
|
||||||
|
|
||||||
|
while !T::regs().sr().read().adons() {
|
||||||
|
yield_now().await;
|
||||||
|
if t.elapsed() > embassy_time::Duration::from_millis(1000) {
|
||||||
|
t = Instant::now();
|
||||||
|
//defmt::trace!("ADC still not on");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//defmt::trace!("ADC on");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn stop_adc(&self) {
|
||||||
|
if T::regs().cr2().read().adon() {
|
||||||
|
//defmt::trace!("ADC should be on, wait for it to start");
|
||||||
|
while !T::regs().csr().read().adons1() {
|
||||||
|
yield_now().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//defmt::trace!("Turn ADC off");
|
||||||
|
|
||||||
|
T::regs().cr2().modify(|w| w.set_adon(false));
|
||||||
|
|
||||||
|
//defmt::trace!("Waiting for ADC to turn off");
|
||||||
|
|
||||||
|
while T::regs().csr().read().adons1() {
|
||||||
|
yield_now().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||||
|
self.set_sample_sequence(&[pin.channel()]).await;
|
||||||
|
self.convert().await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_sample_ready(&self) {
|
||||||
|
//trace!("Waiting for sample channel to be ready");
|
||||||
|
while T::regs().sr().read().rcnr() {
|
||||||
|
yield_now().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_sample_time(&mut self, pin: &mut impl AdcPin<T>, sample_time: SampleTime) {
|
||||||
|
if Self::get_channel_sample_time(pin.channel()) != sample_time {
|
||||||
|
self.stop_adc().await;
|
||||||
|
unsafe {
|
||||||
|
Self::set_channel_sample_time(pin.channel(), sample_time);
|
||||||
|
}
|
||||||
|
self.start_adc().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_sample_time(&self, pin: &impl AdcPin<T>) -> SampleTime {
|
||||||
|
Self::get_channel_sample_time(pin.channel())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the channel sample time
|
||||||
|
///
|
||||||
|
/// ## SAFETY:
|
||||||
|
/// - ADON == 0 i.e ADC must not be enabled when this is called.
|
||||||
|
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||||
|
let sample_time = sample_time.into();
|
||||||
|
|
||||||
|
match ch {
|
||||||
|
0..=9 => T::regs().smpr3().modify(|reg| reg.set_smp(ch as _, sample_time)),
|
||||||
|
10..=19 => T::regs()
|
||||||
|
.smpr2()
|
||||||
|
.modify(|reg| reg.set_smp(ch as usize - 10, sample_time)),
|
||||||
|
20..=29 => T::regs()
|
||||||
|
.smpr1()
|
||||||
|
.modify(|reg| reg.set_smp(ch as usize - 20, sample_time)),
|
||||||
|
30..=31 => T::regs()
|
||||||
|
.smpr0()
|
||||||
|
.modify(|reg| reg.set_smp(ch as usize - 30, sample_time)),
|
||||||
|
_ => panic!("Invalid channel to sample"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_channel_sample_time(ch: u8) -> SampleTime {
|
||||||
|
match ch {
|
||||||
|
0..=9 => T::regs().smpr3().read().smp(ch as _),
|
||||||
|
10..=19 => T::regs().smpr2().read().smp(ch as usize - 10),
|
||||||
|
20..=29 => T::regs().smpr1().read().smp(ch as usize - 20),
|
||||||
|
30..=31 => T::regs().smpr0().read().smp(ch as usize - 30),
|
||||||
|
_ => panic!("Invalid channel to sample"),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the sequence to sample the ADC. Must be less than 28 elements.
|
||||||
|
async fn set_sample_sequence(&self, sequence: &[u8]) {
|
||||||
|
assert!(sequence.len() <= 28);
|
||||||
|
let mut iter = sequence.iter();
|
||||||
|
T::regs().sqr1().modify(|w| w.set_l((sequence.len() - 1) as _));
|
||||||
|
for (idx, ch) in iter.by_ref().take(6).enumerate() {
|
||||||
|
T::regs().sqr5().modify(|w| w.set_sq(idx, *ch));
|
||||||
|
}
|
||||||
|
for (idx, ch) in iter.by_ref().take(6).enumerate() {
|
||||||
|
T::regs().sqr4().modify(|w| w.set_sq(idx, *ch));
|
||||||
|
}
|
||||||
|
for (idx, ch) in iter.by_ref().take(6).enumerate() {
|
||||||
|
T::regs().sqr3().modify(|w| w.set_sq(idx, *ch));
|
||||||
|
}
|
||||||
|
for (idx, ch) in iter.by_ref().take(6).enumerate() {
|
||||||
|
T::regs().sqr2().modify(|w| w.set_sq(idx, *ch));
|
||||||
|
}
|
||||||
|
for (idx, ch) in iter.by_ref().take(4).enumerate() {
|
||||||
|
T::regs().sqr1().modify(|w| w.set_sq(idx, *ch));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_res_clks(res: Resolution) -> u32 {
|
||||||
|
match res {
|
||||||
|
Resolution::TwelveBit => 12,
|
||||||
|
Resolution::TenBit => 11,
|
||||||
|
Resolution::EightBit => 9,
|
||||||
|
Resolution::SixBit => 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_sample_time_clks(sample_time: SampleTime) -> u32 {
|
||||||
|
match sample_time {
|
||||||
|
SampleTime::Cycles4 => 4,
|
||||||
|
SampleTime::Cycles9 => 9,
|
||||||
|
SampleTime::Cycles16 => 16,
|
||||||
|
SampleTime::Cycles24 => 24,
|
||||||
|
SampleTime::Cycles48 => 48,
|
||||||
|
SampleTime::Cycles96 => 96,
|
||||||
|
SampleTime::Cycles192 => 192,
|
||||||
|
SampleTime::Cycles384 => 384,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
|
||||||
|
let res_clks = Self::get_res_clks(self.resolution());
|
||||||
|
let us_clks = us * Self::freq().0 / 1_000_000;
|
||||||
|
let clks = us_clks.saturating_sub(res_clks);
|
||||||
|
match clks {
|
||||||
|
0..=4 => SampleTime::Cycles4,
|
||||||
|
5..=9 => SampleTime::Cycles9,
|
||||||
|
10..=16 => SampleTime::Cycles16,
|
||||||
|
17..=24 => SampleTime::Cycles24,
|
||||||
|
25..=48 => SampleTime::Cycles48,
|
||||||
|
49..=96 => SampleTime::Cycles96,
|
||||||
|
97..=192 => SampleTime::Cycles192,
|
||||||
|
193.. => SampleTime::Cycles384,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn us_for_cfg(&self, res: Resolution, sample_time: SampleTime) -> u32 {
|
||||||
|
let res_clks = Self::get_res_clks(res);
|
||||||
|
let sample_clks = Self::get_sample_time_clks(sample_time);
|
||||||
|
(res_clks + sample_clks) * 1_000_000 / Self::freq().0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
while !T::regs().sr().read().adons() {}
|
||||||
|
|
||||||
|
T::regs().cr2().modify(|w| w.set_adon(false));
|
||||||
|
|
||||||
|
T::disable();
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#[cfg(not(adc_f3_v2))]
|
#[cfg(not(adc_f3_v2))]
|
||||||
#[cfg_attr(adc_f1, path = "f1.rs")]
|
#[cfg_attr(adc_f1, path = "f1.rs")]
|
||||||
#[cfg_attr(adc_f3, path = "f3.rs")]
|
#[cfg_attr(adc_f3, path = "f3.rs")]
|
||||||
|
#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
|
||||||
#[cfg_attr(adc_v1, path = "v1.rs")]
|
#[cfg_attr(adc_v1, path = "v1.rs")]
|
||||||
#[cfg_attr(adc_v2, path = "v2.rs")]
|
#[cfg_attr(adc_v2, path = "v2.rs")]
|
||||||
#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
|
#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
|
||||||
|
@ -26,20 +27,20 @@ use crate::peripherals;
|
||||||
pub struct Adc<'d, T: Instance> {
|
pub struct Adc<'d, T: Instance> {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
adc: crate::PeripheralRef<'d, T>,
|
adc: crate::PeripheralRef<'d, T>,
|
||||||
#[cfg(not(adc_f3_v2))]
|
#[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))]
|
||||||
sample_time: SampleTime,
|
sample_time: SampleTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub waker: AtomicWaker,
|
pub waker: AtomicWaker,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
|
||||||
impl State {
|
impl State {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -54,11 +55,11 @@ pub(crate) mod sealed {
|
||||||
|
|
||||||
pub trait Instance: InterruptableInstance {
|
pub trait Instance: InterruptableInstance {
|
||||||
fn regs() -> crate::pac::adc::Adc;
|
fn regs() -> crate::pac::adc::Adc;
|
||||||
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
|
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
|
||||||
fn common_regs() -> crate::pac::adccommon::AdcCommon;
|
fn common_regs() -> crate::pac::adccommon::AdcCommon;
|
||||||
#[cfg(adc_f3)]
|
#[cfg(adc_f3)]
|
||||||
fn frequency() -> crate::time::Hertz;
|
fn frequency() -> crate::time::Hertz;
|
||||||
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
|
||||||
fn state() -> &'static State;
|
fn state() -> &'static State;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,9 +75,9 @@ pub(crate) mod sealed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0)))]
|
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))]
|
||||||
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
|
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
|
||||||
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0))]
|
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))]
|
||||||
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
|
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
|
||||||
|
|
||||||
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
|
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
|
||||||
|
@ -89,7 +90,7 @@ foreach_adc!(
|
||||||
crate::pac::$inst
|
crate::pac::$inst
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
|
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
|
||||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||||
return crate::pac::$common_inst
|
return crate::pac::$common_inst
|
||||||
}
|
}
|
||||||
|
@ -99,7 +100,7 @@ foreach_adc!(
|
||||||
unsafe { crate::rcc::get_freqs() }.$clock.unwrap()
|
unsafe { crate::rcc::get_freqs() }.$clock.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
|
||||||
fn state() -> &'static sealed::State {
|
fn state() -> &'static sealed::State {
|
||||||
static STATE: sealed::State = sealed::State::new();
|
static STATE: sealed::State = sealed::State::new();
|
||||||
&STATE
|
&STATE
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
|
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum Resolution {
|
pub enum Resolution {
|
||||||
TwelveBit,
|
TwelveBit,
|
||||||
TenBit,
|
TenBit,
|
||||||
|
@ -9,6 +10,7 @@ pub enum Resolution {
|
||||||
|
|
||||||
#[cfg(adc_v4)]
|
#[cfg(adc_v4)]
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum Resolution {
|
pub enum Resolution {
|
||||||
SixteenBit,
|
SixteenBit,
|
||||||
FourteenBit,
|
FourteenBit,
|
||||||
|
@ -19,7 +21,7 @@ pub enum Resolution {
|
||||||
|
|
||||||
impl Default for Resolution {
|
impl Default for Resolution {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
|
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
|
||||||
{
|
{
|
||||||
Self::TwelveBit
|
Self::TwelveBit
|
||||||
}
|
}
|
||||||
|
@ -40,7 +42,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
|
||||||
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
|
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
|
||||||
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
|
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
|
||||||
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
|
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
|
||||||
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
|
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
|
||||||
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
|
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +58,7 @@ impl Resolution {
|
||||||
Resolution::TwelveBit => (1 << 12) - 1,
|
Resolution::TwelveBit => (1 << 12) - 1,
|
||||||
Resolution::TenBit => (1 << 10) - 1,
|
Resolution::TenBit => (1 << 10) - 1,
|
||||||
Resolution::EightBit => (1 << 8) - 1,
|
Resolution::EightBit => (1 << 8) - 1,
|
||||||
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
|
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
|
||||||
Resolution::SixBit => (1 << 6) - 1,
|
Resolution::SixBit => (1 << 6) - 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ macro_rules! impl_sample_time {
|
||||||
($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
|
($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
|
||||||
#[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
|
#[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum SampleTime {
|
pub enum SampleTime {
|
||||||
$(
|
$(
|
||||||
#[doc = concat!($doc, " ADC clock cycles.")]
|
#[doc = concat!($doc, " ADC clock cycles.")]
|
||||||
|
@ -18,6 +19,14 @@ macro_rules! impl_sample_time {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<crate::pac::adc::vals::SampleTime> for SampleTime {
|
||||||
|
fn from(sample_time: crate::pac::adc::vals::SampleTime) -> SampleTime {
|
||||||
|
match sample_time {
|
||||||
|
$(crate::pac::adc::vals::SampleTime::$pac_variant => SampleTime::$variant),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for SampleTime {
|
impl Default for SampleTime {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::$default
|
Self::$default
|
||||||
|
@ -121,3 +130,19 @@ impl_sample_time!(
|
||||||
("601.5", Cycles601_5, CYCLES601_5)
|
("601.5", Cycles601_5, CYCLES601_5)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(any(adc_f3_v1_1))]
|
||||||
|
impl_sample_time!(
|
||||||
|
"4",
|
||||||
|
Cycles4,
|
||||||
|
(
|
||||||
|
("4", Cycles4, CYCLES4),
|
||||||
|
("9", Cycles9, CYCLES9),
|
||||||
|
("16", Cycles16, CYCLES16),
|
||||||
|
("24", Cycles24, CYCLES24),
|
||||||
|
("48", Cycles48, CYCLES48),
|
||||||
|
("96", Cycles96, CYCLES96),
|
||||||
|
("192", Cycles192, CYCLES192),
|
||||||
|
("384", Cycles384, CYCLES384)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
#[cfg_attr(can_bxcan, path = "bxcan.rs")]
|
#[cfg_attr(can_bxcan, path = "bxcan.rs")]
|
||||||
#[cfg_attr(can_fdcan, path = "fdcan.rs")]
|
#[cfg_attr(any(can_fdcan_v1, can_fdcan_h7), path = "fdcan.rs")]
|
||||||
mod _version;
|
mod _version;
|
||||||
pub use _version::*;
|
pub use _version::*;
|
||||||
|
|
|
@ -315,6 +315,8 @@ pub(crate) unsafe fn init(config: Config) {
|
||||||
adc: adc12_ck,
|
adc: adc12_ck,
|
||||||
adc34: adc345_ck,
|
adc34: adc345_ck,
|
||||||
pll1_p: None,
|
pll1_p: None,
|
||||||
|
pll1_q: None, // TODO
|
||||||
|
hse: None, // TODO
|
||||||
rtc,
|
rtc,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ pub struct Clocks {
|
||||||
|
|
||||||
#[cfg(any(stm32g4, rcc_l4))]
|
#[cfg(any(stm32g4, rcc_l4))]
|
||||||
pub pll1_p: Option<Hertz>,
|
pub pll1_p: Option<Hertz>,
|
||||||
#[cfg(any(stm32h5, stm32h7, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_l4))]
|
#[cfg(any(stm32h5, stm32h7, stm32f2, stm32f4, stm32f7, rcc_l4, stm32g4))]
|
||||||
pub pll1_q: Option<Hertz>,
|
pub pll1_q: Option<Hertz>,
|
||||||
#[cfg(any(stm32h5, stm32h7))]
|
#[cfg(any(stm32h5, stm32h7))]
|
||||||
pub pll2_p: Option<Hertz>,
|
pub pll2_p: Option<Hertz>,
|
||||||
|
@ -167,7 +167,7 @@ pub struct Clocks {
|
||||||
|
|
||||||
#[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))]
|
#[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))]
|
||||||
pub lse: Option<Hertz>,
|
pub lse: Option<Hertz>,
|
||||||
#[cfg(any(stm32h5, stm32h7))]
|
#[cfg(any(stm32h5, stm32h7, stm32g4))]
|
||||||
pub hse: Option<Hertz>,
|
pub hse: Option<Hertz>,
|
||||||
|
|
||||||
#[cfg(stm32h5)]
|
#[cfg(stm32h5)]
|
||||||
|
|
|
@ -10,14 +10,14 @@ stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"]
|
||||||
stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"]
|
stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"]
|
||||||
stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"]
|
stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"]
|
||||||
stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"]
|
stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"]
|
||||||
stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac-adc-pin", "rng"]
|
stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"]
|
||||||
stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac-adc-pin", "sdmmc"]
|
stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
|
||||||
stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
|
stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
|
||||||
stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac-adc-pin"]
|
stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"]
|
||||||
stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"]
|
stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"]
|
||||||
stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"]
|
stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"]
|
||||||
stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"]
|
stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"]
|
||||||
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac-adc-pin", "rng"]
|
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng"]
|
||||||
stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"]
|
stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"]
|
||||||
stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
|
stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
|
||||||
stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
|
stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
|
||||||
|
@ -41,7 +41,7 @@ ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
|
||||||
mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
|
mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
|
||||||
embassy-stm32-wpan = []
|
embassy-stm32-wpan = []
|
||||||
not-gpdma = []
|
not-gpdma = []
|
||||||
dac-adc-pin = []
|
dac = []
|
||||||
|
|
||||||
cm0 = ["portable-atomic/unsafe-assume-single-core"]
|
cm0 = ["portable-atomic/unsafe-assume-single-core"]
|
||||||
|
|
||||||
|
@ -84,7 +84,12 @@ required-features = [ "can",]
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "dac"
|
name = "dac"
|
||||||
path = "src/bin/dac.rs"
|
path = "src/bin/dac.rs"
|
||||||
required-features = [ "dac-adc-pin",]
|
required-features = [ "dac",]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "dac_l1"
|
||||||
|
path = "src/bin/dac_l1.rs"
|
||||||
|
required-features = [ "stm32l152re",]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "eth"
|
name = "eth"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
// required-features: dac-adc-pin
|
// required-features: dac
|
||||||
|
|
||||||
#[path = "../common.rs"]
|
#[path = "../common.rs"]
|
||||||
mod common;
|
mod common;
|
||||||
|
@ -22,12 +22,13 @@ async fn main(_spawner: Spawner) {
|
||||||
// Initialize the board and obtain a Peripherals instance
|
// Initialize the board and obtain a Peripherals instance
|
||||||
let p: embassy_stm32::Peripherals = embassy_stm32::init(config());
|
let p: embassy_stm32::Peripherals = embassy_stm32::init(config());
|
||||||
|
|
||||||
|
let adc = peri!(p, ADC);
|
||||||
let dac = peri!(p, DAC);
|
let dac = peri!(p, DAC);
|
||||||
let dac_pin = peri!(p, DAC_PIN);
|
let dac_pin = peri!(p, DAC_PIN);
|
||||||
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
|
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
|
||||||
|
|
||||||
let mut dac = DacCh1::new(dac, NoDma, dac_pin);
|
let mut dac = DacCh1::new(dac, NoDma, dac_pin);
|
||||||
let mut adc = Adc::new(p.ADC1, &mut Delay);
|
let mut adc = Adc::new(adc, &mut Delay);
|
||||||
|
|
||||||
#[cfg(feature = "stm32h755zi")]
|
#[cfg(feature = "stm32h755zi")]
|
||||||
let normalization_factor = 256;
|
let normalization_factor = 256;
|
||||||
|
|
86
tests/stm32/src/bin/dac_l1.rs
Normal file
86
tests/stm32/src/bin/dac_l1.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
// required-features: stm32l152re
|
||||||
|
|
||||||
|
#[path = "../common.rs"]
|
||||||
|
mod common;
|
||||||
|
use core::f32::consts::PI;
|
||||||
|
|
||||||
|
use common::*;
|
||||||
|
use defmt::assert;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::adc::Adc;
|
||||||
|
use embassy_stm32::dac::{DacCh1, Value};
|
||||||
|
use embassy_stm32::dma::NoDma;
|
||||||
|
use embassy_stm32::{bind_interrupts, peripherals};
|
||||||
|
use embassy_time::Timer;
|
||||||
|
use micromath::F32Ext;
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
ADC1 => embassy_stm32::adc::InterruptHandler<peripherals::ADC>;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
// Initialize the board and obtain a Peripherals instance
|
||||||
|
let p: embassy_stm32::Peripherals = embassy_stm32::init(config());
|
||||||
|
|
||||||
|
let adc = peri!(p, ADC);
|
||||||
|
let dac = peri!(p, DAC);
|
||||||
|
let dac_pin = peri!(p, DAC_PIN);
|
||||||
|
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
|
||||||
|
|
||||||
|
let mut dac = DacCh1::new(dac, NoDma, dac_pin);
|
||||||
|
let mut adc = Adc::new(adc, Irqs);
|
||||||
|
|
||||||
|
#[cfg(feature = "stm32h755zi")]
|
||||||
|
let normalization_factor = 256;
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "stm32f429zi",
|
||||||
|
feature = "stm32f446re",
|
||||||
|
feature = "stm32g071rb",
|
||||||
|
feature = "stm32l152re",
|
||||||
|
))]
|
||||||
|
let normalization_factor: i32 = 16;
|
||||||
|
|
||||||
|
dac.set(Value::Bit8(0));
|
||||||
|
// Now wait a little to obtain a stable value
|
||||||
|
Timer::after_millis(30).await;
|
||||||
|
let offset = adc.read(&mut adc_pin).await;
|
||||||
|
|
||||||
|
for v in 0..=255 {
|
||||||
|
// First set the DAC output value
|
||||||
|
let dac_output_val = to_sine_wave(v);
|
||||||
|
dac.set(Value::Bit8(dac_output_val));
|
||||||
|
|
||||||
|
// Now wait a little to obtain a stable value
|
||||||
|
Timer::after_millis(30).await;
|
||||||
|
|
||||||
|
// Need to steal the peripherals here because PA4 is obviously in use already
|
||||||
|
let measured = adc.read(&mut unsafe { embassy_stm32::Peripherals::steal() }.PA4).await;
|
||||||
|
// Calibrate and normalize the measurement to get close to the dac_output_val
|
||||||
|
let measured_normalized = ((measured as i32 - offset as i32) / normalization_factor) as i16;
|
||||||
|
|
||||||
|
info!("value / measured: {} / {}", dac_output_val, measured_normalized);
|
||||||
|
|
||||||
|
// The deviations are quite enormous but that does not matter since this is only a quick test
|
||||||
|
assert!((dac_output_val as i16 - measured_normalized).abs() < 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Test OK");
|
||||||
|
cortex_m::asm::bkpt();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_sine_wave(v: u8) -> u8 {
|
||||||
|
if v >= 128 {
|
||||||
|
// top half
|
||||||
|
let r = PI * ((v - 128) as f32 / 128.0);
|
||||||
|
(r.sin() * 128.0 + 127.0) as u8
|
||||||
|
} else {
|
||||||
|
// bottom half
|
||||||
|
let r = PI + PI * (v as f32 / 128.0);
|
||||||
|
(r.sin() * 128.0 + 127.0) as u8
|
||||||
|
}
|
||||||
|
}
|
|
@ -101,14 +101,14 @@ define_peris!(
|
||||||
define_peris!(
|
define_peris!(
|
||||||
UART = USART1, UART_TX = PC4, UART_RX = PC5, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2,
|
UART = USART1, UART_TX = PC4, UART_RX = PC5, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2,
|
||||||
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2,
|
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2,
|
||||||
DAC = DAC1, DAC_PIN = PA4,
|
ADC = ADC1, DAC = DAC1, DAC_PIN = PA4,
|
||||||
@irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
|
@irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
|
||||||
);
|
);
|
||||||
#[cfg(feature = "stm32f429zi")]
|
#[cfg(feature = "stm32f429zi")]
|
||||||
define_peris!(
|
define_peris!(
|
||||||
UART = USART6, UART_TX = PG14, UART_RX = PG9, UART_TX_DMA = DMA2_CH6, UART_RX_DMA = DMA2_CH1,
|
UART = USART6, UART_TX = PG14, UART_RX = PG9, UART_TX_DMA = DMA2_CH6, UART_RX_DMA = DMA2_CH1,
|
||||||
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2,
|
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2,
|
||||||
DAC = DAC, DAC_PIN = PA4,
|
ADC = ADC1, DAC = DAC, DAC_PIN = PA4,
|
||||||
CAN = CAN1, CAN_RX = PD0, CAN_TX = PD1,
|
CAN = CAN1, CAN_RX = PD0, CAN_TX = PD1,
|
||||||
@irq UART = {USART6 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART6>;},
|
@irq UART = {USART6 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART6>;},
|
||||||
);
|
);
|
||||||
|
@ -116,7 +116,7 @@ define_peris!(
|
||||||
define_peris!(
|
define_peris!(
|
||||||
UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA2_CH7, UART_RX_DMA = DMA2_CH5,
|
UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA2_CH7, UART_RX_DMA = DMA2_CH5,
|
||||||
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2,
|
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2,
|
||||||
DAC = DAC, DAC_PIN = PA4,
|
ADC = ADC1, DAC = DAC, DAC_PIN = PA4,
|
||||||
CAN = CAN1, CAN_RX = PA11, CAN_TX = PA12,
|
CAN = CAN1, CAN_RX = PA11, CAN_TX = PA12,
|
||||||
@irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
|
@irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
|
||||||
);
|
);
|
||||||
|
@ -130,7 +130,7 @@ define_peris!(
|
||||||
define_peris!(
|
define_peris!(
|
||||||
UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1,
|
UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1,
|
||||||
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1,
|
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1,
|
||||||
DAC = DAC1, DAC_PIN = PA4,
|
ADC = ADC1, DAC = DAC1, DAC_PIN = PA4,
|
||||||
@irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
|
@irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
|
||||||
);
|
);
|
||||||
#[cfg(feature = "stm32h7a3zi")]
|
#[cfg(feature = "stm32h7a3zi")]
|
||||||
|
@ -191,6 +191,7 @@ define_peris!(
|
||||||
define_peris!(
|
define_peris!(
|
||||||
UART = USART3, UART_TX = PB10, UART_RX = PB11, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3,
|
UART = USART3, UART_TX = PB10, UART_RX = PB11, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3,
|
||||||
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
|
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
|
||||||
|
ADC = ADC, DAC = DAC, DAC_PIN = PA4,
|
||||||
@irq UART = {USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;},
|
@irq UART = {USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;},
|
||||||
);
|
);
|
||||||
#[cfg(feature = "stm32l552ze")]
|
#[cfg(feature = "stm32l552ze")]
|
||||||
|
|
Loading…
Reference in a new issue