From 4c3504c8e1b182b1c74bc3956af0320614476b58 Mon Sep 17 00:00:00 2001 From: Mike Panetta Date: Mon, 28 Oct 2019 18:02:16 -0400 Subject: [PATCH] Add dac (#70) * Added dac.rs from stm32g4xx-hal crate and modified it a bit. * Removed IDE files. * Fix feature gating for DAC module. * Remove unused calibrate function from DacPin trait. * Add feature gates for all devices that support DAC. * Added docs and example. * Some cleanup, fixed feature gate. --- CHANGELOG.md | 1 + Cargo.toml | 4 + examples/dac.rs | 62 +++++++++++++++ src/dac.rs | 195 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 9 +++ 5 files changed, 271 insertions(+) create mode 100644 examples/dac.rs create mode 100644 src/dac.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 71694e5..c5381aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fixed a few deprecation warning and lints - Enabled commented out and now available GPIOE support for 07x and 09x families - Extract register block address only once +- Add DAC driver ## [v0.15.1] - 2019-08-11 diff --git a/Cargo.toml b/Cargo.toml index d20aefd..50c4de6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,3 +74,7 @@ opt-level = "s" [[example]] name = "led_hal_button_irq" required-features = ["stm32f042", "rt"] + +[[example]] +name = "dac" +required-features = ["stm32f072"] diff --git a/examples/dac.rs b/examples/dac.rs new file mode 100644 index 0000000..0784169 --- /dev/null +++ b/examples/dac.rs @@ -0,0 +1,62 @@ +#![deny(unused_imports)] +#![no_main] +#![no_std] + +use cortex_m; +use cortex_m_rt as rt; +#[allow(unused_imports)] +use panic_halt; + +use stm32f0xx_hal as hal; + +use crate::hal::stm32; +use crate::hal::prelude::*; +use crate::hal::dac::*; + +use rt::entry; + +enum Direction { + Upcounting, + Downcounting, +} + +#[entry] +fn main() -> ! { + if let (Some(mut dp), Some(_cp)) = (stm32::Peripherals::take(), cortex_m::Peripherals::take()) { + cortex_m::interrupt::free(move |cs| { + let mut rcc = dp.RCC.configure().sysclk(8.mhz()).freeze(&mut dp.FLASH); + + let gpioa = dp.GPIOA.split(&mut rcc); + let mut dac = dac(dp.DAC, gpioa.pa4.into_analog(cs), &mut rcc); + + dac.enable(); + + let mut dir = Direction::Upcounting; + let mut val = 0; + + dac.set_value(2058); + cortex_m::asm::bkpt(); + + dac.set_value(4095); + cortex_m::asm::bkpt(); + + loop { + dac.set_value(val); + match val { + 0 => dir = Direction::Upcounting, + 4095 => dir = Direction::Downcounting, + _ => (), + }; + + match dir { + Direction::Upcounting => val += 1, + Direction::Downcounting => val -= 1, + } + } + }); + } + + loop { + continue; + } +} \ No newline at end of file diff --git a/src/dac.rs b/src/dac.rs new file mode 100644 index 0000000..7b58c08 --- /dev/null +++ b/src/dac.rs @@ -0,0 +1,195 @@ +//! # API for the Digital to Analog converter +//! +//! Currently only supports writing to the DR of the DAC, +//! just a basic one-shot conversion. +//! +//! ## Example +//! ``` no_run +//!#![deny(unused_imports)] +//!#![no_main] +//!#![no_std] +//! +//!use cortex_m; +//!use cortex_m_rt as rt; +//!use panic_halt; +//! +//!use stm32f0xx_hal as hal; +//! +//!use crate::hal::stm32; +//!use crate::hal::prelude::*; +//!use crate::hal::dac::*; +//! +//!use rt::entry; +//! +//!enum Direction { +//! Upcounting, +//! Downcounting, +//!} +//! +//!#[entry] +//!fn main() -> ! { +//! if let (Some(mut dp), Some(_cp)) = (stm32::Peripherals::take(), cortex_m::Peripherals::take()) { +//! cortex_m::interrupt::free(move |cs| { +//! let mut rcc = dp.RCC.configure().sysclk(8.mhz()).freeze(&mut dp.FLASH); +//! +//! let gpioa = dp.GPIOA.split(&mut rcc); +//! let mut dac = dac(dp.DAC, gpioa.pa4.into_analog(cs), &mut rcc); +//! +//! dac.enable(); +//! +//! let mut dir = Direction::Upcounting; +//! let mut val = 0; +//! +//! dac.set_value(2058); +//! cortex_m::asm::bkpt(); +//! +//! dac.set_value(4095); +//! cortex_m::asm::bkpt(); +//! +//! loop { +//! dac.set_value(val); +//! match val { +//! 0 => dir = Direction::Upcounting, +//! 4095 => dir = Direction::Downcounting, +//! _ => (), +//! }; +//! +//! match dir { +//! Direction::Upcounting => val += 1, +//! Direction::Downcounting => val -= 1, +//! } +//! } +//! }); +//! } +//! +//! loop { +//! continue; +//! } +//!} +//! ``` +#![deny(unused_imports)] +use core::mem; + +use crate::gpio::gpioa::{PA4, PA5}; +use crate::rcc::Rcc; +use crate::stm32::DAC; +use crate::gpio::Analog; + +pub struct C1; +pub struct C2; + +pub trait DacOut { + fn set_value(&mut self, val: V); + fn get_value(&mut self) -> V; +} + +pub trait DacPin { + fn enable(&mut self); +} + +pub trait Pins { + type Output; +} + +impl Pins for PA4 { + type Output = C1; +} + +impl Pins for PA5 { + type Output = C2; +} + +impl Pins for (PA4, PA5) { + type Output = (C1, C2); +} + +pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut Rcc) -> PINS::Output +where + PINS: Pins, +{ + // Enable DAC clocks + rcc.regs.apb1enr.modify(|_, w| w.dacen().set_bit()); + + // Reset DAC + rcc.regs.apb1rstr.modify(|_, w| w.dacrst().set_bit()); + rcc.regs.apb1rstr.modify(|_, w| w.dacrst().clear_bit()); + + unsafe { mem::uninitialized() } +} + +macro_rules! dac { + ($CX:ident, $en:ident, $cen:ident, $cal_flag:ident, $trim:ident, $mode:ident, $dhrx:ident, $dac_dor:ident, $daccxdhr:ident) => { + impl DacPin for $CX { + fn enable(&mut self) { + let dac = unsafe { &(*DAC::ptr()) }; + dac.cr.modify(|_, w| w.$en().set_bit()); + } + } + + 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 + } + } + }; +} + +pub trait DacExt { + fn constrain(self, pins: PINS, rcc: &mut Rcc) -> PINS::Output + where + PINS: Pins; +} + +impl DacExt for DAC { + fn constrain(self, pins: PINS, rcc: &mut Rcc) -> PINS::Output + where + PINS: Pins, + { + dac(self, pins, rcc) + } +} + +#[cfg(any( +feature = "stm32f051", +feature = "stm32f071", +feature = "stm32f072", +feature = "stm32f078", +feature = "stm32f091", +feature = "stm32f098", +))] +dac!( + C1, + en1, + cen1, + cal_flag1, + otrim1, + mode1, + dhr12r1, + dor1, + dacc1dhr +); + +#[cfg(any( +feature = "stm32f071", +feature = "stm32f072", +feature = "stm32f078", +feature = "stm32f091", +feature = "stm32f098", +))] +dac!( + C2, + en2, + cen2, + cal_flag2, + otrim2, + mode2, + dhr12r2, + dor2, + dacc2dhr +); diff --git a/src/lib.rs b/src/lib.rs index ff2b8a8..0abb490 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,15 @@ pub use stm32f0::stm32f0x8 as stm32; #[cfg(feature = "device-selected")] pub mod adc; +#[cfg(any( + feature = "stm32f051", + feature = "stm32f071", + feature = "stm32f072", + feature = "stm32f078", + feature = "stm32f091", + feature = "stm32f098", +))] +pub mod dac; #[cfg(feature = "device-selected")] pub mod delay; #[cfg(feature = "device-selected")]