Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions embassy-stm32/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* **Fix(stm32h5):** Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696)
## Unreleased - ReleaseDate

- feat: Added support for injected ADC sampling for g4 ([#4243](https://github.com/embassy-rs/embassy/pull/4243))
- fix flash erase on L4 & L5
- fix: Fixed STM32H5 builds requiring time feature
- feat: Derive Clone, Copy for QSPI Config
Expand Down
103 changes: 99 additions & 4 deletions embassy-stm32/src/adc/g4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
use pac::adc::vals::{Adcaldif, Difsel, Exten};
#[allow(unused)]
#[cfg(stm32g4)]
use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs};
use pac::adccommon::vals::Presc;
use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen};
pub use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs};
pub use pac::adccommon::vals::Presc;
pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen};
pub use stm32_metapac::adccommon::vals::Dual;

use super::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, blocking_delay_us};
use crate::adc::SealedAdcChannel;
Expand All @@ -18,6 +19,8 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
/// VREF voltage used for factory calibration of VREFINTCAL register.
pub const VREF_CALIB_MV: u32 = 3300;

const NR_INJECTED_RANKS: usize = 4;

/// Max single ADC operation clock frequency
#[cfg(stm32g4)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
Expand Down Expand Up @@ -357,7 +360,7 @@ impl<'d, T: Instance> Adc<'d, T> {
self.read_channel(channel)
}

/// Read one or multiple ADC channels using DMA.
/// Read one or multiple ADC regular channels using DMA.
///
/// `sequence` iterator and `readings` must have the same length.
///
Expand Down Expand Up @@ -477,6 +480,98 @@ impl<'d, T: Instance> Adc<'d, T> {
});
}

// Dual ADC mode selection
pub fn configure_dual_mode(&mut self, val: Dual) {
T::common_regs().ccr().modify(|reg| {
reg.set_dual(val);
})
}

/// Configure a sequence of injected channels
pub fn configure_injected_sequence<'a>(
&mut self,
sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<T>, SampleTime)>,
) {
assert!(sequence.len() != 0, "Read sequence cannot be empty");
assert!(
sequence.len() <= NR_INJECTED_RANKS,
"Read sequence cannot be more than 4 in length"
);

// Ensure no conversions are ongoing and ADC is enabled.
Self::cancel_conversions();
self.enable();

// Set sequence length
T::regs().jsqr().modify(|w| {
w.set_jl(sequence.len() as u8 - 1);
});

// Configure channels and ranks
for (n, (channel, sample_time)) in sequence.enumerate() {
Self::configure_channel(channel, sample_time);

match n {
0..=3 => {
T::regs().jsqr().modify(|w| {
w.set_jsq(n, channel.channel());
});
}
4..=8 => {
T::regs().jsqr().modify(|w| {
w.set_jsq(n - 4, channel.channel());
});
}
9..=13 => {
T::regs().jsqr().modify(|w| {
w.set_jsq(n - 9, channel.channel());
});
}
14..=15 => {
T::regs().jsqr().modify(|w| {
w.set_jsq(n - 14, channel.channel());
});
}
_ => unreachable!(),
}
}

T::regs().cfgr().modify(|reg| {
reg.set_jdiscen(false); // Will convert all channels for each trigger
});

// Start conversion
T::regs().cr().modify(|reg| {
reg.set_jadstart(true);
});
}

/// Set external trigger for injected conversion sequence
pub fn set_injected_conversion_trigger(&mut self, trigger: u8, edge: Exten) {
T::regs().jsqr().modify(|r| {
r.set_jextsel(trigger); // ADC group injected external trigger source
r.set_jexten(edge); // ADC group injected external trigger polarity
});
}

/// Enable end of injected sequence interrupt
pub fn enable_injected_eos_interrupt(&mut self, enable: bool) {
T::regs().ier().modify(|r| r.set_jeosie(enable));
}

/// Read sampled data from all injected ADC injected ranks
/// Clear the JEOS flag to allow a new injected sequence
pub fn clear_injected_eos(&mut self) -> [u16; NR_INJECTED_RANKS] {
let mut data = [0u16; NR_INJECTED_RANKS];
for i in 0..NR_INJECTED_RANKS {
data[i] = T::regs().jdr(i).read().jdata();
}

// Clear JEOS by writing 1
T::regs().isr().modify(|r| r.set_jeos(true));
data
}

fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
// Configure channel
Self::set_channel_sample_time(channel.channel(), sample_time);
Expand Down
12 changes: 11 additions & 1 deletion embassy-stm32/src/timer/complementary_pwm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use core::marker::PhantomData;

pub use stm32_metapac::timer::vals::{Ckd, Ossi, Ossr};
pub use stm32_metapac::timer::vals::{Ckd, Mms2, Ossi, Ossr};

use super::low_level::{CountingMode, OutputPolarity, Timer};
use super::simple_pwm::PwmPin;
Expand Down Expand Up @@ -136,6 +136,16 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
self.inner.get_moe()
}

/// Set Master Slave Mode 2
pub fn set_mms2(&mut self, mms2: Mms2) {
self.inner.set_mms2_selection(mms2);
}

/// Set Repetition Counter
pub fn set_repetition_counter(&mut self, val: u16) {
self.inner.set_repetition_counter(val);
}

/// Enable the given channel.
pub fn enable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, true);
Expand Down
10 changes: 10 additions & 0 deletions embassy-stm32/src/timer/low_level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,16 @@ impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val));
}

/// Set master mode selection 2
pub fn set_mms2_selection(&self, mms2: vals::Mms2) {
self.regs_advanced().cr2().modify(|w| w.set_mms2(mms2));
}

/// Set repetition counter
pub fn set_repetition_counter(&self, val: u16) {
self.regs_advanced().rcr().modify(|w| w.set_rep(val));
}

/// Trigger software break 1 or 2
/// Setting this bit generates a break event. This bit is automatically cleared by the hardware.
pub fn trigger_software_break(&self, n: usize) {
Expand Down