From eca7ccc63ec3352134085e3d0107a299102a9bf4 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sun, 23 Jan 2022 21:32:05 +0100 Subject: [PATCH 1/4] DAC featrue merged to branche, to separate features. --- .github/workflows/ci_dac.yml | 84 ++++++++++ .github/workflows/clippy_dac.yml | 22 +++ .github/workflows/rustfmt_dac.yml | 23 +++ Cargo.toml | 6 + dac.rs | 267 ++++++++++++++++++++++++++++++ src/lib.rs | 7 + 6 files changed, 409 insertions(+) create mode 100644 .github/workflows/ci_dac.yml create mode 100644 .github/workflows/clippy_dac.yml create mode 100644 .github/workflows/rustfmt_dac.yml create mode 100644 dac.rs diff --git a/.github/workflows/ci_dac.yml b/.github/workflows/ci_dac.yml new file mode 100644 index 00000000..945e2442 --- /dev/null +++ b/.github/workflows/ci_dac.yml @@ -0,0 +1,84 @@ +on: + push: + branches: [DAC] + pull_request: + +name: Continuous integration + +jobs: + ci: + runs-on: ubuntu-latest + strategy: + matrix: # All permutations of {rust, mcu} + rust: + - stable + mcu: + - stm32l412 + - stm32l422 + - stm32l431 + - stm32l432 + - stm32l433 + - stm32l442 + - stm32l443 + - stm32l451 + - stm32l452 + - stm32l462 + - stm32l471 + - stm32l475 + - stm32l476 + - stm32l486 + - stm32l496 + - stm32l4a6 + #- stm32l4r9 + #- stm32l4s9 + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: thumbv7em-none-eabihf + override: true + - name: build + uses: actions-rs/cargo@v1 + with: + use-cross: true + command: build + args: --verbose --release --examples --target thumbv7em-none-eabihf --features rt,unproven,${{ matrix.mcu }} + - name: test + uses: actions-rs/cargo@v1 + with: + command: test + args: --lib --target x86_64-unknown-linux-gnu --features rt,unproven,${{ matrix.mcu }} + + ci-r9: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + mcu: + - stm32l4r9 + - stm32l4s9 + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: thumbv7em-none-eabihf + override: true + - name: build + uses: actions-rs/cargo@v1 + with: + use-cross: true + command: build + args: --verbose --release --target thumbv7em-none-eabihf --features rt,unproven,${{ matrix.mcu }} + # note that examples were not built + - name: test + uses: actions-rs/cargo@v1 + with: + command: test + args: --lib --target x86_64-unknown-linux-gnu --features rt,unproven,${{ matrix.mcu }} diff --git a/.github/workflows/clippy_dac.yml b/.github/workflows/clippy_dac.yml new file mode 100644 index 00000000..982eb112 --- /dev/null +++ b/.github/workflows/clippy_dac.yml @@ -0,0 +1,22 @@ +on: + push: + branches: [ DAC ] + pull_request: + +name: Clippy check +jobs: + clippy_check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + target: thumbv7em-none-eabihf + override: true + components: clippy + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --examples --target thumbv7em-none-eabihf --features=stm32l432,rt,unproven diff --git a/.github/workflows/rustfmt_dac.yml b/.github/workflows/rustfmt_dac.yml new file mode 100644 index 00000000..7aa24fc3 --- /dev/null +++ b/.github/workflows/rustfmt_dac.yml @@ -0,0 +1,23 @@ +on: + push: + branches: [ DAC ] + pull_request: + +name: Code formatting check + +jobs: + fmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check diff --git a/Cargo.toml b/Cargo.toml index 769f5b15..90216cdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -197,3 +197,9 @@ required-features = ["rt"] [[example]] name = "adc_dma" required-features = ["rt"] + +[[example]] +name = "dac" +required-features = ["rt", "stm32l476"] + + diff --git a/dac.rs b/dac.rs new file mode 100644 index 00000000..b53a20c1 --- /dev/null +++ b/dac.rs @@ -0,0 +1,267 @@ +//! DAC + +use core::marker::PhantomData; +use core::mem::MaybeUninit; + +use crate::gpio::gpioa::{PA4, PA5}; +use crate::gpio::Analog; +use crate::hal::blocking::delay::DelayUs; +use crate::rcc::*; +use crate::stm32::DAC; + +pub trait DacOut { + fn set_value(&mut self, val: V); + fn get_value(&mut self) -> V; +} + +pub struct GeneratorConfig { + mode: u8, + amp: u8, +} + +impl GeneratorConfig { + pub fn triangle(amplitude: u8) -> Self { + Self { + mode: 0b10, + amp: amplitude, + } + } + + pub fn noise(seed: u8) -> Self { + Self { + mode: 0b01, + amp: seed, + } + } +} + +/// Enabled DAC (type state) +pub struct Enabled; +/// Enabled DAC without output buffer (type state) +pub struct EnabledUnbuffered; +/// Enabled DAC wave generator (type state) +pub struct WaveGenerator; +/// Disabled DAC (type state) +pub struct Disabled; + +pub trait ED {} +impl ED for Enabled {} +impl ED for EnabledUnbuffered {} +impl ED for WaveGenerator {} +impl ED for Disabled {} + +pub struct Channel1 { + _enabled: PhantomData, +} +pub struct Channel2 { + _enabled: PhantomData, +} + +/// Trait for GPIO pins that can be converted to DAC output pins +pub trait Pins { + type Output; +} + +impl Pins for PA4 { + type Output = Channel1; +} + +impl Pins for PA5 { + type Output = Channel2; +} + +impl Pins for (PA4, PA5) { + type Output = (Channel1, Channel2); +} + +// pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut Rcc::APB1R1) -> PINS::Output +pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut APB1R1) -> PINS::Output +where + PINS: Pins, +{ + DAC::enable(rcc); + DAC::reset(rcc); + + #[allow(clippy::uninit_assumed_init)] + unsafe { + MaybeUninit::uninit().assume_init() + } +} + +macro_rules! dac { + ($($CX:ident: ( + $en:ident, + $cen:ident, + $cal_flag:ident, + $trim:ident, + $mode:ident, + $dhrx:ident, + $dac_dor:ident, + $daccxdhr:ident, + $wave:ident, + $mamp:ident, + $ten:ident, + $swtrig:ident + ),)+) => { + $( + impl $CX { + pub fn enable(self) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); + dac.cr.modify(|_, w| w.$en().set_bit()); + + $CX { + _enabled: PhantomData, + } + } + + pub fn enable_unbuffered(self) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(2) }); + dac.cr.modify(|_, w| w.$en().set_bit()); + + $CX { + _enabled: PhantomData, + } + } + + pub fn enable_generator(self, config: GeneratorConfig) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); + dac.cr.modify(|_, w| unsafe { + w.$wave().bits(config.mode); + w.$ten().set_bit(); + w.$mamp().bits(config.amp); + w.$en().set_bit() + }); + + $CX { + _enabled: PhantomData, + } + } + } + + impl $CX { + /// Calibrate the DAC output buffer by performing a "User + /// trimming" operation. It is useful when the VDDA/VREF+ + /// voltage or temperature differ from the factory trimming + /// conditions. + /// + /// The calibration is only valid when the DAC channel is + /// operating with the buffer enabled. If applied in other + /// modes it has no effect. + /// + /// After the calibration operation, the DAC channel is + /// disabled. + pub fn calibrate_buffer(self, delay: &mut T) -> $CX + where + T: DelayUs, + { + let dac = unsafe { &(*DAC::ptr()) }; + dac.cr.modify(|_, w| w.$en().clear_bit()); + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(0) }); + dac.cr.modify(|_, w| w.$cen().set_bit()); + let mut trim = 0; + while true { + dac.ccr.modify(|_, w| unsafe { w.$trim().bits(trim) }); + delay.delay_us(64_u32); + if dac.sr.read().$cal_flag().bit() { + break; + } + trim += 1; + } + dac.cr.modify(|_, w| w.$cen().clear_bit()); + + $CX { + _enabled: PhantomData, + } + } + + /// Disable the DAC channel + pub fn disable(self) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + dac.cr.modify(|_, w| unsafe { + w.$en().clear_bit().$wave().bits(0).$ten().clear_bit() + }); + + $CX { + _enabled: PhantomData, + } + } + } + + /// DacOut implementation available in any Enabled/Disabled + /// state + impl DacOut for $CX { + fn set_value(&mut self, val: u16) { + let dac = unsafe { &(*DAC::ptr()) }; + dac.$dhrx.write(|w| unsafe { w.bits(val as u32) }); + } + + fn get_value(&mut self) -> u16 { + let dac = unsafe { &(*DAC::ptr()) }; + dac.$dac_dor.read().bits() as u16 + } + } + + /// Wave generator state implementation + impl $CX { + pub fn trigger(&mut self) { + let dac = unsafe { &(*DAC::ptr()) }; + dac.swtrigr.write(|w| { w.$swtrig().set_bit() }); + } + } + )+ + }; +} + +pub trait DacExt { + fn constrain(self, pins: PINS, rcc: &mut APB1R1) -> PINS::Output + where + PINS: Pins; +} + +impl DacExt for DAC { + fn constrain(self, pins: PINS, rcc: &mut APB1R1) -> PINS::Output + where + PINS: Pins, + { + dac(self, pins, rcc) + } +} + +dac!( + Channel1: + ( + en1, + cen1, + cal_flag1, + otrim1, + mode1, + dhr12r1, + dor1, + dacc1dhr, + wave1, + mamp1, + ten1, + swtrig1 + ), + Channel2: + ( + en2, + cen2, + cal_flag2, + otrim2, + mode2, + dhr12r2, + dor2, + dacc2dhr, + wave2, + mamp2, + ten2, + swtrig2 + ), +); diff --git a/src/lib.rs b/src/lib.rs index 87ea2daf..56801dc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,6 +128,13 @@ pub mod adc; pub mod can; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod crc; +#[cfg(any( + feature = "stm32l476", + feature = "stm32l486", + feature = "stm32l496", + feature = "stm32l4a6" +))] +pub mod dac; pub mod datetime; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod delay; From 091bd7c46086939f6abdead122bd3d19eae4133c Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sun, 23 Jan 2022 21:39:32 +0100 Subject: [PATCH 2/4] example was missing --- examples/dac.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 examples/dac.rs diff --git a/examples/dac.rs b/examples/dac.rs new file mode 100644 index 00000000..7ca9d21c --- /dev/null +++ b/examples/dac.rs @@ -0,0 +1,82 @@ +// #![deny(warnings)] +#![deny(unsafe_code)] +#![no_main] +#![no_std] + +// use rtt_target::{rprintln, rtt_init_print}; + +// currently only works with these devices +// #[cfg(any(feature = "stm32l476", feature = "stm32l486", feature = "stm32l496", feature = "stm32l4a6"))] + +extern crate cortex_m; +extern crate cortex_m_rt as rt; +extern crate panic_halt; +extern crate stm32l4xx_hal as hal; + +// use hal::dac::GeneratorConfig; +use hal::delay::Delay; +use hal::hal::Direction; +use hal::prelude::*; +// use hal::rcc::Config; +use hal::stm32; +use rt::entry; + +use crate::hal::dac::DacExt; +use crate::hal::dac::DacOut; + +#[entry] +fn main() -> ! { + // rtt_init_print!(); + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals"); + + let mut rcc = dp.RCC.constrain(); + let mut flash = dp.FLASH.constrain(); + let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); + let clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); + let mut delay = Delay::new(cp.SYST, clocks); + + let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); + let pa4 = gpioa.pa4.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + let pa5 = gpioa.pa5.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + + #[cfg(any( + feature = "stm32l476", + feature = "stm32l486", + feature = "stm32l496", + feature = "stm32l4a6" + ))] + let (dac0, _dac1) = dp.DAC.constrain((pa4, pa5), &mut rcc.apb1r1); + + #[cfg(not(any( + // feature = "stm32l412", + feature = "stm32l476", + feature = "stm32l486", + feature = "stm32l496", + feature = "stm32l4a6" + )))] + let dac0 = dp.DAC1.constrain(pa4, &mut rcc.apb1r1); + + let mut dac = dac0.calibrate_buffer(&mut delay).enable(); + + // let mut generator = dac1.enable_generator(GeneratorConfig::noise(11)); + + let mut dir = Direction::Upcounting; + let mut val = 0; + + loop { + // generator.trigger(); + dac.set_value(val); + match val { + 0 => dir = Direction::Upcounting, + 4095 => dir = Direction::Downcounting, + _ => (), + }; + + match dir { + Direction::Upcounting => val += 1, + Direction::Downcounting => val -= 1, + } + } +} From 3e31351aa3d9b9d833a94b0050c76b108f6690a4 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sun, 23 Jan 2022 21:43:58 +0100 Subject: [PATCH 3/4] correct dir for das.rs --- src/dac.rs | 267 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 src/dac.rs diff --git a/src/dac.rs b/src/dac.rs new file mode 100644 index 00000000..b53a20c1 --- /dev/null +++ b/src/dac.rs @@ -0,0 +1,267 @@ +//! DAC + +use core::marker::PhantomData; +use core::mem::MaybeUninit; + +use crate::gpio::gpioa::{PA4, PA5}; +use crate::gpio::Analog; +use crate::hal::blocking::delay::DelayUs; +use crate::rcc::*; +use crate::stm32::DAC; + +pub trait DacOut { + fn set_value(&mut self, val: V); + fn get_value(&mut self) -> V; +} + +pub struct GeneratorConfig { + mode: u8, + amp: u8, +} + +impl GeneratorConfig { + pub fn triangle(amplitude: u8) -> Self { + Self { + mode: 0b10, + amp: amplitude, + } + } + + pub fn noise(seed: u8) -> Self { + Self { + mode: 0b01, + amp: seed, + } + } +} + +/// Enabled DAC (type state) +pub struct Enabled; +/// Enabled DAC without output buffer (type state) +pub struct EnabledUnbuffered; +/// Enabled DAC wave generator (type state) +pub struct WaveGenerator; +/// Disabled DAC (type state) +pub struct Disabled; + +pub trait ED {} +impl ED for Enabled {} +impl ED for EnabledUnbuffered {} +impl ED for WaveGenerator {} +impl ED for Disabled {} + +pub struct Channel1 { + _enabled: PhantomData, +} +pub struct Channel2 { + _enabled: PhantomData, +} + +/// Trait for GPIO pins that can be converted to DAC output pins +pub trait Pins { + type Output; +} + +impl Pins for PA4 { + type Output = Channel1; +} + +impl Pins for PA5 { + type Output = Channel2; +} + +impl Pins for (PA4, PA5) { + type Output = (Channel1, Channel2); +} + +// pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut Rcc::APB1R1) -> PINS::Output +pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut APB1R1) -> PINS::Output +where + PINS: Pins, +{ + DAC::enable(rcc); + DAC::reset(rcc); + + #[allow(clippy::uninit_assumed_init)] + unsafe { + MaybeUninit::uninit().assume_init() + } +} + +macro_rules! dac { + ($($CX:ident: ( + $en:ident, + $cen:ident, + $cal_flag:ident, + $trim:ident, + $mode:ident, + $dhrx:ident, + $dac_dor:ident, + $daccxdhr:ident, + $wave:ident, + $mamp:ident, + $ten:ident, + $swtrig:ident + ),)+) => { + $( + impl $CX { + pub fn enable(self) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); + dac.cr.modify(|_, w| w.$en().set_bit()); + + $CX { + _enabled: PhantomData, + } + } + + pub fn enable_unbuffered(self) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(2) }); + dac.cr.modify(|_, w| w.$en().set_bit()); + + $CX { + _enabled: PhantomData, + } + } + + pub fn enable_generator(self, config: GeneratorConfig) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); + dac.cr.modify(|_, w| unsafe { + w.$wave().bits(config.mode); + w.$ten().set_bit(); + w.$mamp().bits(config.amp); + w.$en().set_bit() + }); + + $CX { + _enabled: PhantomData, + } + } + } + + impl $CX { + /// Calibrate the DAC output buffer by performing a "User + /// trimming" operation. It is useful when the VDDA/VREF+ + /// voltage or temperature differ from the factory trimming + /// conditions. + /// + /// The calibration is only valid when the DAC channel is + /// operating with the buffer enabled. If applied in other + /// modes it has no effect. + /// + /// After the calibration operation, the DAC channel is + /// disabled. + pub fn calibrate_buffer(self, delay: &mut T) -> $CX + where + T: DelayUs, + { + let dac = unsafe { &(*DAC::ptr()) }; + dac.cr.modify(|_, w| w.$en().clear_bit()); + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(0) }); + dac.cr.modify(|_, w| w.$cen().set_bit()); + let mut trim = 0; + while true { + dac.ccr.modify(|_, w| unsafe { w.$trim().bits(trim) }); + delay.delay_us(64_u32); + if dac.sr.read().$cal_flag().bit() { + break; + } + trim += 1; + } + dac.cr.modify(|_, w| w.$cen().clear_bit()); + + $CX { + _enabled: PhantomData, + } + } + + /// Disable the DAC channel + pub fn disable(self) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + dac.cr.modify(|_, w| unsafe { + w.$en().clear_bit().$wave().bits(0).$ten().clear_bit() + }); + + $CX { + _enabled: PhantomData, + } + } + } + + /// DacOut implementation available in any Enabled/Disabled + /// state + impl DacOut for $CX { + fn set_value(&mut self, val: u16) { + let dac = unsafe { &(*DAC::ptr()) }; + dac.$dhrx.write(|w| unsafe { w.bits(val as u32) }); + } + + fn get_value(&mut self) -> u16 { + let dac = unsafe { &(*DAC::ptr()) }; + dac.$dac_dor.read().bits() as u16 + } + } + + /// Wave generator state implementation + impl $CX { + pub fn trigger(&mut self) { + let dac = unsafe { &(*DAC::ptr()) }; + dac.swtrigr.write(|w| { w.$swtrig().set_bit() }); + } + } + )+ + }; +} + +pub trait DacExt { + fn constrain(self, pins: PINS, rcc: &mut APB1R1) -> PINS::Output + where + PINS: Pins; +} + +impl DacExt for DAC { + fn constrain(self, pins: PINS, rcc: &mut APB1R1) -> PINS::Output + where + PINS: Pins, + { + dac(self, pins, rcc) + } +} + +dac!( + Channel1: + ( + en1, + cen1, + cal_flag1, + otrim1, + mode1, + dhr12r1, + dor1, + dacc1dhr, + wave1, + mamp1, + ten1, + swtrig1 + ), + Channel2: + ( + en2, + cen2, + cal_flag2, + otrim2, + mode2, + dhr12r2, + dor2, + dacc2dhr, + wave2, + mamp2, + ten2, + swtrig2 + ), +); From 7ecefeda8d652b3e0dfc363504c443d51c99dfe2 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sun, 23 Jan 2022 21:44:34 +0100 Subject: [PATCH 4/4] remove dac.rs in main folder --- dac.rs | 267 --------------------------------------------------------- 1 file changed, 267 deletions(-) delete mode 100644 dac.rs diff --git a/dac.rs b/dac.rs deleted file mode 100644 index b53a20c1..00000000 --- a/dac.rs +++ /dev/null @@ -1,267 +0,0 @@ -//! DAC - -use core::marker::PhantomData; -use core::mem::MaybeUninit; - -use crate::gpio::gpioa::{PA4, PA5}; -use crate::gpio::Analog; -use crate::hal::blocking::delay::DelayUs; -use crate::rcc::*; -use crate::stm32::DAC; - -pub trait DacOut { - fn set_value(&mut self, val: V); - fn get_value(&mut self) -> V; -} - -pub struct GeneratorConfig { - mode: u8, - amp: u8, -} - -impl GeneratorConfig { - pub fn triangle(amplitude: u8) -> Self { - Self { - mode: 0b10, - amp: amplitude, - } - } - - pub fn noise(seed: u8) -> Self { - Self { - mode: 0b01, - amp: seed, - } - } -} - -/// Enabled DAC (type state) -pub struct Enabled; -/// Enabled DAC without output buffer (type state) -pub struct EnabledUnbuffered; -/// Enabled DAC wave generator (type state) -pub struct WaveGenerator; -/// Disabled DAC (type state) -pub struct Disabled; - -pub trait ED {} -impl ED for Enabled {} -impl ED for EnabledUnbuffered {} -impl ED for WaveGenerator {} -impl ED for Disabled {} - -pub struct Channel1 { - _enabled: PhantomData, -} -pub struct Channel2 { - _enabled: PhantomData, -} - -/// Trait for GPIO pins that can be converted to DAC output pins -pub trait Pins { - type Output; -} - -impl Pins for PA4 { - type Output = Channel1; -} - -impl Pins for PA5 { - type Output = Channel2; -} - -impl Pins for (PA4, PA5) { - type Output = (Channel1, Channel2); -} - -// pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut Rcc::APB1R1) -> PINS::Output -pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut APB1R1) -> PINS::Output -where - PINS: Pins, -{ - DAC::enable(rcc); - DAC::reset(rcc); - - #[allow(clippy::uninit_assumed_init)] - unsafe { - MaybeUninit::uninit().assume_init() - } -} - -macro_rules! dac { - ($($CX:ident: ( - $en:ident, - $cen:ident, - $cal_flag:ident, - $trim:ident, - $mode:ident, - $dhrx:ident, - $dac_dor:ident, - $daccxdhr:ident, - $wave:ident, - $mamp:ident, - $ten:ident, - $swtrig:ident - ),)+) => { - $( - impl $CX { - pub fn enable(self) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; - - dac.mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); - dac.cr.modify(|_, w| w.$en().set_bit()); - - $CX { - _enabled: PhantomData, - } - } - - pub fn enable_unbuffered(self) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; - - dac.mcr.modify(|_, w| unsafe { w.$mode().bits(2) }); - dac.cr.modify(|_, w| w.$en().set_bit()); - - $CX { - _enabled: PhantomData, - } - } - - pub fn enable_generator(self, config: GeneratorConfig) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; - - dac.mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); - dac.cr.modify(|_, w| unsafe { - w.$wave().bits(config.mode); - w.$ten().set_bit(); - w.$mamp().bits(config.amp); - w.$en().set_bit() - }); - - $CX { - _enabled: PhantomData, - } - } - } - - impl $CX { - /// Calibrate the DAC output buffer by performing a "User - /// trimming" operation. It is useful when the VDDA/VREF+ - /// voltage or temperature differ from the factory trimming - /// conditions. - /// - /// The calibration is only valid when the DAC channel is - /// operating with the buffer enabled. If applied in other - /// modes it has no effect. - /// - /// After the calibration operation, the DAC channel is - /// disabled. - pub fn calibrate_buffer(self, delay: &mut T) -> $CX - where - T: DelayUs, - { - let dac = unsafe { &(*DAC::ptr()) }; - dac.cr.modify(|_, w| w.$en().clear_bit()); - dac.mcr.modify(|_, w| unsafe { w.$mode().bits(0) }); - dac.cr.modify(|_, w| w.$cen().set_bit()); - let mut trim = 0; - while true { - dac.ccr.modify(|_, w| unsafe { w.$trim().bits(trim) }); - delay.delay_us(64_u32); - if dac.sr.read().$cal_flag().bit() { - break; - } - trim += 1; - } - dac.cr.modify(|_, w| w.$cen().clear_bit()); - - $CX { - _enabled: PhantomData, - } - } - - /// Disable the DAC channel - pub fn disable(self) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; - dac.cr.modify(|_, w| unsafe { - w.$en().clear_bit().$wave().bits(0).$ten().clear_bit() - }); - - $CX { - _enabled: PhantomData, - } - } - } - - /// DacOut implementation available in any Enabled/Disabled - /// state - impl DacOut for $CX { - fn set_value(&mut self, val: u16) { - let dac = unsafe { &(*DAC::ptr()) }; - dac.$dhrx.write(|w| unsafe { w.bits(val as u32) }); - } - - fn get_value(&mut self) -> u16 { - let dac = unsafe { &(*DAC::ptr()) }; - dac.$dac_dor.read().bits() as u16 - } - } - - /// Wave generator state implementation - impl $CX { - pub fn trigger(&mut self) { - let dac = unsafe { &(*DAC::ptr()) }; - dac.swtrigr.write(|w| { w.$swtrig().set_bit() }); - } - } - )+ - }; -} - -pub trait DacExt { - fn constrain(self, pins: PINS, rcc: &mut APB1R1) -> PINS::Output - where - PINS: Pins; -} - -impl DacExt for DAC { - fn constrain(self, pins: PINS, rcc: &mut APB1R1) -> PINS::Output - where - PINS: Pins, - { - dac(self, pins, rcc) - } -} - -dac!( - Channel1: - ( - en1, - cen1, - cal_flag1, - otrim1, - mode1, - dhr12r1, - dor1, - dacc1dhr, - wave1, - mamp1, - ten1, - swtrig1 - ), - Channel2: - ( - en2, - cen2, - cal_flag2, - otrim2, - mode2, - dhr12r2, - dor2, - dacc2dhr, - wave2, - mamp2, - ten2, - swtrig2 - ), -);