From 240ff5a874608843f702b632d44b431ebd085a58 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 30 May 2023 06:32:11 +0200 Subject: [PATCH 01/18] Add modified src/dac.rs and src/comparator.rs from g0xx-hal --- src/comparator.rs | 615 ++++++++++++++++++++++++++++++++++++++++++++++ src/dac.rs | 265 ++++++++++++++++++++ src/lib.rs | 3 +- 3 files changed, 882 insertions(+), 1 deletion(-) create mode 100644 src/comparator.rs create mode 100644 src/dac.rs diff --git a/src/comparator.rs b/src/comparator.rs new file mode 100644 index 00000000..452bc0c2 --- /dev/null +++ b/src/comparator.rs @@ -0,0 +1,615 @@ +//! Comparator + +use core::marker::PhantomData; + +use crate::dac; +use crate::exti::{Event as ExtiEvent, ExtiExt}; +use crate::gpio::*; +use crate::gpio::gpiob::PB14; +use crate::gpio::gpiod::PD14; +use crate::rcc::{Clocks, Rcc}; +use crate::stm32::comp::{C1CSR, C2CSR}; +use crate::stm32::{COMP, EXTI}; + +/// Enabled Comparator (type state) +pub struct Enabled; + +/// Disabled Comparator (type state) +pub struct Disabled; + +pub trait ED {} +impl ED for Enabled {} +impl ED for Disabled {} + +macro_rules! impl_comp { + ($($t:ident: $reg_t:ident, $reg:ident,)+) => {$( + pub struct $t { + _rb: PhantomData<()>, + } + + impl $t { + pub fn csr(&self) -> &$crate::stm32::comp::$reg_t { + // SAFETY: The COMP1 type is only constructed with logical ownership of + // these registers. + &unsafe { &*COMP::ptr() }.$reg + } + } + )+}; +} + +impl_comp!{ + COMP1: C1CSR, c1csr, + COMP2: C2CSR, c2csr, + COMP3: C3CSR, c3csr, + COMP4: C4CSR, c4csr, +} +#[cfg(any(feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484"))] +impl_comp!{ + COMP5: C5CSR, c5csr, + COMP6: C6CSR, c6csr, + COMP7: C7CSR, c7csr, +} + +// TODO: Split COMP in PAC + +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Config { + power_mode: PowerMode, + hysteresis: Hysteresis, + inverted: bool, + output_xor: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + hysteresis: Hysteresis::None, + inverted: false, + power_mode: PowerMode::HighSpeed, + output_xor: false, + } + } +} + +impl Config { + pub fn hysteresis(mut self, hysteresis: Hysteresis) -> Self { + self.hysteresis = hysteresis; + self + } + + pub fn output_inverted(mut self) -> Self { + self.inverted = true; + self + } + + pub fn output_polarity(mut self, inverted: bool) -> Self { + self.inverted = inverted; + self + } + + pub fn power_mode(mut self, power_mode: PowerMode) -> Self { + self.power_mode = power_mode; + self + } + + /// Sets the output to be Comparator 1 XOR Comparator 2. + /// Used to implement window comparator mode. + pub fn output_xor(mut self) -> Self { + self.output_xor = true; + self + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum Hysteresis { + None = 0b00, + Low = 0b01, + Medium = 0b10, + High = 0b11, +} + +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum PowerMode { + HighSpeed = 0b00, + MediumSpeed = 0b01, +} + +/// Comparator positive input +pub trait PositiveInput { + fn setup(&self, comp: &C); +} + +/// Comparator negative input +pub trait NegativeInput { + fn setup(&self, comp: &C); +} + +/// 1/4 Vref +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Vref1div4; + +/// 1/2 Vref +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Vref1div2; + +/// 3/4 Vref +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Vref3div4; + +/// Vref +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Vref; + +/* +/// Comparator 1 positive input used as positive input for Comparator 2. +/// Used to implement window comparator mode. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Comp1InP; + +/// Comparator 2 positive input used as positive input for Comparator 1. +/// Used to implement window comparator mode. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Comp2InP; + + +macro_rules! window_input_pin { + ($COMP:ident, $pin:ty) => { + impl PositiveInput<$COMP> for $pin { + fn setup(&self, comp: &$COMP) { + comp.csr().modify(|_, w| w.winmode().set_bit()) + } + } + }; +} + +window_input_pin!(COMP1, Comp2InP); +window_input_pin!(COMP2, Comp1InP); +*/ + +macro_rules! positive_input_pin { + ($COMP:ident, $pin_0:ty, $pin_1:ty) => { + impl PositiveInput<$COMP> for $pin_0 { + fn setup(&self, comp: &$COMP) { + comp.csr().modify(|_, w| unsafe { w.inpsel().bit(0) }) + } + } + + impl PositiveInput<$COMP> for $pin_1 { + fn setup(&self, comp: &$COMP) { + comp.csr().modify(|_, w| unsafe { w.inpsel().bit(1) }) + } + } + }; +} + +positive_input_pin!(COMP1, PA1, PB1); +positive_input_pin!(COMP2, PA7, PA3); +positive_input_pin!(COMP3, PA0, PC1); +positive_input_pin!(COMP4, PB0, PE7); + +#[cfg(any(feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484"))] +positive_input_pin!(COMP5, PB13, PD12); + +#[cfg(any(feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484"))] +positive_input_pin!(COMP6, PB11, PD11); + +#[cfg(any(feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484"))] +positive_input_pin!(COMP7, PB14, PD14); + +macro_rules! negative_input_pin_helper { + ($COMP:ident, $input:ty, $bits:expr) => { + impl NegativeInput<$COMP> for $input { + fn setup(&self, comp: &$COMP) { + comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) }) + } + } + }; +} + +macro_rules! negative_input_pin { + ($($COMP:ident: $dac_0:ty, $dac_1:ty, $pin_0:ty, $pin_1:ty,)+) => {$( + negative_input_pin_helper($COMP, Vref1div4, 0b000); + negative_input_pin_helper($COMP, Vref1div2, 0b001); + negative_input_pin_helper($COMP, Vref3div4, 0b010); + negative_input_pin_helper($COMP, Vref, 0b011); + + //negative_input_pin_helper($COMP, $dac_0, 0b100); + //negative_input_pin_helper($COMP, $dac_1, 0b101); + + negative_input_pin_helper($COMP, $pin_0, 0b110); + negative_input_pin_helper($COMP, $pin_1, 0b111); + )+}; +} + +/// TODO: Add DAC support +struct TodoAddDac; + +negative_input_pin!{ + COMP1: TodoAddDac, TodoAddDac, PA4, PA0, + COMP2: TodoAddDac, TodoAddDac, PA5, PA2, + COMP3: TodoAddDac, TodoAddDac, PF1, PC0, + COMP4: TodoAddDac, TodoAddDac, PE8, PB2, +} + +#[cfg(any(feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484"))] +negative_input_pin!{ + COMP5: TodoAddDac, TodoAddDac, PB10, PD13, + COMP6: TodoAddDac, TodoAddDac, PD10, PB15, + COMP7: TodoAddDac, TodoAddDac, PD15, PB12, +}; + +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum RefintInput { + /// VRefint * 1/4 + VRefintM14 = 0b0000, + /// VRefint * 1/2 + VRefintM12 = 0b0001, + /// VRefint * 3/4 + VRefintM34 = 0b0010, + /// VRefint + VRefint = 0b0011, +} + +/* +macro_rules! dac_input { + ($COMP:ident, $channel:ty, $bits:expr) => { + impl NegativeInput<$COMP> for &$channel { + fn setup(&self, comp: &$COMP) { + comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) }) + } + } + }; +} + +#[cfg(any(feature = "stm32g071", feature = "stm32g081"))] +dac_input!(COMP1, dac::Channel1, 0b0100); +#[cfg(any(feature = "stm32g071", feature = "stm32g081"))] +dac_input!(COMP1, dac::Channel2, 0b0101); + +#[cfg(any(feature = "stm32g071", feature = "stm32g081"))] +dac_input!(COMP2, dac::Channel1, 0b0100); +#[cfg(any(feature = "stm32g071", feature = "stm32g081"))] +dac_input!(COMP2, dac::Channel2, 0b0101);*/ + +pub struct Comparator { + regs: C, + _enabled: PhantomData, +} + +pub trait ComparatorExt { + /// Initializes a comparator + fn comparator, N: NegativeInput>( + self, + positive_input: P, + negative_input: N, + config: Config, + clocks: &Clocks, + ) -> Comparator; +} + +macro_rules! impl_comparator { + ($COMP:ty, $comp:ident, $Event:expr) => { + impl ComparatorExt<$COMP> for $COMP { + fn comparator, N: NegativeInput<$COMP>>( + self, + positive_input: P, + negative_input: N, + config: Config, + clocks: &Clocks, + ) -> Comparator<$COMP, Disabled> { + positive_input.setup(&self); + negative_input.setup(&self); + // Delay for scaler voltage bridge initialization for certain negative inputs + let voltage_scaler_delay = clocks.sys_clk.raw() / (1_000_000 / 200); // 200us + cortex_m::asm::delay(voltage_scaler_delay); + self.csr().modify(|_, w| unsafe { + w.hyst() + .bits(config.hysteresis as u8) + //.brgen() + //.set_bit() + .pol() + .bit(config.inverted) + }); + + Comparator { + regs: self, + _enabled: PhantomData, + } + } + } + + impl Comparator<$COMP, Disabled> { + /// Initializes a comparator + pub fn $comp, N: NegativeInput<$COMP>>( + comp: $COMP, + positive_input: P, + negative_input: N, + config: Config, + clocks: &Clocks, + ) -> Self { + comp.comparator(positive_input, negative_input, config, clocks) + } + + /// Enables the comparator + pub fn enable(self) -> Comparator<$COMP, Enabled> { + self.regs.csr().modify(|_, w| w.en().set_bit()); + Comparator { + regs: self.regs, + _enabled: PhantomData, + } + } + + /// Enables raising the `ADC_COMP` interrupt at the specified output signal edge + pub fn listen(&self, edge: SignalEdge, exti: &EXTI) { + exti.listen($Event, edge); + } + } + + impl Comparator<$COMP, Enabled> { + /// Returns the value of the output of the comparator + pub fn output(&self) -> bool { + self.regs.csr().read().value().bit_is_set() + } + + /// Disables the comparator + pub fn disable(self) -> Comparator<$COMP, Disabled> { + self.regs.csr().modify(|_, w| w.en().clear_bit()); + Comparator { + regs: self.regs, + _enabled: PhantomData, + } + } + } + + impl Comparator<$COMP, ED> { + /// Disables raising interrupts for the output signal + pub fn unlisten(&self, exti: &EXTI) { + exti.unlisten($Event); + } + + /// Returns `true` if the output signal interrupt is pending for the `edge` + pub fn is_pending(&self, edge: SignalEdge, exti: &EXTI) -> bool { + exti.is_pending($Event, edge) + } + + /// Unpends the output signal interrupt + pub fn unpend(&self, exti: &EXTI) { + exti.unpend($Event); + } + + /// Configures a GPIO pin to output the signal of the comparator + /// + /// Multiple GPIO pins may be configured as the output simultaneously. + pub fn output_pin>(&self, pin: P) { + pin.setup(); + } + } + }; +} + +impl_comparator!(COMP1, comp1, ExtiEvent::COMP1); +impl_comparator!(COMP2, comp2, ExtiEvent::COMP2); + +/// Uses two comparators to implement a window comparator. +/// See Figure 69 in RM0444 Rev 5. +pub struct WindowComparator { + pub upper: Comparator, + pub lower: Comparator, +} + +pub trait WindowComparatorExt { + /// Uses two comparators to implement a window comparator + /// + /// See Figure 69 in RM0444 Rev 5. Ignores and overrides the `output_xor` setting in `config`. + fn window_comparator, L: NegativeInput, U: NegativeInput>( + self, + input: I, + lower_threshold: L, + upper_threshold: U, + config: Config, + clocks: &Clocks, + ) -> WindowComparator; +} + +macro_rules! impl_window_comparator { + ($UPPER:ident, $LOWER:ident, $LOTHR:expr) => { + impl WindowComparatorExt<$UPPER, $LOWER> for ($UPPER, $LOWER) { + fn window_comparator< + I: PositiveInput<$UPPER>, + L: NegativeInput<$LOWER>, + U: NegativeInput<$UPPER>, + >( + self, + input: I, + lower_threshold: L, + upper_threshold: U, + config: Config, + clocks: &Clocks, + ) -> WindowComparator<$UPPER, $LOWER, Disabled> { + let (upper, lower) = self; + + let mut configu = config.clone(); + configu.output_xor = true; + let upper = upper.comparator(input, upper_threshold, configu, clocks); + + let mut configl = config; + configl.output_xor = false; + let lower = lower.comparator($LOTHR, lower_threshold, configl, clocks); + + WindowComparator { upper, lower } + } + } + + impl WindowComparator<$UPPER, $LOWER, Disabled> { + /// Enables the comparator + pub fn enable(self) -> WindowComparator<$UPPER, $LOWER, Enabled> { + WindowComparator { + upper: self.upper.enable(), + lower: self.lower.enable(), + } + } + + /// Enables raising the `ADC_COMP` interrupt at the specified signal edge + pub fn listen(&self, edge: SignalEdge, exti: &mut EXTI) { + self.upper.listen(edge, exti) + } + } + + impl WindowComparator<$UPPER, $LOWER, Enabled> { + /// Disables the comparator + pub fn disable(self) -> WindowComparator<$UPPER, $LOWER, Disabled> { + WindowComparator { + upper: self.upper.disable(), + lower: self.lower.disable(), + } + } + + /// Returns the value of the output of the comparator + pub fn output(&self) -> bool { + self.upper.output() + } + + /// Returns `true` if the input signal is above the lower threshold + pub fn above_lower(&self) -> bool { + self.lower.output() + } + } + + impl WindowComparator<$UPPER, $LOWER, ED> { + /// Configures a GPIO pin to output the signal of the comparator + /// + /// Multiple GPIO pins may be configured as the output simultaneously. + pub fn output_pin>(&self, pin: P) { + self.upper.output_pin(pin) + } + + /// Disables raising interrupts for the output signal + pub fn unlisten(&self, exti: &mut EXTI) { + self.upper.unlisten(exti) + } + + /// Returns `true` if the output signal interrupt is pending for the `edge` + pub fn is_pending(&self, edge: SignalEdge, exti: &EXTI) -> bool { + self.upper.is_pending(edge, exti) + } + + /// Unpends the output signal interrupt + pub fn unpend(&self, exti: &EXTI) { + self.upper.unpend(exti) + } + } + }; +} + +impl_window_comparator!(COMP1, COMP2, Comp1InP); +impl_window_comparator!(COMP2, COMP1, Comp2InP); + +pub fn window_comparator12< + I: PositiveInput, + L: NegativeInput, + U: NegativeInput, +>( + comp: COMP, + input: I, + lower_threshold: L, + upper_threshold: U, + config: Config, + rcc: &mut Rcc, +) -> WindowComparator { + let (comp1, comp2) = comp.split(rcc); + (comp1, comp2).window_comparator(input, lower_threshold, upper_threshold, config, &rcc.clocks) +} + +pub fn window_comparator21< + I: PositiveInput, + L: NegativeInput, + U: NegativeInput, +>( + comp: COMP, + input: I, + lower_threshold: L, + upper_threshold: U, + config: Config, + rcc: &mut Rcc, +) -> WindowComparator { + let (comp1, comp2) = comp.split(rcc); + (comp2, comp1).window_comparator(input, lower_threshold, upper_threshold, config, &rcc.clocks) +} + +/// Enables the comparator peripheral, and splits the [`COMP`] into independent [`COMP1`] and [`COMP2`] +pub fn split(_comp: COMP, rcc: &mut Rcc) -> (COMP1, COMP2) { + // Enable COMP, SYSCFG, VREFBUF clocks + rcc.rb.apbenr2.modify(|_, w| w.syscfgen().set_bit()); + + // Reset COMP, SYSCFG, VREFBUF + rcc.rb.apbrstr2.modify(|_, w| w.syscfgrst().set_bit()); + rcc.rb.apbrstr2.modify(|_, w| w.syscfgrst().clear_bit()); + + (COMP1 { _rb: PhantomData }, COMP2 { _rb: PhantomData }) +} + +pub trait ComparatorSplit { + /// Enables the comparator peripheral, and splits the [`COMP`] into independent [`COMP1`] and [`COMP2`] + fn split(self, rcc: &mut Rcc) -> (COMP1, COMP2); +} + +impl ComparatorSplit for COMP { + fn split(self, rcc: &mut Rcc) -> (COMP1, COMP2) { + split(self, rcc) + } +} + +pub trait OutputPin { + fn setup(&self); + fn release(self) -> Self; +} + +macro_rules! output_pin_push_pull { + ($COMP:ident, $pin:ty) => { + impl OutputPin<$COMP> for $pin { + fn setup(&self) { + self.set_alt_mode(AltFunction::AF7) + } + + fn release(self) -> Self { + self.into_push_pull_output() + } + } + }; +} + +macro_rules! output_pin_open_drain { + ($COMP:ident, $pin:ty) => { + impl OutputPin<$COMP> for $pin { + fn setup(&self) { + self.set_alt_mode(AltFunction::AF7) + } + + fn release(self) -> Self { + self.into_open_drain_output() + } + } + }; +} + +output_pin_push_pull!(COMP1, PA0>); +output_pin_open_drain!(COMP1, PA0>); +output_pin_push_pull!(COMP1, PA6>); +output_pin_open_drain!(COMP1, PA6>); +output_pin_push_pull!(COMP1, PA11>); +output_pin_open_drain!(COMP1, PA11>); +output_pin_push_pull!(COMP1, PB0>); +output_pin_open_drain!(COMP1, PB0>); +output_pin_push_pull!(COMP1, PB10>); +output_pin_open_drain!(COMP1, PB10>); + +output_pin_push_pull!(COMP2, PA2>); +output_pin_open_drain!(COMP2, PA2>); +output_pin_push_pull!(COMP2, PA7>); +output_pin_open_drain!(COMP2, PA7>); +output_pin_push_pull!(COMP2, PA12>); +output_pin_open_drain!(COMP2, PA12>); +output_pin_push_pull!(COMP2, PB5>); +output_pin_open_drain!(COMP2, PB5>); +output_pin_push_pull!(COMP2, PB11>); +output_pin_open_drain!(COMP2, PB11>); diff --git a/src/dac.rs b/src/dac.rs new file mode 100644 index 00000000..ac31cd53 --- /dev/null +++ b/src/dac.rs @@ -0,0 +1,265 @@ +//! DAC + +use core::marker::PhantomData; +use core::mem::MaybeUninit; + +use crate::gpio::{DefaultMode, PA4, PA5}; +use crate::rcc::*; +use crate::stm32::DAC; +use hal::blocking::delay::DelayUs; + +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) -> 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.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); + dac.dac_cr.modify(|_, w| w.$en().set_bit()); + + $CX { + _enabled: PhantomData, + } + } + + pub fn enable_unbuffered(self) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(2) }); + dac.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.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); + dac.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.dac_cr.modify(|_, w| w.$en().clear_bit()); + dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(0) }); + dac.dac_cr.modify(|_, w| w.$cen().set_bit()); + let mut trim = 0; + while true { + dac.dac_ccr.modify(|_, w| unsafe { w.$trim().bits(trim) }); + delay.delay_us(64_u32); + if dac.dac_sr.read().$cal_flag().bit() { + break; + } + trim += 1; + } + dac.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.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.dac_swtrgr.write(|w| { w.$swtrig().set_bit() }); + } + } + )+ + }; +} + +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) + } +} + +dac!( + Channel1: + ( + en1, + cen1, + cal_flag1, + otrim1, + mode1, + dac_dhr12r1, + dac_dor1, + dacc1dhr, + wave1, + mamp1, + ten1, + swtrig1 + ), + Channel2: + ( + en2, + cen2, + cal_flag2, + otrim2, + mode2, + dac_dhr12r2, + dac_dor2, + dacc2dhr, + wave2, + mamp2, + ten2, + swtrig2 + ), +); diff --git a/src/lib.rs b/src/lib.rs index 43640ce6..ab3508c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,8 +63,9 @@ pub use crate::stm32::interrupt; pub mod adc; pub mod bb; pub mod can; +pub mod comparator; // pub mod crc; -// pub mod dac; +pub mod dac; pub mod delay; pub mod dma; pub mod exti; From 3c68d701b4491b2b0de629f1fd0bd69948beeb55 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 31 May 2023 07:52:18 +0200 Subject: [PATCH 02/18] Both examples/comp.rs and examples/dac.rs seems to be working --- examples/comp.rs | 56 ++++++ examples/dac.rs | 49 +++++ src/comparator.rs | 502 ++++++++++++++++++++++++++++++++-------------- src/dac.rs | 145 ++++++++----- 4 files changed, 552 insertions(+), 200 deletions(-) create mode 100644 examples/comp.rs create mode 100644 examples/dac.rs diff --git a/examples/comp.rs b/examples/comp.rs new file mode 100644 index 00000000..629878e1 --- /dev/null +++ b/examples/comp.rs @@ -0,0 +1,56 @@ +//#![deny(warnings)] +#![deny(unsafe_code)] +#![no_main] +#![no_std] + +use hal::adc::config::SampleTime; +use hal::adc::{AdcClaim, ClockSource}; +use hal::comparator::{ComparatorExt, ComparatorSplit, Config, Hysteresis, RefintInput}; +use hal::delay::SYSTDelayExt; +use hal::gpio::GpioExt; +use hal::prelude::OutputPin; +use hal::rcc::RccExt; +use stm32g4xx_hal as hal; +mod utils; +extern crate cortex_m_rt as rt; + +use hal::stm32; +use rt::entry; + +#[entry] +fn main() -> ! { + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let mut rcc = dp.RCC.constrain(); + + let gpioa = dp.GPIOA.split(&mut rcc); + + let (comp1, comp2, ..) = dp.COMP.split(&mut rcc); + + let pa1 = gpioa.pa1.into_analog(); + let pa0 = gpioa.pa0.into_analog(); + let comp1 = comp1.comparator(pa1, pa0, Config::default(), &rcc.clocks); + let comp1 = comp1.enable(); + let mut led1 = gpioa.pa5.into_push_pull_output(); + + let pa7 = gpioa.pa7.into_analog(); + let comp2 = comp2.comparator( + pa7, + RefintInput::VRefintM12, + Config::default() + .hysteresis(Hysteresis::None) + .output_inverted(), + &rcc.clocks, + ); + let led2 = gpioa.pa12.into_push_pull_output(); + // Configure PA12 to the comparator's alternate function so it gets + // changed directly by the comparator. + comp2.output_pin(led2); + let _comp2 = comp2.enable().lock(); + + loop { + match comp1.output() { + true => led1.set_high().unwrap(), + false => led1.set_low().unwrap(), + } + } +} diff --git a/examples/dac.rs b/examples/dac.rs new file mode 100644 index 00000000..e9d329fb --- /dev/null +++ b/examples/dac.rs @@ -0,0 +1,49 @@ +// #![deny(warnings)] +#![deny(unsafe_code)] +#![no_main] +#![no_std] + +use embedded_hal::Direction; +use hal::dac::{DacExt, DacOut, GeneratorConfig}; +use hal::delay::SYSTDelayExt; +use hal::gpio::GpioExt; +use hal::rcc::RccExt; +use stm32g4xx_hal as hal; +mod utils; +extern crate cortex_m_rt as rt; + +use hal::stm32; +use rt::entry; + +#[entry] +fn main() -> ! { + 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 delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + let (dac1ch1, dac1ch2) = dp.DAC1.constrain((gpioa.pa4, gpioa.pa5), &mut rcc); + + let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable(); + let mut generator = dac1ch2.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, + } + } +} diff --git a/src/comparator.rs b/src/comparator.rs index 452bc0c2..39f1757b 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -1,19 +1,63 @@ //! Comparator +//! +//! ## Origin +//! +//! This code has been taken from the stm32g0xx-hal project and modified slightly to support +//! STM32G4xx MCUs. use core::marker::PhantomData; use crate::dac; use crate::exti::{Event as ExtiEvent, ExtiExt}; +use crate::gpio::gpioa::{PA0, PA1, PA11, PA12, PA2, PA3, PA4, PA5, PA6, PA7}; +use crate::gpio::gpiob::{PB0, PB1, PB14, PB2, PB6, PB7, PB8, PB9}; use crate::gpio::*; -use crate::gpio::gpiob::PB14; + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +use crate::gpio::gpioa::{PA10, PA8, PA9}; + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +use crate::gpio::gpiob::{PB10, PB11, PB12, PB13, PB15}; + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +use crate::gpio::gpioc::{PC6, PC7, PC8}; + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +use crate::gpio::gpiod::{PD10, PD11, PD12, PD13, PD15}; + +use crate::gpio::gpioc::{PC0, PC1, PC2}; use crate::gpio::gpiod::PD14; +use crate::gpio::gpioe::{PE7, PE8}; +use crate::gpio::gpiof::{PF1, PF4}; use crate::rcc::{Clocks, Rcc}; -use crate::stm32::comp::{C1CSR, C2CSR}; use crate::stm32::{COMP, EXTI}; /// Enabled Comparator (type state) pub struct Enabled; +/// Enabled and locked (config is read only) +pub struct Locked; + /// Disabled Comparator (type state) pub struct Disabled; @@ -21,12 +65,16 @@ pub trait ED {} impl ED for Enabled {} impl ED for Disabled {} +pub trait EnabledState {} +impl EnabledState for Enabled {} +impl EnabledState for Locked {} + macro_rules! impl_comp { ($($t:ident: $reg_t:ident, $reg:ident,)+) => {$( pub struct $t { _rb: PhantomData<()>, } - + impl $t { pub fn csr(&self) -> &$crate::stm32::comp::$reg_t { // SAFETY: The COMP1 type is only constructed with logical ownership of @@ -37,14 +85,19 @@ macro_rules! impl_comp { )+}; } -impl_comp!{ +impl_comp! { COMP1: C1CSR, c1csr, COMP2: C2CSR, c2csr, COMP3: C3CSR, c3csr, COMP4: C4CSR, c4csr, } -#[cfg(any(feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484"))] -impl_comp!{ +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +impl_comp! { COMP5: C5CSR, c5csr, COMP6: C6CSR, c6csr, COMP7: C7CSR, c7csr, @@ -54,10 +107,10 @@ impl_comp!{ #[derive(Copy, Clone, Eq, PartialEq)] pub struct Config { - power_mode: PowerMode, + //power_mode: PowerMode, hysteresis: Hysteresis, inverted: bool, - output_xor: bool, + //output_xor: bool, } impl Default for Config { @@ -65,8 +118,8 @@ impl Default for Config { Self { hysteresis: Hysteresis::None, inverted: false, - power_mode: PowerMode::HighSpeed, - output_xor: false, + //power_mode: PowerMode::HighSpeed, + //output_xor: false, } } } @@ -87,25 +140,31 @@ impl Config { self } + /* pub fn power_mode(mut self, power_mode: PowerMode) -> Self { self.power_mode = power_mode; self - } + }*/ + /* /// Sets the output to be Comparator 1 XOR Comparator 2. /// Used to implement window comparator mode. pub fn output_xor(mut self) -> Self { self.output_xor = true; self - } + }*/ } #[derive(Copy, Clone, Eq, PartialEq)] pub enum Hysteresis { - None = 0b00, - Low = 0b01, - Medium = 0b10, - High = 0b11, + None = 0b000, + H10mV = 0b001, + H20mV = 0b010, + H30mV = 0b011, + H40mV = 0b100, + H50mV = 0b101, + H60mV = 0b110, + H70mV = 0b111, } #[derive(Copy, Clone, Eq, PartialEq)] @@ -121,24 +180,18 @@ pub trait PositiveInput { /// Comparator negative input pub trait NegativeInput { - fn setup(&self, comp: &C); -} - -/// 1/4 Vref -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct Vref1div4; - -/// 1/2 Vref -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct Vref1div2; + /// Does this input use the internal reference Vrefint + /// + /// This only true for RefintInput + const USE_VREFINT: bool; -/// 3/4 Vref -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct Vref3div4; + /// Does this input rely on dividing Vrefint using an internal resistor divider + /// + /// This is only relevant for `RefintInput` other than `RefintInput::VRefint` + fn use_resistor_divider(&self) -> bool; -/// Vref -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct Vref; + fn setup(&self, comp: &C); +} /* /// Comparator 1 positive input used as positive input for Comparator 2. @@ -167,38 +220,59 @@ window_input_pin!(COMP2, Comp1InP); */ macro_rules! positive_input_pin { - ($COMP:ident, $pin_0:ty, $pin_1:ty) => { - impl PositiveInput<$COMP> for $pin_0 { + ($COMP:ident, $pin_0:ident, $pin_1:ident) => { + impl PositiveInput<$COMP> for $pin_0 { fn setup(&self, comp: &$COMP) { - comp.csr().modify(|_, w| unsafe { w.inpsel().bit(0) }) + comp.csr().modify(|_, w| w.inpsel().bit(false)) } } - impl PositiveInput<$COMP> for $pin_1 { + impl PositiveInput<$COMP> for $pin_1 { fn setup(&self, comp: &$COMP) { - comp.csr().modify(|_, w| unsafe { w.inpsel().bit(1) }) + comp.csr().modify(|_, w| w.inpsel().bit(true)) } } }; } -positive_input_pin!(COMP1, PA1, PB1); -positive_input_pin!(COMP2, PA7, PA3); -positive_input_pin!(COMP3, PA0, PC1); -positive_input_pin!(COMP4, PB0, PE7); - -#[cfg(any(feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484"))] -positive_input_pin!(COMP5, PB13, PD12); - -#[cfg(any(feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484"))] -positive_input_pin!(COMP6, PB11, PD11); - -#[cfg(any(feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484"))] -positive_input_pin!(COMP7, PB14, PD14); +positive_input_pin!(COMP1, PA1, PB1); +positive_input_pin!(COMP2, PA7, PA3); +positive_input_pin!(COMP3, PA0, PC1); +positive_input_pin!(COMP4, PB0, PE7); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +positive_input_pin!(COMP5, PB13, PD12); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +positive_input_pin!(COMP6, PB11, PD11); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +positive_input_pin!(COMP7, PB14, PD14); macro_rules! negative_input_pin_helper { ($COMP:ident, $input:ty, $bits:expr) => { impl NegativeInput<$COMP> for $input { + const USE_VREFINT: bool = false; + + fn use_resistor_divider(&self) -> bool { + false + } + fn setup(&self, comp: &$COMP) { comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) }) } @@ -207,53 +281,79 @@ macro_rules! negative_input_pin_helper { } macro_rules! negative_input_pin { - ($($COMP:ident: $dac_0:ty, $dac_1:ty, $pin_0:ty, $pin_1:ty,)+) => {$( - negative_input_pin_helper($COMP, Vref1div4, 0b000); - negative_input_pin_helper($COMP, Vref1div2, 0b001); - negative_input_pin_helper($COMP, Vref3div4, 0b010); - negative_input_pin_helper($COMP, Vref, 0b011); - - //negative_input_pin_helper($COMP, $dac_0, 0b100); - //negative_input_pin_helper($COMP, $dac_1, 0b101); - - negative_input_pin_helper($COMP, $pin_0, 0b110); - negative_input_pin_helper($COMP, $pin_1, 0b111); + ($($COMP:ident: $pin_0:ty, $pin_1:ty,)+) => {$( + negative_input_pin_helper!($COMP, $pin_0, 0b110); + negative_input_pin_helper!($COMP, $pin_1, 0b111); )+}; } -/// TODO: Add DAC support -struct TodoAddDac; - -negative_input_pin!{ - COMP1: TodoAddDac, TodoAddDac, PA4, PA0, - COMP2: TodoAddDac, TodoAddDac, PA5, PA2, - COMP3: TodoAddDac, TodoAddDac, PF1, PC0, - COMP4: TodoAddDac, TodoAddDac, PE8, PB2, +negative_input_pin! { + COMP1: PA4, PA0, + COMP2: PA5, PA2, + COMP3: PF1, PC0, + COMP4: PE8, PB2, } -#[cfg(any(feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484"))] -negative_input_pin!{ - COMP5: TodoAddDac, TodoAddDac, PB10, PD13, - COMP6: TodoAddDac, TodoAddDac, PD10, PB15, - COMP7: TodoAddDac, TodoAddDac, PD15, PB12, -}; +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +negative_input_pin! { + COMP5: PB10, PD13, + COMP6: PD10, PB15, + COMP7: PD15, PB12, +} #[derive(Copy, Clone, Eq, PartialEq)] pub enum RefintInput { /// VRefint * 1/4 - VRefintM14 = 0b0000, + VRefintM14 = 0b000, /// VRefint * 1/2 - VRefintM12 = 0b0001, + VRefintM12 = 0b001, /// VRefint * 3/4 - VRefintM34 = 0b0010, + VRefintM34 = 0b010, /// VRefint - VRefint = 0b0011, + VRefint = 0b011, } -/* +macro_rules! refint_input { + ($($COMP:ident, )+) => {$( + impl NegativeInput<$COMP> for RefintInput { + const USE_VREFINT: bool = true; + + fn use_resistor_divider(&self) -> bool { + *self != RefintInput::VRefint + } + + fn setup(&self, comp: &$COMP) { + comp.csr() + .modify(|_, w| unsafe { w.inmsel().bits(*self as u8) }) + } + } + )+}; +} + +refint_input!(COMP1, COMP2, COMP3, COMP4,); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +refint_input!(COMP5, COMP6, COMP7,); + macro_rules! dac_input { - ($COMP:ident, $channel:ty, $bits:expr) => { + ($COMP:ident: $channel:ty, $bits:expr) => { impl NegativeInput<$COMP> for &$channel { + const USE_VREFINT: bool = false; + + fn use_resistor_divider(&self) -> bool { + false + } + fn setup(&self, comp: &$COMP) { comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) }) } @@ -261,15 +361,62 @@ macro_rules! dac_input { }; } -#[cfg(any(feature = "stm32g071", feature = "stm32g081"))] -dac_input!(COMP1, dac::Channel1, 0b0100); -#[cfg(any(feature = "stm32g071", feature = "stm32g081"))] -dac_input!(COMP1, dac::Channel2, 0b0101); - -#[cfg(any(feature = "stm32g071", feature = "stm32g081"))] -dac_input!(COMP2, dac::Channel1, 0b0100); -#[cfg(any(feature = "stm32g071", feature = "stm32g081"))] -dac_input!(COMP2, dac::Channel2, 0b0101);*/ +dac_input!(COMP1: dac::Dac3Ch1, 0b100); +dac_input!(COMP1: dac::Dac1Ch1, 0b101); + +dac_input!(COMP2: dac::Dac3Ch2, 0b100); +dac_input!(COMP2: dac::Dac1Ch2, 0b101); + +dac_input!(COMP3: dac::Dac3Ch1, 0b100); +dac_input!(COMP3: dac::Dac1Ch1, 0b101); + +dac_input!(COMP4: dac::Dac3Ch2, 0b100); +dac_input!(COMP4: dac::Dac1Ch1, 0b101); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +dac_input!(COMP5: dac::Dac4Ch1, 0b100); +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +dac_input!(COMP5: dac::Dac1Ch2, 0b101); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +dac_input!(COMP6: dac::Dac4Ch2, 0b100); +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +dac_input!(COMP6: dac::Dac2Ch1, 0b101); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +dac_input!(COMP7: dac::Dac4Ch1, 0b100); +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +dac_input!(COMP7: dac::Dac2Ch1, 0b101); pub struct Comparator { regs: C, @@ -300,13 +447,15 @@ macro_rules! impl_comparator { positive_input.setup(&self); negative_input.setup(&self); // Delay for scaler voltage bridge initialization for certain negative inputs - let voltage_scaler_delay = clocks.sys_clk.raw() / (1_000_000 / 200); // 200us + let voltage_scaler_delay = clocks.sys_clk.0 / (1_000_000 / 200); // 200us cortex_m::asm::delay(voltage_scaler_delay); self.csr().modify(|_, w| unsafe { w.hyst() .bits(config.hysteresis as u8) - //.brgen() - //.set_bit() + .scalen() + .bit(N::USE_VREFINT) + .brgen() + .bit(negative_input.use_resistor_divider()) .pol() .bit(config.inverted) }); @@ -345,11 +494,22 @@ macro_rules! impl_comparator { } } - impl Comparator<$COMP, Enabled> { + impl Comparator<$COMP, ED> { /// Returns the value of the output of the comparator pub fn output(&self) -> bool { self.regs.csr().read().value().bit_is_set() } + } + + impl Comparator<$COMP, Enabled> { + pub fn lock(self) -> Comparator<$COMP, Locked> { + // Setting this bit turns all other bits into read only until restart + self.regs.csr().modify(|_, w| w.lock().set_bit()); + Comparator { + regs: self.regs, + _enabled: PhantomData, + } + } /// Disables the comparator pub fn disable(self) -> Comparator<$COMP, Disabled> { @@ -368,8 +528,8 @@ macro_rules! impl_comparator { } /// Returns `true` if the output signal interrupt is pending for the `edge` - pub fn is_pending(&self, edge: SignalEdge, exti: &EXTI) -> bool { - exti.is_pending($Event, edge) + pub fn is_pending(&self, exti: &EXTI) -> bool { + exti.is_pending($Event) } /// Unpends the output signal interrupt @@ -390,6 +550,7 @@ macro_rules! impl_comparator { impl_comparator!(COMP1, comp1, ExtiEvent::COMP1); impl_comparator!(COMP2, comp2, ExtiEvent::COMP2); +/* /// Uses two comparators to implement a window comparator. /// See Figure 69 in RM0444 Rev 5. pub struct WindowComparator { @@ -534,82 +695,125 @@ pub fn window_comparator21< ) -> WindowComparator { let (comp1, comp2) = comp.split(rcc); (comp2, comp1).window_comparator(input, lower_threshold, upper_threshold, config, &rcc.clocks) -} +}*/ + +#[cfg(not(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +)))] +type Comparators = (COMP1, COMP2, COMP3, COMP4); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +type Comparators = (COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7); /// Enables the comparator peripheral, and splits the [`COMP`] into independent [`COMP1`] and [`COMP2`] -pub fn split(_comp: COMP, rcc: &mut Rcc) -> (COMP1, COMP2) { +pub fn split(_comp: COMP, rcc: &mut Rcc) -> Comparators { // Enable COMP, SYSCFG, VREFBUF clocks - rcc.rb.apbenr2.modify(|_, w| w.syscfgen().set_bit()); + rcc.rb.apb2enr.modify(|_, w| w.syscfgen().set_bit()); // Reset COMP, SYSCFG, VREFBUF - rcc.rb.apbrstr2.modify(|_, w| w.syscfgrst().set_bit()); - rcc.rb.apbrstr2.modify(|_, w| w.syscfgrst().clear_bit()); - - (COMP1 { _rb: PhantomData }, COMP2 { _rb: PhantomData }) + rcc.rb.apb2rstr.modify(|_, w| w.syscfgrst().set_bit()); + rcc.rb.apb2rstr.modify(|_, w| w.syscfgrst().clear_bit()); + + ( + COMP1 { _rb: PhantomData }, + COMP2 { _rb: PhantomData }, + COMP3 { _rb: PhantomData }, + COMP4 { _rb: PhantomData }, + #[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" + ))] + COMP5 { _rb: PhantomData }, + #[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" + ))] + COMP6 { _rb: PhantomData }, + #[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" + ))] + COMP7 { _rb: PhantomData }, + ) } pub trait ComparatorSplit { /// Enables the comparator peripheral, and splits the [`COMP`] into independent [`COMP1`] and [`COMP2`] - fn split(self, rcc: &mut Rcc) -> (COMP1, COMP2); + fn split(self, rcc: &mut Rcc) -> Comparators; } impl ComparatorSplit for COMP { - fn split(self, rcc: &mut Rcc) -> (COMP1, COMP2) { + fn split(self, rcc: &mut Rcc) -> Comparators { split(self, rcc) } } pub trait OutputPin { - fn setup(&self); - fn release(self) -> Self; + fn setup(self); } -macro_rules! output_pin_push_pull { - ($COMP:ident, $pin:ty) => { - impl OutputPin<$COMP> for $pin { - fn setup(&self) { - self.set_alt_mode(AltFunction::AF7) - } - - fn release(self) -> Self { - self.into_push_pull_output() +macro_rules! output_pin { + ($COMP:ident, $pin:ident, $AF:ident, $mode_t:ident, $into:ident) => { + impl OutputPin<$COMP> for $pin> { + fn setup(self) { + self.$into::<$AF>(); } } }; + ($($COMP:ident: $pin:ident, $AF:ident,)+) => {$( + output_pin!($COMP, $pin, $AF, PushPull, into_alternate); + output_pin!($COMP, $pin, $AF, OpenDrain, into_alternate_open_drain); + )+}; } -macro_rules! output_pin_open_drain { - ($COMP:ident, $pin:ty) => { - impl OutputPin<$COMP> for $pin { - fn setup(&self) { - self.set_alt_mode(AltFunction::AF7) - } - - fn release(self) -> Self { - self.into_open_drain_output() - } - } - }; +output_pin! { + COMP1: PA0, AF8, + COMP1: PA6, AF8, + COMP1: PA11, AF8, + COMP1: PB8, AF8, + COMP1: PF4, AF2, + + COMP2: PA2, AF8, + COMP2: PA7, AF8, + COMP2: PA12, AF8, + COMP2: PB9, AF8, + + COMP3: PB7, AF8, + COMP3: PB15, AF3, + COMP3: PC2, AF3, + + COMP4: PB1, AF8, + COMP4: PB6, AF8, + COMP4: PB14, AF8, } -output_pin_push_pull!(COMP1, PA0>); -output_pin_open_drain!(COMP1, PA0>); -output_pin_push_pull!(COMP1, PA6>); -output_pin_open_drain!(COMP1, PA6>); -output_pin_push_pull!(COMP1, PA11>); -output_pin_open_drain!(COMP1, PA11>); -output_pin_push_pull!(COMP1, PB0>); -output_pin_open_drain!(COMP1, PB0>); -output_pin_push_pull!(COMP1, PB10>); -output_pin_open_drain!(COMP1, PB10>); - -output_pin_push_pull!(COMP2, PA2>); -output_pin_open_drain!(COMP2, PA2>); -output_pin_push_pull!(COMP2, PA7>); -output_pin_open_drain!(COMP2, PA7>); -output_pin_push_pull!(COMP2, PA12>); -output_pin_open_drain!(COMP2, PA12>); -output_pin_push_pull!(COMP2, PB5>); -output_pin_open_drain!(COMP2, PB5>); -output_pin_push_pull!(COMP2, PB11>); -output_pin_open_drain!(COMP2, PB11>); +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +output_pin! { + COMP5: PA9, AF8, + COMP5: PC7, AF7, + + COMP6: PA10, AF8, + COMP6: PC6, AF7, + + COMP7: PA8, AF8, + COMP7: PC8, AF7, +} diff --git a/src/dac.rs b/src/dac.rs index ac31cd53..b31745b9 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -1,11 +1,17 @@ //! DAC +//! +//! ## Origin +//! +//! This code has been taken from the stm32g0xx-hal project and modified slightly to support +//! STM32G4xx MCUs. use core::marker::PhantomData; use core::mem::MaybeUninit; -use crate::gpio::{DefaultMode, PA4, PA5}; -use crate::rcc::*; -use crate::stm32::DAC; +use crate::gpio::gpioa::{PA4, PA5, PA6}; +use crate::gpio::DefaultMode; +use crate::rcc::{self, *}; +use crate::stm32::{DAC1, DAC2, DAC3, DAC4, RCC}; use hal::blocking::delay::DelayUs; pub trait DacOut { @@ -26,6 +32,13 @@ impl GeneratorConfig { } } + pub fn sawtooth(amplitude: u8) -> Self { + Self { + mode: 0b11, + amp: amplitude, + } + } + pub fn noise(seed: u8) -> Self { Self { mode: 0b01, @@ -49,36 +62,53 @@ impl ED for EnabledUnbuffered {} impl ED for WaveGenerator {} impl ED for Disabled {} -pub struct Channel1 { - _enabled: PhantomData, -} -pub struct Channel2 { - _enabled: PhantomData, +macro_rules! impl_dac { + ($DACxCHy:ident) => { + pub struct $DACxCHy { + _enabled: PhantomData, + } + }; } +impl_dac!(Dac1Ch1); +impl_dac!(Dac1Ch2); +impl_dac!(Dac2Ch1); // DAC2 only has 1 channel +impl_dac!(Dac3Ch1); +impl_dac!(Dac3Ch2); +impl_dac!(Dac4Ch1); +impl_dac!(Dac4Ch2); + /// 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; +macro_rules! impl_pin_for_dac { + ($DAC:ident: $pin:ty, $output:ty) => { + impl Pins<$DAC> for $pin { + type Output = $output; + } + }; } -impl Pins for (PA4, PA5) { - type Output = (Channel1, Channel2); -} +impl_pin_for_dac!(DAC1: PA4, Dac1Ch1); +impl_pin_for_dac!(DAC1: PA5, Dac1Ch2); +impl_pin_for_dac!( + DAC1: (PA4, PA5), + (Dac1Ch1, Dac1Ch2) +); +impl_pin_for_dac!(DAC2: PA6, Dac2Ch1); -pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut Rcc) -> PINS::Output +pub fn dac(_dac: DAC, _pins: PINS, _rcc: &mut Rcc) -> PINS::Output where + DAC: rcc::Enable + rcc::Reset, PINS: Pins, { - DAC::enable(rcc); - DAC::reset(rcc); + unsafe { + let rcc_ptr = &(*RCC::ptr()); + DAC::enable(rcc_ptr); + DAC::reset(rcc_ptr); + } #[allow(clippy::uninit_assumed_init)] unsafe { @@ -86,8 +116,8 @@ where } } -macro_rules! dac { - ($($CX:ident: ( +macro_rules! dac_helper { + ($($CX:ident: $DAC:ty: ( $en:ident, $cen:ident, $cal_flag:ident, @@ -104,7 +134,7 @@ macro_rules! dac { $( impl $CX { pub fn enable(self) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; + let dac = unsafe { &(*<$DAC>::ptr()) }; dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); dac.dac_cr.modify(|_, w| w.$en().set_bit()); @@ -115,7 +145,7 @@ macro_rules! dac { } pub fn enable_unbuffered(self) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; + let dac = unsafe { &(*<$DAC>::ptr()) }; dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(2) }); dac.dac_cr.modify(|_, w| w.$en().set_bit()); @@ -126,7 +156,7 @@ macro_rules! dac { } pub fn enable_generator(self, config: GeneratorConfig) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; + let dac = unsafe { &(*<$DAC>::ptr()) }; dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); dac.dac_cr.modify(|_, w| unsafe { @@ -158,7 +188,7 @@ macro_rules! dac { where T: DelayUs, { - let dac = unsafe { &(*DAC::ptr()) }; + let dac = unsafe { &(*<$DAC>::ptr()) }; dac.dac_cr.modify(|_, w| w.$en().clear_bit()); dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(0) }); dac.dac_cr.modify(|_, w| w.$cen().set_bit()); @@ -180,7 +210,7 @@ macro_rules! dac { /// Disable the DAC channel pub fn disable(self) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; + let dac = unsafe { &(*<$DAC>::ptr()) }; dac.dac_cr.modify(|_, w| unsafe { w.$en().clear_bit().$wave().bits(0).$ten().clear_bit() }); @@ -195,12 +225,12 @@ macro_rules! dac { /// state impl DacOut for $CX { fn set_value(&mut self, val: u16) { - let dac = unsafe { &(*DAC::ptr()) }; + 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()) }; + let dac = unsafe { &(*<$DAC>::ptr()) }; dac.$dac_dor.read().bits() as u16 } } @@ -208,7 +238,7 @@ macro_rules! dac { /// Wave generator state implementation impl $CX { pub fn trigger(&mut self) { - let dac = unsafe { &(*DAC::ptr()) }; + let dac = unsafe { &(*<$DAC>::ptr()) }; dac.dac_swtrgr.write(|w| { w.$swtrig().set_bit() }); } } @@ -216,24 +246,9 @@ macro_rules! dac { }; } -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) - } -} - -dac!( - Channel1: - ( +macro_rules! dac { + ($($DAC:ident ch1: $DACxCH1:ident $(, ch2: $DACxCH2:ident)*)+) => {$( + dac_helper!{$DACxCH1: $DAC: ( en1, cen1, cal_flag1, @@ -247,8 +262,7 @@ dac!( ten1, swtrig1 ), - Channel2: - ( + $($DACxCH2: $DAC: ( en2, cen2, cal_flag2, @@ -261,5 +275,34 @@ dac!( mamp2, ten2, swtrig2 - ), + ),)*} + )+}; +} + +pub trait DacExt: Sized { + fn constrain(self, pins: PINS, rcc: &mut Rcc) -> PINS::Output + where + PINS: Pins; +} + +macro_rules! impl_dac_ext { + ($($DAC:ty, )+) => {$( + impl DacExt for $DAC { + fn constrain(self, pins: PINS, rcc: &mut Rcc) -> PINS::Output + where + PINS: Pins<$DAC>, + { + dac(self, pins, rcc) + } + } + )+}; +} + +impl_dac_ext!(DAC1, DAC2, DAC3, DAC4,); + +dac!( + DAC1 ch1: Dac1Ch1, ch2: Dac1Ch2 + DAC2 ch1: Dac2Ch1 + DAC3 ch1: Dac3Ch1, ch2: Dac3Ch2 + DAC4 ch1: Dac4Ch1, ch2: Dac4Ch2 ); From 6e4ac907dce1ef6464ddaf50ac371a5e23e6c5bb Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 31 May 2023 14:41:17 +0200 Subject: [PATCH 03/18] Examples fixed, tested and seems to work * Add support for comparator to take signal from dac as input * Added example for using dac as input to comparator --- examples/comp.rs | 3 -- examples/comp_w_dac.rs | 63 ++++++++++++++++++++++++++++++++ examples/dac.rs | 8 ++--- src/comparator.rs | 30 ++++++++-------- src/dac.rs | 82 +++++++++++++++++++++++++++++++----------- 5 files changed, 144 insertions(+), 42 deletions(-) create mode 100644 examples/comp_w_dac.rs diff --git a/examples/comp.rs b/examples/comp.rs index 629878e1..f5be49ea 100644 --- a/examples/comp.rs +++ b/examples/comp.rs @@ -3,10 +3,7 @@ #![no_main] #![no_std] -use hal::adc::config::SampleTime; -use hal::adc::{AdcClaim, ClockSource}; use hal::comparator::{ComparatorExt, ComparatorSplit, Config, Hysteresis, RefintInput}; -use hal::delay::SYSTDelayExt; use hal::gpio::GpioExt; use hal::prelude::OutputPin; use hal::rcc::RccExt; diff --git a/examples/comp_w_dac.rs b/examples/comp_w_dac.rs new file mode 100644 index 00000000..a001b962 --- /dev/null +++ b/examples/comp_w_dac.rs @@ -0,0 +1,63 @@ +// #![deny(warnings)] +#![deny(unsafe_code)] +#![no_main] +#![no_std] + +use embedded_hal::Direction; +use hal::comparator::{self, ComparatorExt, ComparatorSplit}; +use hal::dac::{Dac1IntSig1, DacExt, DacOut}; +use hal::delay::SYSTDelayExt; +use hal::gpio::GpioExt; +use hal::rcc::RccExt; +use stm32g4xx_hal as hal; +mod utils; +extern crate cortex_m_rt as rt; + +use hal::stm32; +use rt::entry; + +#[entry] +fn main() -> ! { + 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 delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + let dac1ch1 = dp.DAC1.constrain((gpioa.pa4, Dac1IntSig1), &mut rcc); + + let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable(); + + let (comp1, _comp2, ..) = dp.COMP.split(&mut rcc); + let pa1 = gpioa.pa1.into_analog(); + let comp = comp1.comparator( + pa1, + &dac, + comparator::Config::default().hysteresis(comparator::Hysteresis::None), + &rcc.clocks, + ); + + let led2 = gpioa.pa0.into_push_pull_output(); + // Configure PA12 to the comparator's alternate function so it gets + // changed directly by the comparator. + comp.output_pin(led2); + let _comp1 = comp.enable().lock(); + + let mut dir = Direction::Upcounting; + let mut val = 0; + + 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, + } + } +} diff --git a/examples/dac.rs b/examples/dac.rs index e9d329fb..6a28c8af 100644 --- a/examples/dac.rs +++ b/examples/dac.rs @@ -26,15 +26,15 @@ fn main() -> ! { let gpioa = dp.GPIOA.split(&mut rcc); let (dac1ch1, dac1ch2) = dp.DAC1.constrain((gpioa.pa4, gpioa.pa5), &mut rcc); - let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable(); - let mut generator = dac1ch2.enable_generator(GeneratorConfig::noise(11)); + let mut dac_manual = dac1ch1.calibrate_buffer(&mut delay).enable(); + let mut dac_generator = dac1ch2.enable_generator(GeneratorConfig::noise(11)); let mut dir = Direction::Upcounting; let mut val = 0; loop { - generator.trigger(); - dac.set_value(val); + dac_generator.trigger(); + dac_manual.set_value(val); match val { 0 => dir = Direction::Upcounting, 4095 => dir = Direction::Downcounting, diff --git a/src/comparator.rs b/src/comparator.rs index 39f1757b..c44f244f 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -347,7 +347,7 @@ refint_input!(COMP5, COMP6, COMP7,); macro_rules! dac_input { ($COMP:ident: $channel:ty, $bits:expr) => { - impl NegativeInput<$COMP> for &$channel { + impl NegativeInput<$COMP> for &$channel { const USE_VREFINT: bool = false; fn use_resistor_divider(&self) -> bool { @@ -361,17 +361,17 @@ macro_rules! dac_input { }; } -dac_input!(COMP1: dac::Dac3Ch1, 0b100); -dac_input!(COMP1: dac::Dac1Ch1, 0b101); +dac_input!(COMP1: dac::Dac3Ch1, 0b100); +dac_input!(COMP1: dac::Dac1Ch1, 0b101); -dac_input!(COMP2: dac::Dac3Ch2, 0b100); -dac_input!(COMP2: dac::Dac1Ch2, 0b101); +dac_input!(COMP2: dac::Dac3Ch2, 0b100); +dac_input!(COMP2: dac::Dac1Ch2, 0b101); -dac_input!(COMP3: dac::Dac3Ch1, 0b100); -dac_input!(COMP3: dac::Dac1Ch1, 0b101); +dac_input!(COMP3: dac::Dac3Ch1, 0b100); +dac_input!(COMP3: dac::Dac1Ch1, 0b101); -dac_input!(COMP4: dac::Dac3Ch2, 0b100); -dac_input!(COMP4: dac::Dac1Ch1, 0b101); +dac_input!(COMP4: dac::Dac3Ch2, 0b100); +dac_input!(COMP4: dac::Dac1Ch1, 0b101); #[cfg(any( feature = "stm32g473", @@ -379,14 +379,14 @@ dac_input!(COMP4: dac::Dac1Ch1, 0b101); feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP5: dac::Dac4Ch1, 0b100); +dac_input!(COMP5: dac::Dac4Ch1, 0b100); #[cfg(any( feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP5: dac::Dac1Ch2, 0b101); +dac_input!(COMP5: dac::Dac1Ch2, 0b101); #[cfg(any( feature = "stm32g473", @@ -394,14 +394,14 @@ dac_input!(COMP5: dac::Dac1Ch2, 0b101); feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP6: dac::Dac4Ch2, 0b100); +dac_input!(COMP6: dac::Dac4Ch2, 0b100); #[cfg(any( feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP6: dac::Dac2Ch1, 0b101); +dac_input!(COMP6: dac::Dac2Ch1, 0b101); #[cfg(any( feature = "stm32g473", @@ -409,14 +409,14 @@ dac_input!(COMP6: dac::Dac2Ch1, 0b101); feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP7: dac::Dac4Ch1, 0b100); +dac_input!(COMP7: dac::Dac4Ch1, 0b100); #[cfg(any( feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP7: dac::Dac2Ch1, 0b101); +dac_input!(COMP7: dac::Dac2Ch1, 0b101); pub struct Comparator { regs: C, diff --git a/src/dac.rs b/src/dac.rs index b31745b9..b61a74c7 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -64,7 +64,7 @@ impl ED for Disabled {} macro_rules! impl_dac { ($DACxCHy:ident) => { - pub struct $DACxCHy { + pub struct $DACxCHy { _enabled: PhantomData, } }; @@ -83,21 +83,63 @@ pub trait Pins { type Output; } +const M_EXT_PIN: u8 = 0b000; +const M_MIX_SIG: u8 = 0b001; +const M_INT_SIG: u8 = 0b011; + +pub struct Dac1IntSig1; +pub struct Dac1IntSig2; +pub struct Dac2IntSig1; +pub struct Dac3IntSig1; +pub struct Dac3IntSig2; +pub struct Dac4IntSig1; +pub struct Dac4IntSig2; + macro_rules! impl_pin_for_dac { ($DAC:ident: $pin:ty, $output:ty) => { + #[allow(unused_parens)] impl Pins<$DAC> for $pin { + #[allow(unused_parens)] type Output = $output; } }; } -impl_pin_for_dac!(DAC1: PA4, Dac1Ch1); -impl_pin_for_dac!(DAC1: PA5, Dac1Ch2); -impl_pin_for_dac!( - DAC1: (PA4, PA5), - (Dac1Ch1, Dac1Ch2) -); -impl_pin_for_dac!(DAC2: PA6, Dac2Ch1); +// Implement all combinations of ch2 for the specified ch1 on DAC1 +macro_rules! impl_dac1_ch2_combos { + ($($pin_ch1:ty, $output_ch1:ty)*) => { + $(impl_pin_for_dac!(DAC1: $pin_ch1, // ch2: Not used + $output_ch1 + );)* + impl_pin_for_dac!(DAC1: ($($pin_ch1,)* PA5), // ch2: Ext pin + ($($output_ch1,)* Dac1Ch2) + ); + impl_pin_for_dac!(DAC1: ($($pin_ch1,)* Dac1IntSig2), // ch2: Internal + ($($output_ch1,)* Dac1Ch2) + ); + impl_pin_for_dac!(DAC1: ($($pin_ch1,)* (PA5, Dac1IntSig2)),// ch2: Mixed + ($($output_ch1,)* Dac1Ch2) + ); + }; +} + +impl_dac1_ch2_combos!(); // ch1: Not used +impl_dac1_ch2_combos!(PA4, Dac1Ch1); // ch1: Ext pin +impl_dac1_ch2_combos!(Dac1IntSig1, Dac1Ch1); // ch1: Internal +impl_dac1_ch2_combos!((PA4, Dac1IntSig1), Dac1Ch1); // ch1: Mixed + +// DAC2 +impl_pin_for_dac!(DAC2: PA6, Dac2Ch1); // ch1: Ext pin +impl_pin_for_dac!(DAC2: Dac2IntSig1, Dac2Ch1); // ch1: Internal +impl_pin_for_dac!(DAC2: (PA6, Dac2IntSig1), Dac2Ch1); // ch1: Mixed + +// DAC3 int +impl_pin_for_dac!(DAC3: Dac3IntSig1, Dac3Ch1); +impl_pin_for_dac!(DAC3: Dac3IntSig2, Dac3Ch2); + +// DAC4 int +impl_pin_for_dac!(DAC4: Dac4IntSig1, Dac4Ch1); +impl_pin_for_dac!(DAC4: Dac4IntSig2, Dac4Ch2); pub fn dac(_dac: DAC, _pins: PINS, _rcc: &mut Rcc) -> PINS::Output where @@ -132,11 +174,11 @@ macro_rules! dac_helper { $swtrig:ident ),)+) => { $( - impl $CX { - pub fn enable(self) -> $CX { + impl $CX { + pub fn enable(self) -> $CX { let dac = unsafe { &(*<$DAC>::ptr()) }; - dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); + dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(MODE_BITS) }); dac.dac_cr.modify(|_, w| w.$en().set_bit()); $CX { @@ -144,7 +186,7 @@ macro_rules! dac_helper { } } - pub fn enable_unbuffered(self) -> $CX { + /*pub fn enable_unbuffered(self) -> $CX { let dac = unsafe { &(*<$DAC>::ptr()) }; dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(2) }); @@ -153,12 +195,12 @@ macro_rules! dac_helper { $CX { _enabled: PhantomData, } - } + }*/ - pub fn enable_generator(self, config: GeneratorConfig) -> $CX { + pub fn enable_generator(self, config: GeneratorConfig) -> $CX { let dac = unsafe { &(*<$DAC>::ptr()) }; - dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); + dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(MODE_BITS) }); dac.dac_cr.modify(|_, w| unsafe { w.$wave().bits(config.mode); w.$ten().set_bit(); @@ -172,7 +214,7 @@ macro_rules! dac_helper { } } - impl $CX { + 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 @@ -184,7 +226,7 @@ macro_rules! dac_helper { /// /// After the calibration operation, the DAC channel is /// disabled. - pub fn calibrate_buffer(self, delay: &mut T) -> $CX + pub fn calibrate_buffer(self, delay: &mut T) -> $CX where T: DelayUs, { @@ -209,7 +251,7 @@ macro_rules! dac_helper { } /// Disable the DAC channel - pub fn disable(self) -> $CX { + pub fn disable(self) -> $CX { let dac = unsafe { &(*<$DAC>::ptr()) }; dac.dac_cr.modify(|_, w| unsafe { w.$en().clear_bit().$wave().bits(0).$ten().clear_bit() @@ -223,7 +265,7 @@ macro_rules! dac_helper { /// DacOut implementation available in any Enabled/Disabled /// state - impl DacOut for $CX { + 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) }); @@ -236,7 +278,7 @@ macro_rules! dac_helper { } /// Wave generator state implementation - impl $CX { + impl $CX { pub fn trigger(&mut self) { let dac = unsafe { &(*<$DAC>::ptr()) }; dac.dac_swtrgr.write(|w| { w.$swtrig().set_bit() }); From b3ce8c2e98c6ce03b4be5b40271bbc8dc59b3480 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 31 May 2023 15:24:23 +0200 Subject: [PATCH 04/18] Prevent using dac with incorrect mode as input to comparator --- src/comparator.rs | 41 ++++++++++++++++++++++++----------------- src/dac.rs | 11 ++++++++--- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/comparator.rs b/src/comparator.rs index c44f244f..7318c23b 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -345,9 +345,9 @@ refint_input!(COMP1, COMP2, COMP3, COMP4,); ))] refint_input!(COMP5, COMP6, COMP7,); -macro_rules! dac_input { - ($COMP:ident: $channel:ty, $bits:expr) => { - impl NegativeInput<$COMP> for &$channel { +macro_rules! dac_input_helper { + ($COMP:ident: $channel:ident, $MODE:ident, $bits:expr) => { + impl NegativeInput<$COMP> for &dac::$channel<{dac::$MODE}, ED> { const USE_VREFINT: bool = false; fn use_resistor_divider(&self) -> bool { @@ -361,17 +361,24 @@ macro_rules! dac_input { }; } -dac_input!(COMP1: dac::Dac3Ch1, 0b100); -dac_input!(COMP1: dac::Dac1Ch1, 0b101); +macro_rules! dac_input { + ($COMP:ident: $channel:ident, $bits:expr) => { + dac_input_helper!($COMP: $channel, M_MIX_SIG, $bits); + dac_input_helper!($COMP: $channel, M_INT_SIG, $bits); + }; +} + +dac_input!(COMP1: Dac3Ch1, 0b100); +dac_input!(COMP1: Dac1Ch1, 0b101); -dac_input!(COMP2: dac::Dac3Ch2, 0b100); -dac_input!(COMP2: dac::Dac1Ch2, 0b101); +dac_input!(COMP2: Dac3Ch2, 0b100); +dac_input!(COMP2: Dac1Ch2, 0b101); -dac_input!(COMP3: dac::Dac3Ch1, 0b100); -dac_input!(COMP3: dac::Dac1Ch1, 0b101); +dac_input!(COMP3: Dac3Ch1, 0b100); +dac_input!(COMP3: Dac1Ch1, 0b101); -dac_input!(COMP4: dac::Dac3Ch2, 0b100); -dac_input!(COMP4: dac::Dac1Ch1, 0b101); +dac_input!(COMP4: Dac3Ch2, 0b100); +dac_input!(COMP4: Dac1Ch1, 0b101); #[cfg(any( feature = "stm32g473", @@ -379,14 +386,14 @@ dac_input!(COMP4: dac::Dac1Ch1, 0b101); feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP5: dac::Dac4Ch1, 0b100); +dac_input!(COMP5: Dac4Ch1, 0b100); #[cfg(any( feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP5: dac::Dac1Ch2, 0b101); +dac_input!(COMP5: Dac1Ch2, 0b101); #[cfg(any( feature = "stm32g473", @@ -394,14 +401,14 @@ dac_input!(COMP5: dac::Dac1Ch2, 0b101); feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP6: dac::Dac4Ch2, 0b100); +dac_input!(COMP6: Dac4Ch2, 0b100); #[cfg(any( feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP6: dac::Dac2Ch1, 0b101); +dac_input!(COMP6: Dac2Ch1, 0b101); #[cfg(any( feature = "stm32g473", @@ -409,14 +416,14 @@ dac_input!(COMP6: dac::Dac2Ch1, 0b101); feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP7: dac::Dac4Ch1, 0b100); +dac_input!(COMP7: Dac4Ch1, 0b100); #[cfg(any( feature = "stm32g473", feature = "stm32g483", feature = "stm32g474", feature = "stm32g484" ))] -dac_input!(COMP7: dac::Dac2Ch1, 0b101); +dac_input!(COMP7: Dac2Ch1, 0b101); pub struct Comparator { regs: C, diff --git a/src/dac.rs b/src/dac.rs index b61a74c7..b816efc5 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -83,9 +83,14 @@ pub trait Pins { type Output; } -const M_EXT_PIN: u8 = 0b000; -const M_MIX_SIG: u8 = 0b001; -const M_INT_SIG: u8 = 0b011; +/// Dac output mode: external pin only +pub const M_EXT_PIN: u8 = 0b000; + +/// Dac output mode: internal signal and external pin +pub const M_MIX_SIG: u8 = 0b001; + +/// Dac output mode: internal signal only +pub const M_INT_SIG: u8 = 0b011; pub struct Dac1IntSig1; pub struct Dac1IntSig2; From bc73e38df73209c902e45f69b1693ff4282208b2 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 31 May 2023 15:29:32 +0200 Subject: [PATCH 05/18] Update comments and fmt --- examples/comp.rs | 5 +++++ examples/dac.rs | 5 +++++ src/comparator.rs | 2 +- src/dac.rs | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/comp.rs b/examples/comp.rs index f5be49ea..0e866dac 100644 --- a/examples/comp.rs +++ b/examples/comp.rs @@ -1,3 +1,8 @@ +//! ## Origin +//! +//! This code has been taken from the stm32g0xx-hal project and modified slightly to support +//! STM32G4xx MCUs. + //#![deny(warnings)] #![deny(unsafe_code)] #![no_main] diff --git a/examples/dac.rs b/examples/dac.rs index 6a28c8af..ce00a88e 100644 --- a/examples/dac.rs +++ b/examples/dac.rs @@ -1,3 +1,8 @@ +//! ## Origin +//! +//! This code has been taken from the stm32g0xx-hal project and modified to support +//! STM32G4xx MCUs. + // #![deny(warnings)] #![deny(unsafe_code)] #![no_main] diff --git a/src/comparator.rs b/src/comparator.rs index 7318c23b..743a9d1b 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -347,7 +347,7 @@ refint_input!(COMP5, COMP6, COMP7,); macro_rules! dac_input_helper { ($COMP:ident: $channel:ident, $MODE:ident, $bits:expr) => { - impl NegativeInput<$COMP> for &dac::$channel<{dac::$MODE}, ED> { + impl NegativeInput<$COMP> for &dac::$channel<{ dac::$MODE }, ED> { const USE_VREFINT: bool = false; fn use_resistor_divider(&self) -> bool { diff --git a/src/dac.rs b/src/dac.rs index b816efc5..9f2e6832 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -2,7 +2,7 @@ //! //! ## Origin //! -//! This code has been taken from the stm32g0xx-hal project and modified slightly to support +//! This code has been taken from the stm32g0xx-hal project and modified to support //! STM32G4xx MCUs. use core::marker::PhantomData; From 5f3c63b6523bdd918936b2d30567ba3e19a79d94 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 2 Jun 2023 20:31:39 +0200 Subject: [PATCH 06/18] Clean up examples --- examples/comp.rs | 3 +++ examples/comp_w_dac.rs | 12 +++++++++++- examples/dac.rs | 7 +++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/examples/comp.rs b/examples/comp.rs index 0e866dac..79f914d3 100644 --- a/examples/comp.rs +++ b/examples/comp.rs @@ -32,6 +32,8 @@ fn main() -> ! { let pa0 = gpioa.pa0.into_analog(); let comp1 = comp1.comparator(pa1, pa0, Config::default(), &rcc.clocks); let comp1 = comp1.enable(); + + // led1 pa1 will be updated manually when to match comp1 value let mut led1 = gpioa.pa5.into_push_pull_output(); let pa7 = gpioa.pa7.into_analog(); @@ -50,6 +52,7 @@ fn main() -> ! { let _comp2 = comp2.enable().lock(); loop { + // Read comp1 output and update led1 accordingly match comp1.output() { true => led1.set_high().unwrap(), false => led1.set_low().unwrap(), diff --git a/examples/comp_w_dac.rs b/examples/comp_w_dac.rs index a001b962..aa57e0a0 100644 --- a/examples/comp_w_dac.rs +++ b/examples/comp_w_dac.rs @@ -25,12 +25,16 @@ fn main() -> ! { let mut delay = cp.SYST.delay(&rcc.clocks); let gpioa = dp.GPIOA.split(&mut rcc); - let dac1ch1 = dp.DAC1.constrain((gpioa.pa4, Dac1IntSig1), &mut rcc); + // Set up DAC to output to pa4 and to internal signal Dac1IntSig1 + // which just so happens is compatible with comp1 + let dac1ch1 = dp.DAC1.constrain((gpioa.pa4, Dac1IntSig1), &mut rcc); let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable(); let (comp1, _comp2, ..) = dp.COMP.split(&mut rcc); let pa1 = gpioa.pa1.into_analog(); + + // Set up comparator with pa1 as positive, and the DAC as negative input let comp = comp1.comparator( pa1, &dac, @@ -47,6 +51,12 @@ fn main() -> ! { let mut dir = Direction::Upcounting; let mut val = 0; + // Manually step the DAC's value to produce a triangle wave + // + // This will produce a pwm-like signal at pa0 with the duty controlled by pa1 + // where + // * 0V at p1 => 0% duty + // * VDDA at p1 => 100% duty loop { dac.set_value(val); match val { diff --git a/examples/dac.rs b/examples/dac.rs index ce00a88e..7348f703 100644 --- a/examples/dac.rs +++ b/examples/dac.rs @@ -31,14 +31,20 @@ fn main() -> ! { let gpioa = dp.GPIOA.split(&mut rcc); let (dac1ch1, dac1ch2) = dp.DAC1.constrain((gpioa.pa4, gpioa.pa5), &mut rcc); + // dac_manual will have its value set manually let mut dac_manual = dac1ch1.calibrate_buffer(&mut delay).enable(); + + // dac_generator will have its value set automatically from its internal noise generator let mut dac_generator = dac1ch2.enable_generator(GeneratorConfig::noise(11)); let mut dir = Direction::Upcounting; let mut val = 0; loop { + // This will pull out a new value from the noise generator and apply it to the DAC dac_generator.trigger(); + + // This will manually set the DAC's value dac_manual.set_value(val); match val { 0 => dir = Direction::Upcounting, @@ -46,6 +52,7 @@ fn main() -> ! { _ => (), }; + // Step manually set value as a triangle wave match dir { Direction::Upcounting => val += 1, Direction::Downcounting => val -= 1, From fda37a4daed92738bd5aaccd99694a3c740d4404 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 2 Jun 2023 20:35:03 +0200 Subject: [PATCH 07/18] Comment out unused code --- src/comparator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/comparator.rs b/src/comparator.rs index 743a9d1b..d8afcd90 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -167,11 +167,11 @@ pub enum Hysteresis { H70mV = 0b111, } -#[derive(Copy, Clone, Eq, PartialEq)] +/*#[derive(Copy, Clone, Eq, PartialEq)] pub enum PowerMode { HighSpeed = 0b00, MediumSpeed = 0b01, -} +}*/ /// Comparator positive input pub trait PositiveInput { From d1900a7d43d37b94a0cf46761fe2f7aabf78d917 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 2 Jun 2023 20:40:13 +0200 Subject: [PATCH 08/18] Comment out more unused code --- src/dac.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dac.rs b/src/dac.rs index 9f2e6832..e86be68c 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -49,8 +49,8 @@ impl GeneratorConfig { /// Enabled DAC (type state) pub struct Enabled; -/// Enabled DAC without output buffer (type state) -pub struct EnabledUnbuffered; +// / Enabled DAC without output buffer (type state) +//pub struct EnabledUnbuffered; /// Enabled DAC wave generator (type state) pub struct WaveGenerator; /// Disabled DAC (type state) From eb0cac86aee4fb8109dd17876a4dd72ee8c736d4 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 2 Jun 2023 20:41:43 +0200 Subject: [PATCH 09/18] Comment out more unused code - fix --- src/dac.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dac.rs b/src/dac.rs index e86be68c..0fe39ebd 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -58,7 +58,7 @@ pub struct Disabled; pub trait ED {} impl ED for Enabled {} -impl ED for EnabledUnbuffered {} +//impl ED for EnabledUnbuffered {} impl ED for WaveGenerator {} impl ED for Disabled {} From 448954a1d4e8853f2ab3c454f47b2b59e6536e17 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 8 Jun 2023 16:48:38 +0200 Subject: [PATCH 10/18] Remove comp impl of devices other than g474 --- examples/comp.rs | 22 ++++++++++++++++------ examples/comp_w_dac.rs | 24 ++++++++++++++++-------- src/comparator.rs | 33 +++++++++++++++++++++++---------- 3 files changed, 55 insertions(+), 24 deletions(-) diff --git a/examples/comp.rs b/examples/comp.rs index 79f914d3..b34cabed 100644 --- a/examples/comp.rs +++ b/examples/comp.rs @@ -8,19 +8,29 @@ #![no_main] #![no_std] -use hal::comparator::{ComparatorExt, ComparatorSplit, Config, Hysteresis, RefintInput}; -use hal::gpio::GpioExt; -use hal::prelude::OutputPin; -use hal::rcc::RccExt; -use stm32g4xx_hal as hal; + mod utils; extern crate cortex_m_rt as rt; -use hal::stm32; + use rt::entry; +#[cfg(not(feature = "stm32g474"))] #[entry] fn main() -> ! { + loop{} // TODO: add support for more devices +} + +#[cfg(feature = "stm32g474")] +#[entry] +fn main() -> ! { + use hal::stm32; + use hal::comparator::{ComparatorExt, ComparatorSplit, Config, Hysteresis, RefintInput}; + use hal::gpio::GpioExt; + use hal::prelude::OutputPin; + use hal::rcc::RccExt; + use stm32g4xx_hal as hal; + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); let mut rcc = dp.RCC.constrain(); diff --git a/examples/comp_w_dac.rs b/examples/comp_w_dac.rs index aa57e0a0..7bbc6623 100644 --- a/examples/comp_w_dac.rs +++ b/examples/comp_w_dac.rs @@ -3,21 +3,29 @@ #![no_main] #![no_std] -use embedded_hal::Direction; -use hal::comparator::{self, ComparatorExt, ComparatorSplit}; -use hal::dac::{Dac1IntSig1, DacExt, DacOut}; -use hal::delay::SYSTDelayExt; -use hal::gpio::GpioExt; -use hal::rcc::RccExt; -use stm32g4xx_hal as hal; mod utils; extern crate cortex_m_rt as rt; -use hal::stm32; use rt::entry; +#[cfg(not(feature = "stm32g474"))] #[entry] fn main() -> ! { + loop{} // TODO: add support for more devices +} + +#[cfg(feature = "stm32g474")] +#[entry] +fn main() -> ! { + use hal::stm32; + use embedded_hal::Direction; + use hal::comparator::{self, ComparatorExt, ComparatorSplit}; + use hal::dac::{Dac1IntSig1, DacExt, DacOut}; + use hal::delay::SYSTDelayExt; + use hal::gpio::GpioExt; + use hal::rcc::RccExt; + use stm32g4xx_hal as hal; + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals"); diff --git a/src/comparator.rs b/src/comparator.rs index d8afcd90..89d3df1c 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -9,10 +9,18 @@ use core::marker::PhantomData; use crate::dac; use crate::exti::{Event as ExtiEvent, ExtiExt}; -use crate::gpio::gpioa::{PA0, PA1, PA11, PA12, PA2, PA3, PA4, PA5, PA6, PA7}; -use crate::gpio::gpiob::{PB0, PB1, PB14, PB2, PB6, PB7, PB8, PB9}; +use crate::gpio::gpioa::{PA0, PA1, PA2, PA3, PA4, PA5, PA7}; +use crate::gpio::gpiob::{PB0, PB1, PB2}; use crate::gpio::*; +#[cfg(any(feature = "stm32g474"))] +use crate::gpio::{ + gpiob::{PB6, PB7, PB8, PB9}, + gpioc::PC2, + gpiof::PF4, + gpioa::{PA11, PA12, PA6}, +}; + #[cfg(any( feature = "stm32g473", feature = "stm32g483", @@ -27,7 +35,7 @@ use crate::gpio::gpioa::{PA10, PA8, PA9}; feature = "stm32g474", feature = "stm32g484" ))] -use crate::gpio::gpiob::{PB10, PB11, PB12, PB13, PB15}; +use crate::gpio::gpiob::{PB10, PB11, PB12, PB13, PB14, PB15}; #[cfg(any( feature = "stm32g473", @@ -43,12 +51,11 @@ use crate::gpio::gpioc::{PC6, PC7, PC8}; feature = "stm32g474", feature = "stm32g484" ))] -use crate::gpio::gpiod::{PD10, PD11, PD12, PD13, PD15}; +use crate::gpio::gpiod::{PD10, PD11, PD12, PD13, PD14, PD15}; -use crate::gpio::gpioc::{PC0, PC1, PC2}; -use crate::gpio::gpiod::PD14; +use crate::gpio::gpioc::{PC0, PC1}; use crate::gpio::gpioe::{PE7, PE8}; -use crate::gpio::gpiof::{PF1, PF4}; +use crate::gpio::gpiof::PF1; use crate::rcc::{Clocks, Rcc}; use crate::stm32::{COMP, EXTI}; @@ -773,6 +780,7 @@ pub trait OutputPin { fn setup(self); } +#[allow(unused_macros)] // TODO: add support for more devices macro_rules! output_pin { ($COMP:ident, $pin:ident, $AF:ident, $mode_t:ident, $into:ident) => { impl OutputPin<$COMP> for $pin> { @@ -787,6 +795,9 @@ macro_rules! output_pin { )+}; } +// TODO: look up alternate functions for more devices than g474 +// https://www.mouser.se/datasheet/2/389/stm32g474cb-1600828.pdf#page=73 +#[cfg(feature = "stm32g474")] output_pin! { COMP1: PA0, AF8, COMP1: PA6, AF8, @@ -808,11 +819,13 @@ output_pin! { COMP4: PB14, AF8, } +// TODO: look up alternate functions for more devices than g474 +// https://www.mouser.se/datasheet/2/389/stm32g474cb-1600828.pdf#page=73 #[cfg(any( - feature = "stm32g473", - feature = "stm32g483", + //feature = "stm32g473", + //feature = "stm32g483", feature = "stm32g474", - feature = "stm32g484" + //feature = "stm32g484" ))] output_pin! { COMP5: PA9, AF8, From 4e52055ec0be6e18fcc369d84f73b8247d3ee9d5 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 8 Jun 2023 17:06:00 +0200 Subject: [PATCH 11/18] fmt --- examples/comp.rs | 6 ++---- examples/comp_w_dac.rs | 4 ++-- src/comparator.rs | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/comp.rs b/examples/comp.rs index b34cabed..38553d10 100644 --- a/examples/comp.rs +++ b/examples/comp.rs @@ -8,27 +8,25 @@ #![no_main] #![no_std] - mod utils; extern crate cortex_m_rt as rt; - use rt::entry; #[cfg(not(feature = "stm32g474"))] #[entry] fn main() -> ! { - loop{} // TODO: add support for more devices + loop {} // TODO: add support for more devices } #[cfg(feature = "stm32g474")] #[entry] fn main() -> ! { - use hal::stm32; use hal::comparator::{ComparatorExt, ComparatorSplit, Config, Hysteresis, RefintInput}; use hal::gpio::GpioExt; use hal::prelude::OutputPin; use hal::rcc::RccExt; + use hal::stm32; use stm32g4xx_hal as hal; let dp = stm32::Peripherals::take().expect("cannot take peripherals"); diff --git a/examples/comp_w_dac.rs b/examples/comp_w_dac.rs index 7bbc6623..af97f473 100644 --- a/examples/comp_w_dac.rs +++ b/examples/comp_w_dac.rs @@ -11,19 +11,19 @@ use rt::entry; #[cfg(not(feature = "stm32g474"))] #[entry] fn main() -> ! { - loop{} // TODO: add support for more devices + loop {} // TODO: add support for more devices } #[cfg(feature = "stm32g474")] #[entry] fn main() -> ! { - use hal::stm32; use embedded_hal::Direction; use hal::comparator::{self, ComparatorExt, ComparatorSplit}; use hal::dac::{Dac1IntSig1, DacExt, DacOut}; use hal::delay::SYSTDelayExt; use hal::gpio::GpioExt; use hal::rcc::RccExt; + use hal::stm32; use stm32g4xx_hal as hal; let dp = stm32::Peripherals::take().expect("cannot take peripherals"); diff --git a/src/comparator.rs b/src/comparator.rs index 89d3df1c..029518c7 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -15,10 +15,10 @@ use crate::gpio::*; #[cfg(any(feature = "stm32g474"))] use crate::gpio::{ + gpioa::{PA11, PA12, PA6}, gpiob::{PB6, PB7, PB8, PB9}, gpioc::PC2, gpiof::PF4, - gpioa::{PA11, PA12, PA6}, }; #[cfg(any( From 1fbe8db5abea751cc286b52058d23a5321bcf7d6 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 13 Jun 2023 19:03:56 +0200 Subject: [PATCH 12/18] Add more comparator impls --- src/comparator.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/comparator.rs b/src/comparator.rs index 029518c7..a2544de3 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -563,6 +563,32 @@ macro_rules! impl_comparator { impl_comparator!(COMP1, comp1, ExtiEvent::COMP1); impl_comparator!(COMP2, comp2, ExtiEvent::COMP2); +impl_comparator!(COMP3, comp1, ExtiEvent::COMP3); +impl_comparator!(COMP4, comp2, ExtiEvent::COMP4); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +impl_comparator!(COMP5, comp1, ExtiEvent::COMP5); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +impl_comparator!(COMP6, comp2, ExtiEvent::COMP6); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g483", + feature = "stm32g474", + feature = "stm32g484" +))] +impl_comparator!(COMP7, comp2, ExtiEvent::COMP7); /* /// Uses two comparators to implement a window comparator. From 949a90bae5647aa2ff86ea6476762410d88040dd Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 13 Jun 2023 19:11:55 +0200 Subject: [PATCH 13/18] Comparator does not need to consume its positive input pin --- examples/comp.rs | 4 ++-- examples/comp_w_dac.rs | 2 +- src/comparator.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/comp.rs b/examples/comp.rs index 38553d10..abfa16ba 100644 --- a/examples/comp.rs +++ b/examples/comp.rs @@ -38,7 +38,7 @@ fn main() -> ! { let pa1 = gpioa.pa1.into_analog(); let pa0 = gpioa.pa0.into_analog(); - let comp1 = comp1.comparator(pa1, pa0, Config::default(), &rcc.clocks); + let comp1 = comp1.comparator(&pa1, pa0, Config::default(), &rcc.clocks); let comp1 = comp1.enable(); // led1 pa1 will be updated manually when to match comp1 value @@ -46,7 +46,7 @@ fn main() -> ! { let pa7 = gpioa.pa7.into_analog(); let comp2 = comp2.comparator( - pa7, + &pa7, RefintInput::VRefintM12, Config::default() .hysteresis(Hysteresis::None) diff --git a/examples/comp_w_dac.rs b/examples/comp_w_dac.rs index af97f473..5d33d619 100644 --- a/examples/comp_w_dac.rs +++ b/examples/comp_w_dac.rs @@ -44,7 +44,7 @@ fn main() -> ! { // Set up comparator with pa1 as positive, and the DAC as negative input let comp = comp1.comparator( - pa1, + &pa1, &dac, comparator::Config::default().hysteresis(comparator::Hysteresis::None), &rcc.clocks, diff --git a/src/comparator.rs b/src/comparator.rs index a2544de3..16bce1ed 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -228,13 +228,13 @@ window_input_pin!(COMP2, Comp1InP); macro_rules! positive_input_pin { ($COMP:ident, $pin_0:ident, $pin_1:ident) => { - impl PositiveInput<$COMP> for $pin_0 { + impl PositiveInput<$COMP> for &$pin_0 { fn setup(&self, comp: &$COMP) { comp.csr().modify(|_, w| w.inpsel().bit(false)) } } - impl PositiveInput<$COMP> for $pin_1 { + impl PositiveInput<$COMP> for &$pin_1 { fn setup(&self, comp: &$COMP) { comp.csr().modify(|_, w| w.inpsel().bit(true)) } From 67965e5559192226423e7ccbcee1c9b3ceea8df1 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 8 Nov 2023 22:44:02 +0100 Subject: [PATCH 14/18] COMP make compile for all devices --- src/comparator.rs | 53 ++++++++++++----------------------------------- 1 file changed, 13 insertions(+), 40 deletions(-) diff --git a/src/comparator.rs b/src/comparator.rs index 16bce1ed..de38db69 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -9,16 +9,12 @@ use core::marker::PhantomData; use crate::dac; use crate::exti::{Event as ExtiEvent, ExtiExt}; -use crate::gpio::gpioa::{PA0, PA1, PA2, PA3, PA4, PA5, PA7}; -use crate::gpio::gpiob::{PB0, PB1, PB2}; -use crate::gpio::*; - -#[cfg(any(feature = "stm32g474"))] use crate::gpio::{ - gpioa::{PA11, PA12, PA6}, - gpiob::{PB6, PB7, PB8, PB9}, + gpioa::{PA0, PA1, PA11, PA12, PA2, PA3, PA4, PA5, PA6, PA7}, + gpiob::{PB0, PB1, PB14, PB15, PB2, PB6, PB7, PB8, PB9}, gpioc::PC2, gpiof::PF4, + Analog, OpenDrain, Output, PushPull, SignalEdge, AF2, AF3, AF8, }; #[cfg(any( @@ -27,31 +23,13 @@ use crate::gpio::{ feature = "stm32g474", feature = "stm32g484" ))] -use crate::gpio::gpioa::{PA10, PA8, PA9}; - -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] -use crate::gpio::gpiob::{PB10, PB11, PB12, PB13, PB14, PB15}; - -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] -use crate::gpio::gpioc::{PC6, PC7, PC8}; - -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] -use crate::gpio::gpiod::{PD10, PD11, PD12, PD13, PD14, PD15}; +use crate::gpio::{ + gpioa::{PA10, PA8, PA9}, + gpiob::{PB10, PB11, PB12, PB13}, + gpioc::{PC6, PC7, PC8}, + gpiod::{PD10, PD11, PD12, PD13, PD14, PD15}, + AF7, +}; use crate::gpio::gpioc::{PC0, PC1}; use crate::gpio::gpioe::{PE7, PE8}; @@ -821,9 +799,6 @@ macro_rules! output_pin { )+}; } -// TODO: look up alternate functions for more devices than g474 -// https://www.mouser.se/datasheet/2/389/stm32g474cb-1600828.pdf#page=73 -#[cfg(feature = "stm32g474")] output_pin! { COMP1: PA0, AF8, COMP1: PA6, AF8, @@ -845,13 +820,11 @@ output_pin! { COMP4: PB14, AF8, } -// TODO: look up alternate functions for more devices than g474 -// https://www.mouser.se/datasheet/2/389/stm32g474cb-1600828.pdf#page=73 #[cfg(any( - //feature = "stm32g473", - //feature = "stm32g483", + feature = "stm32g473", + feature = "stm32g483", feature = "stm32g474", - //feature = "stm32g484" + feature = "stm32g484", ))] output_pin! { COMP5: PA9, AF8, From 931e9ba9aad96c3c7a435671d6f1f2e713329e1b Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 29 Nov 2023 20:28:16 +0100 Subject: [PATCH 15/18] Remove dead code --- src/comparator.rs | 193 ---------------------------------------------- src/dac.rs | 11 --- 2 files changed, 204 deletions(-) diff --git a/src/comparator.rs b/src/comparator.rs index de38db69..97e2143c 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -124,20 +124,6 @@ impl Config { self.inverted = inverted; self } - - /* - pub fn power_mode(mut self, power_mode: PowerMode) -> Self { - self.power_mode = power_mode; - self - }*/ - - /* - /// Sets the output to be Comparator 1 XOR Comparator 2. - /// Used to implement window comparator mode. - pub fn output_xor(mut self) -> Self { - self.output_xor = true; - self - }*/ } #[derive(Copy, Clone, Eq, PartialEq)] @@ -152,12 +138,6 @@ pub enum Hysteresis { H70mV = 0b111, } -/*#[derive(Copy, Clone, Eq, PartialEq)] -pub enum PowerMode { - HighSpeed = 0b00, - MediumSpeed = 0b01, -}*/ - /// Comparator positive input pub trait PositiveInput { fn setup(&self, comp: &C); @@ -178,32 +158,6 @@ pub trait NegativeInput { fn setup(&self, comp: &C); } -/* -/// Comparator 1 positive input used as positive input for Comparator 2. -/// Used to implement window comparator mode. -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct Comp1InP; - -/// Comparator 2 positive input used as positive input for Comparator 1. -/// Used to implement window comparator mode. -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct Comp2InP; - - -macro_rules! window_input_pin { - ($COMP:ident, $pin:ty) => { - impl PositiveInput<$COMP> for $pin { - fn setup(&self, comp: &$COMP) { - comp.csr().modify(|_, w| w.winmode().set_bit()) - } - } - }; -} - -window_input_pin!(COMP1, Comp2InP); -window_input_pin!(COMP2, Comp1InP); -*/ - macro_rules! positive_input_pin { ($COMP:ident, $pin_0:ident, $pin_1:ident) => { impl PositiveInput<$COMP> for &$pin_0 { @@ -568,153 +522,6 @@ impl_comparator!(COMP6, comp2, ExtiEvent::COMP6); ))] impl_comparator!(COMP7, comp2, ExtiEvent::COMP7); -/* -/// Uses two comparators to implement a window comparator. -/// See Figure 69 in RM0444 Rev 5. -pub struct WindowComparator { - pub upper: Comparator, - pub lower: Comparator, -} - -pub trait WindowComparatorExt { - /// Uses two comparators to implement a window comparator - /// - /// See Figure 69 in RM0444 Rev 5. Ignores and overrides the `output_xor` setting in `config`. - fn window_comparator, L: NegativeInput, U: NegativeInput>( - self, - input: I, - lower_threshold: L, - upper_threshold: U, - config: Config, - clocks: &Clocks, - ) -> WindowComparator; -} - -macro_rules! impl_window_comparator { - ($UPPER:ident, $LOWER:ident, $LOTHR:expr) => { - impl WindowComparatorExt<$UPPER, $LOWER> for ($UPPER, $LOWER) { - fn window_comparator< - I: PositiveInput<$UPPER>, - L: NegativeInput<$LOWER>, - U: NegativeInput<$UPPER>, - >( - self, - input: I, - lower_threshold: L, - upper_threshold: U, - config: Config, - clocks: &Clocks, - ) -> WindowComparator<$UPPER, $LOWER, Disabled> { - let (upper, lower) = self; - - let mut configu = config.clone(); - configu.output_xor = true; - let upper = upper.comparator(input, upper_threshold, configu, clocks); - - let mut configl = config; - configl.output_xor = false; - let lower = lower.comparator($LOTHR, lower_threshold, configl, clocks); - - WindowComparator { upper, lower } - } - } - - impl WindowComparator<$UPPER, $LOWER, Disabled> { - /// Enables the comparator - pub fn enable(self) -> WindowComparator<$UPPER, $LOWER, Enabled> { - WindowComparator { - upper: self.upper.enable(), - lower: self.lower.enable(), - } - } - - /// Enables raising the `ADC_COMP` interrupt at the specified signal edge - pub fn listen(&self, edge: SignalEdge, exti: &mut EXTI) { - self.upper.listen(edge, exti) - } - } - - impl WindowComparator<$UPPER, $LOWER, Enabled> { - /// Disables the comparator - pub fn disable(self) -> WindowComparator<$UPPER, $LOWER, Disabled> { - WindowComparator { - upper: self.upper.disable(), - lower: self.lower.disable(), - } - } - - /// Returns the value of the output of the comparator - pub fn output(&self) -> bool { - self.upper.output() - } - - /// Returns `true` if the input signal is above the lower threshold - pub fn above_lower(&self) -> bool { - self.lower.output() - } - } - - impl WindowComparator<$UPPER, $LOWER, ED> { - /// Configures a GPIO pin to output the signal of the comparator - /// - /// Multiple GPIO pins may be configured as the output simultaneously. - pub fn output_pin>(&self, pin: P) { - self.upper.output_pin(pin) - } - - /// Disables raising interrupts for the output signal - pub fn unlisten(&self, exti: &mut EXTI) { - self.upper.unlisten(exti) - } - - /// Returns `true` if the output signal interrupt is pending for the `edge` - pub fn is_pending(&self, edge: SignalEdge, exti: &EXTI) -> bool { - self.upper.is_pending(edge, exti) - } - - /// Unpends the output signal interrupt - pub fn unpend(&self, exti: &EXTI) { - self.upper.unpend(exti) - } - } - }; -} - -impl_window_comparator!(COMP1, COMP2, Comp1InP); -impl_window_comparator!(COMP2, COMP1, Comp2InP); - -pub fn window_comparator12< - I: PositiveInput, - L: NegativeInput, - U: NegativeInput, ->( - comp: COMP, - input: I, - lower_threshold: L, - upper_threshold: U, - config: Config, - rcc: &mut Rcc, -) -> WindowComparator { - let (comp1, comp2) = comp.split(rcc); - (comp1, comp2).window_comparator(input, lower_threshold, upper_threshold, config, &rcc.clocks) -} - -pub fn window_comparator21< - I: PositiveInput, - L: NegativeInput, - U: NegativeInput, ->( - comp: COMP, - input: I, - lower_threshold: L, - upper_threshold: U, - config: Config, - rcc: &mut Rcc, -) -> WindowComparator { - let (comp1, comp2) = comp.split(rcc); - (comp2, comp1).window_comparator(input, lower_threshold, upper_threshold, config, &rcc.clocks) -}*/ - #[cfg(not(any( feature = "stm32g473", feature = "stm32g483", diff --git a/src/dac.rs b/src/dac.rs index 0fe39ebd..e996290e 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -191,17 +191,6 @@ macro_rules! dac_helper { } } - /*pub fn enable_unbuffered(self) -> $CX { - let dac = unsafe { &(*<$DAC>::ptr()) }; - - dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(2) }); - dac.dac_cr.modify(|_, w| w.$en().set_bit()); - - $CX { - _enabled: PhantomData, - } - }*/ - pub fn enable_generator(self, config: GeneratorConfig) -> $CX { let dac = unsafe { &(*<$DAC>::ptr()) }; From 6887fcbbef1349a13b3ef839e0d5da57d778daf5 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 29 Nov 2023 20:40:12 +0100 Subject: [PATCH 16/18] Update for fugit --- src/comparator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comparator.rs b/src/comparator.rs index 97e2143c..d0597ea7 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -393,7 +393,7 @@ macro_rules! impl_comparator { positive_input.setup(&self); negative_input.setup(&self); // Delay for scaler voltage bridge initialization for certain negative inputs - let voltage_scaler_delay = clocks.sys_clk.0 / (1_000_000 / 200); // 200us + let voltage_scaler_delay = clocks.sys_clk.raw() / (1_000_000 / 200); // 200us cortex_m::asm::delay(voltage_scaler_delay); self.csr().modify(|_, w| unsafe { w.hyst() From 78d40756e79996ea536fb91ebae699cf548cb386 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 29 Nov 2023 20:43:54 +0100 Subject: [PATCH 17/18] Add missing impls --- src/dac.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dac.rs b/src/dac.rs index e996290e..109374c0 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -141,10 +141,18 @@ impl_pin_for_dac!(DAC2: (PA6, Dac2IntSig1), Dac2Ch1); impl_pin_for_dac!(DAC3: Dac3IntSig2, Dac3Ch2); +impl_pin_for_dac!( + DAC3: (Dac3IntSig1, Dac3IntSig2), + (Dac3Ch1, Dac3Ch2) +); // DAC4 int impl_pin_for_dac!(DAC4: Dac4IntSig1, Dac4Ch1); impl_pin_for_dac!(DAC4: Dac4IntSig2, Dac4Ch2); +impl_pin_for_dac!( + DAC4: (Dac4IntSig1, Dac4IntSig2), + (Dac4Ch1, Dac4Ch2) +); pub fn dac(_dac: DAC, _pins: PINS, _rcc: &mut Rcc) -> PINS::Output where @@ -180,6 +188,8 @@ macro_rules! dac_helper { ),)+) => { $( impl $CX { + /// TODO: The DAC does not seem to work unless `calibrate_buffer` has been callen + /// even when only using dac output internally pub fn enable(self) -> $CX { let dac = unsafe { &(*<$DAC>::ptr()) }; From d96a4664bfd201f07bccaeb02b0a461b1f66cef4 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 30 Nov 2023 00:52:04 +0100 Subject: [PATCH 18/18] Fix warnings (#76) * Fix all warnings * Fix all warnings in examples * Format * Fix more warnings * Resolve comments --- Cargo.toml | 6 +++++- examples/can-echo.rs | 2 +- examples/flash_with_rtic.rs | 2 -- examples/hello.rs | 2 +- examples/i2c-bme680.rs | 6 +++--- examples/opamp.rs | 8 +++++--- examples/pwm.rs | 6 +++++- examples/spi-sd.rs | 20 +++++++++----------- examples/utils/logger.rs | 8 +++++++- src/adc.rs | 8 +------- src/can.rs | 1 + src/dma/config.rs | 8 ++------ src/dma/mux.rs | 1 + src/dma/transfer.rs | 4 ++-- src/flash.rs | 18 ++++++++++-------- src/pwm.rs | 2 -- src/rcc/config.rs | 20 ++++++++++---------- src/timer.rs | 1 + 18 files changed, 64 insertions(+), 59 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 56d19f3b..4e881f93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,7 @@ optional = true [dev-dependencies] cortex-m-rt = "0.7.2" defmt-rtt = "0.4.0" -cortex-m-rtic = "0.5.8" +cortex-m-rtic = "1.1.4" cortex-m-semihosting = "0.3.5" panic-probe = { version = "0.3.0", features = ["print-defmt"] } panic-semihosting = "0.5.3" @@ -101,3 +101,7 @@ debug = false codegen-units = 1 incremental = false lto = true + +[[example]] +name = "flash_with_rtic" +required-features = ["stm32g474"] \ No newline at end of file diff --git a/examples/can-echo.rs b/examples/can-echo.rs index 89911b8e..f10512bf 100644 --- a/examples/can-echo.rs +++ b/examples/can-echo.rs @@ -120,7 +120,7 @@ fn main() -> ! { loop { if let Ok(rxheader) = block!(can.receive0(&mut buffer)) { - block!(can.transmit(rxheader.unwrap().to_tx_header(None), &mut buffer)).unwrap(); + block!(can.transmit(rxheader.unwrap().to_tx_header(None), &buffer)).unwrap(); } } } diff --git a/examples/flash_with_rtic.rs b/examples/flash_with_rtic.rs index bf236eb3..3f42240c 100644 --- a/examples/flash_with_rtic.rs +++ b/examples/flash_with_rtic.rs @@ -16,8 +16,6 @@ mod app { const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info; - use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics - // Resources shared between tasks #[shared] struct Shared {} diff --git a/examples/hello.rs b/examples/hello.rs index 990f05f2..63210f39 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -16,7 +16,7 @@ use utils::logger::println; #[entry] fn main() -> ! { - let _ = println!("Hello, STM32G4!"); + println!("Hello, STM32G4!"); #[allow(clippy::empty_loop)] loop {} diff --git a/examples/i2c-bme680.rs b/examples/i2c-bme680.rs index 83de035e..2fa8a9c0 100644 --- a/examples/i2c-bme680.rs +++ b/examples/i2c-bme680.rs @@ -52,15 +52,15 @@ fn main() -> ! { .with_run_gas(true) .build(); - let profile_dur = dev.get_profile_dur(&settings.0).unwrap(); + let _profile_dur = dev.get_profile_dur(&settings.0).unwrap(); dev.set_sensor_settings(&mut delayer, settings).unwrap(); dev.set_sensor_mode(&mut delayer, PowerMode::ForcedMode) .unwrap(); - let sensor_settings = dev.get_sensor_settings(settings.1); + let _sensor_settings = dev.get_sensor_settings(settings.1); loop { delay.delay_ms(500u32); - let power_mode = dev.get_sensor_mode(); + let _power_mode = dev.get_sensor_mode(); dev.set_sensor_mode(&mut delayer, PowerMode::ForcedMode) .unwrap(); let (data, _state) = dev.get_sensor_data(&mut delayer).unwrap(); diff --git a/examples/opamp.rs b/examples/opamp.rs index 4952c5a7..473ba538 100644 --- a/examples/opamp.rs +++ b/examples/opamp.rs @@ -58,7 +58,7 @@ fn main() -> ! { ); // Configure op with pa7 as non-inverting input and set gain to x4 - let mut opamp2 = opamp2.pga( + let opamp2 = opamp2.pga( pa7, PgaModeInternal::gain(NonInvertingGain::Gain4), Option::>::None, // Do not route output to any external pin, use internal AD instead @@ -72,7 +72,7 @@ fn main() -> ! { loop { // Here we can sample the output of opamp2 as if it was a regular AD pin let sample = adc.convert( - &mut opamp2, + &opamp2, stm32g4xx_hal::adc::config::SampleTime::Cycles_640_5, ); @@ -87,6 +87,8 @@ fn main() -> ! { let (_opamp1, _pa1, _mode, _some_pa2) = _opamp1.disable(); let (_opamp2, _pa7, _mode, _none) = opamp2.disable(); - loop {} + loop { + delay.delay_ms(100); + } } } diff --git a/examples/pwm.rs b/examples/pwm.rs index 8ed1d511..9d2ca8e8 100644 --- a/examples/pwm.rs +++ b/examples/pwm.rs @@ -10,11 +10,15 @@ use hal::prelude::*; use hal::stm32; use hal::time::RateExtU32; use stm32g4xx_hal as hal; -mod utils; extern crate cortex_m_rt as rt; +#[macro_use] +mod utils; + #[entry] fn main() -> ! { + utils::logger::init(); + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); let mut rcc = dp.RCC.constrain(); let gpioa = dp.GPIOA.split(&mut rcc); diff --git a/examples/spi-sd.rs b/examples/spi-sd.rs index 57a29799..37af1233 100644 --- a/examples/spi-sd.rs +++ b/examples/spi-sd.rs @@ -5,34 +5,30 @@ extern crate embedded_sdmmc; +use fugit::RateExtU32; use hal::gpio::gpiob::PB14; use hal::gpio::gpiob::PB15; -use hal::gpio::gpiof::PF8; use hal::gpio::gpiof::PF9; use hal::gpio::Alternate; use hal::gpio::AF5; use hal::prelude::*; use hal::rcc::Config; use hal::spi; -use hal::stm32; + use hal::stm32::Peripherals; -use hal::time::RateExtU32; -use hal::timer::Timer; use stm32g4xx_hal as hal; -use embedded_sdmmc::{ - Block, BlockCount, BlockDevice, BlockIdx, Controller, Error, Mode, TimeSource, Timestamp, - VolumeIdx, -}; +use embedded_sdmmc::{TimeSource, Timestamp}; use cortex_m_rt::entry; -use log::info; #[macro_use] mod utils; #[entry] fn main() -> ! { + utils::logger::init(); + let dp = Peripherals::take().unwrap(); let rcc = dp.RCC.constrain(); let mut rcc = rcc.freeze(Config::hsi()); @@ -49,7 +45,7 @@ fn main() -> ! { let miso: PB14> = gpiob.pb14.into_alternate(); let mosi: PB15> = gpiob.pb15.into_alternate(); - let mut spi = dp + let spi = dp .SPI2 .spi((sck, miso, mosi), spi::MODE_0, 400.kHz(), &mut rcc); @@ -70,6 +66,8 @@ fn main() -> ! { let mut cont = embedded_sdmmc::Controller::new(embedded_sdmmc::SdMmcSpi::new(spi, cs), Clock); - cont.device().init(); + cont.device().init().unwrap(); + + #[allow(clippy::empty_loop)] loop {} } diff --git a/examples/utils/logger.rs b/examples/utils/logger.rs index e11b73b2..4de3d943 100644 --- a/examples/utils/logger.rs +++ b/examples/utils/logger.rs @@ -5,7 +5,13 @@ cfg_if::cfg_if! { pub use defmt::println as println; } else { pub use log::{info, trace, warn, debug, error}; - pub use cortex_m_semihosting::hprintln as println; + + #[allow(unused_macros)] + macro_rules! println { + ($($tt:tt)*) => { + $crate::cortex_m_semihosting::hprintln!($($tt,)*).unwrap(); + }; + } } } diff --git a/src/adc.rs b/src/adc.rs index b0c5225e..52908d0e 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -571,7 +571,7 @@ pub mod config { } /// Sets the input type per channel - #[derive(Debug, Clone, Copy)] + #[derive(Debug, Clone, Copy, Default)] pub struct DifferentialSelection(pub(crate) u32); impl DifferentialSelection { /// Set pin to Single-Ended or Differential @@ -614,12 +614,6 @@ pub mod config { } } - impl Default for DifferentialSelection { - fn default() -> Self { - DifferentialSelection(0) - } - } - /// Configuration for the adc. /// There are some additional parameters on the adc peripheral that can be /// added here when needed but this covers several basic usecases. diff --git a/src/can.rs b/src/can.rs index c4db270a..b70eb04d 100644 --- a/src/can.rs +++ b/src/can.rs @@ -12,6 +12,7 @@ mod sealed { } /// Select an FDCAN Clock Source +#[allow(clippy::upper_case_acronyms)] #[allow(dead_code)] enum FdCanClockSource { /// Select HSE as the FDCAN clock source diff --git a/src/dma/config.rs b/src/dma/config.rs index 2bffb564..21b3bd02 100644 --- a/src/dma/config.rs +++ b/src/dma/config.rs @@ -4,22 +4,18 @@ use super::Bits; /// the same software priority level, the stream with the lower number takes /// priority over the stream with the higher number. For example, Stream 2 /// takes priority over Stream 4. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Default)] pub enum Priority { /// Low priority. Low, /// Medium priority. + #[default] Medium, /// High priority. High, /// Very high priority. VeryHigh, } -impl Default for Priority { - fn default() -> Self { - Priority::Medium - } -} impl Bits for Priority { fn bits(self) -> u8 { diff --git a/src/dma/mux.rs b/src/dma/mux.rs index 3aeaa61c..968f345c 100644 --- a/src/dma/mux.rs +++ b/src/dma/mux.rs @@ -1,3 +1,4 @@ +#[allow(clippy::upper_case_acronyms)] pub enum DmaMuxResources { DMAMUXReqG0 = 1, DMAMUXReqG1 = 2, diff --git a/src/dma/transfer.rs b/src/dma/transfer.rs index febaf1f4..168d70cc 100644 --- a/src/dma/transfer.rs +++ b/src/dma/transfer.rs @@ -313,7 +313,7 @@ where { /// Return the number of elements available to read pub fn elements_available(&mut self) -> usize { - let blen = unsafe { self.transfer.buf.static_write_buffer().1 } as usize; + let blen = unsafe { self.transfer.buf.static_write_buffer().1 }; let ndtr = STREAM::get_number_of_transfers() as usize; let pos_at = self.r_pos; @@ -341,7 +341,7 @@ where &mut self, dat: &mut [>::MemSize], ) -> usize { - let blen = unsafe { self.transfer.buf.static_write_buffer().1 } as usize; + let blen = unsafe { self.transfer.buf.static_write_buffer().1 }; let pos = self.r_pos; let read = dat.len(); diff --git a/src/flash.rs b/src/flash.rs index 99657872..26b60484 100644 --- a/src/flash.rs +++ b/src/flash.rs @@ -59,6 +59,7 @@ pub struct FlashWriter<'a, const SECTOR_SZ_KB: u32> { verify: bool, } impl<'a, const SECTOR_SZ_KB: u32> FlashWriter<'a, SECTOR_SZ_KB> { + #[allow(unused)] fn unlock_options(&mut self) -> Result<()> { // Check if flash is busy while self.flash.sr.sr().read().bsy().bit_is_set() {} @@ -142,12 +143,12 @@ impl<'a, const SECTOR_SZ_KB: u32> FlashWriter<'a, SECTOR_SZ_KB> { if offset .checked_add(length as u32) .ok_or(Error::LengthTooLong)? - > self.flash_sz.kbytes() as u32 + > self.flash_sz.kbytes() { return Err(Error::LengthTooLong); } - if force_padding == false && length % 8 != 0 { + if !force_padding && length % 8 != 0 { return Err(Error::ArrayMustBeDivisibleBy8); } @@ -164,7 +165,7 @@ impl<'a, const SECTOR_SZ_KB: u32> FlashWriter<'a, SECTOR_SZ_KB> { // Set Page Erase self.flash.cr.cr().modify(|_, w| w.per().set_bit()); - let page = start_offset / (SECTOR_SZ_KB as u32); + let page = start_offset / SECTOR_SZ_KB; // Write address bits // NOTE(unsafe) This sets the page address in the Address Register. @@ -206,7 +207,7 @@ impl<'a, const SECTOR_SZ_KB: u32> FlashWriter<'a, SECTOR_SZ_KB> { let size = SECTOR_SZ_KB; let start = start_offset & !(size - 1); for idx in (start..start + size).step_by(2) { - let write_address = (FLASH_START + idx as u32) as *const u16; + let write_address = (FLASH_START + idx) as *const u16; let verify: u16 = unsafe { core::ptr::read_volatile(write_address) }; if verify != 0xFFFF { return Err(Error::VerifyError); @@ -237,7 +238,7 @@ impl<'a, const SECTOR_SZ_KB: u32> FlashWriter<'a, SECTOR_SZ_KB> { pub fn read(&self, offset: u32, length: usize) -> Result<&[u8]> { self.valid_address(offset)?; - if offset + length as u32 > self.flash_sz.kbytes() as u32 { + if offset + length as u32 > self.flash_sz.kbytes() { return Err(Error::LengthTooLong); } @@ -281,9 +282,7 @@ impl<'a, const SECTOR_SZ_KB: u32> FlashWriter<'a, SECTOR_SZ_KB> { // Check if there is enough data to make 2 words, if there isn't, pad the data with 0xFF if idx + 8 > data.len() { let mut tmp_buffer = [255u8; 8]; - for jdx in idx..data.len() { - tmp_buffer[jdx] = data[idx + jdx]; - } + tmp_buffer[idx..data.len()].copy_from_slice(&data[(idx + idx)..(data.len() + idx)]); let tmp_dword = u64::from_le_bytes(tmp_buffer); word1 = tmp_dword as u32; word2 = (tmp_dword >> 32) as u32; @@ -392,6 +391,7 @@ pub struct Parts { pub(crate) cr: CR, /// Opaque ECCR register + #[allow(unused)] pub(crate) eccr: ECCR, /// Opaque KEYR register @@ -410,9 +410,11 @@ pub struct Parts { pub(crate) _pcrop1er: PCROP1ER, /// Opaque PDKEYR register + #[allow(unused)] pub(crate) pdkeyr: PDKEYR, /// Opaque SEC1R register + #[allow(unused)] pub(crate) sec1r: SEC1R, /// Opaque SR register diff --git a/src/pwm.rs b/src/pwm.rs index ad65463a..4cfd69e8 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -1080,8 +1080,6 @@ fn calculate_deadtime(base_freq: Hertz, deadtime: NanoSecond) -> (u8, u8) { let deadtime_ticks = deadtime_ticks as u64 * 429497; let deadtime_ticks = (deadtime_ticks >> 32) as u32; - let deadtime_ticks = deadtime_ticks as u32; - // Choose CR1 CKD divider of 1, 2, or 4 to determine tDTS let (deadtime_ticks, ckd) = match deadtime_ticks { t if t <= 1008 => (deadtime_ticks, 1), diff --git a/src/rcc/config.rs b/src/rcc/config.rs index 1f54d923..5dec5a5b 100644 --- a/src/rcc/config.rs +++ b/src/rcc/config.rs @@ -71,11 +71,11 @@ pub enum PllMDiv { impl PllMDiv { pub fn divisor(&self) -> u32 { - (self.clone() as u32) + 1 + (*self as u32) + 1 } pub fn register_setting(&self) -> u8 { - self.clone() as u8 + *self as u8 } } @@ -90,11 +90,11 @@ pub enum PllQDiv { impl PllQDiv { pub fn divisor(&self) -> u32 { - ((self.clone() as u32) + 1) * 2 + ((*self as u32) + 1) * 2 } pub fn register_setting(&self) -> u8 { - self.clone() as u8 + *self as u8 } } @@ -109,11 +109,11 @@ pub enum PllRDiv { impl PllRDiv { pub fn divisor(&self) -> u32 { - ((self.clone() as u32) + 1) * 2 + ((*self as u32) + 1) * 2 } pub fn register_setting(&self) -> u8 { - self.clone() as u8 + *self as u8 } } @@ -158,11 +158,11 @@ pub enum PllPDiv { impl PllPDiv { pub fn divisor(&self) -> u32 { - self.clone() as u32 + *self as u32 } pub fn register_setting(&self) -> u8 { - self.clone() as u8 + *self as u8 } } @@ -293,11 +293,11 @@ pub enum PllNMul { impl PllNMul { pub fn multiplier(&self) -> u32 { - self.clone() as u32 + *self as u32 } pub fn register_setting(&self) -> u8 { - self.clone() as u8 + *self as u8 } } diff --git a/src/timer.rs b/src/timer.rs index 47584e76..eae92497 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -150,6 +150,7 @@ impl MonoTimer { dwt.enable_cycle_counter(); // now the CYCCNT counter can't be stopped or reset + #[allow(clippy::drop_non_drop)] drop(dwt); MonoTimer {