Adds ADC4 for WBA

This commit is contained in:
purepani 2025-06-30 03:04:52 -05:00
parent 15c7526c0a
commit 08f3b45de6
No known key found for this signature in database
GPG Key ID: AE638DA3914078EC
4 changed files with 141 additions and 30 deletions

View File

@ -1490,6 +1490,10 @@ fn main() {
signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma));
}
if chip_name.starts_with("stm32wba") {
signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma4));
}
if chip_name.starts_with("stm32g4") {
let line_number = chip_name.chars().skip(8).next().unwrap();
if line_number == '3' || line_number == '4' {

View File

@ -1,10 +1,19 @@
#[cfg(stm32u5)]
use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingRatio as OversamplingRatio};
#[allow(unused)]
use pac::adc::vals::{Adc4Dmacfg, Adc4Exten, Adc4OversamplingRatio};
#[cfg(stm32wba)]
use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel};
use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel};
use crate::dma::Transfer;
pub use crate::pac::adc::regs::Adc4Chselrmod0;
#[cfg(stm32u5)]
pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr;
#[cfg(stm32wba)]
pub use crate::pac::adc::regs::Chselr;
#[cfg(stm32u5)]
pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4SampleTime as SampleTime};
#[cfg(stm32wba)]
pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime};
use crate::time::Hertz;
use crate::{pac, rcc, Peri};
@ -242,17 +251,28 @@ impl<'d, T: Instance> Adc4<'d, T> {
fn configure(&mut self) {
// single conversion mode, software trigger
T::regs().cfgr1().modify(|w| {
#[cfg(stm32u5)]
w.set_cont(false);
#[cfg(stm32wba)]
w.set_cont(Cont::SINGLE);
w.set_discen(false);
w.set_exten(Adc4Exten::DISABLED);
w.set_exten(Exten::DISABLED);
#[cfg(stm32u5)]
w.set_chselrmod(false);
#[cfg(stm32wba)]
w.set_chselrmod(Chselrmod::ENABLE_INPUT);
});
// only use one channel at the moment
T::regs().smpr().modify(|w| {
#[cfg(stm32u5)]
for i in 0..24 {
w.set_smpsel(i, false);
}
#[cfg(stm32wba)]
for i in 0..14 {
w.set_smpsel(i, Smpsel::SMP1);
}
});
}
@ -275,6 +295,7 @@ impl<'d, T: Instance> Adc4<'d, T> {
}
/// Enable reading the vbat internal channel.
#[cfg(stm32u5)]
pub fn enable_vbat(&self) -> Vbat {
T::regs().ccr().modify(|w| {
w.set_vbaten(true);
@ -289,6 +310,7 @@ impl<'d, T: Instance> Adc4<'d, T> {
}
/// Enable reading the vbat internal channel.
#[cfg(stm32u5)]
pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac {
let mux;
match dac {
@ -317,17 +339,38 @@ impl<'d, T: Instance> Adc4<'d, T> {
}
/// Set hardware averaging.
#[cfg(stm32u5)]
pub fn set_averaging(&mut self, averaging: Averaging) {
let (enable, samples, right_shift) = match averaging {
Averaging::Disabled => (false, Adc4OversamplingRatio::OVERSAMPLE2X, 0),
Averaging::Samples2 => (true, Adc4OversamplingRatio::OVERSAMPLE2X, 1),
Averaging::Samples4 => (true, Adc4OversamplingRatio::OVERSAMPLE4X, 2),
Averaging::Samples8 => (true, Adc4OversamplingRatio::OVERSAMPLE8X, 3),
Averaging::Samples16 => (true, Adc4OversamplingRatio::OVERSAMPLE16X, 4),
Averaging::Samples32 => (true, Adc4OversamplingRatio::OVERSAMPLE32X, 5),
Averaging::Samples64 => (true, Adc4OversamplingRatio::OVERSAMPLE64X, 6),
Averaging::Samples128 => (true, Adc4OversamplingRatio::OVERSAMPLE128X, 7),
Averaging::Samples256 => (true, Adc4OversamplingRatio::OVERSAMPLE256X, 8),
Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0),
Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1),
Averaging::Samples4 => (true, OversamplingRatio::OVERSAMPLE4X, 2),
Averaging::Samples8 => (true, OversamplingRatio::OVERSAMPLE8X, 3),
Averaging::Samples16 => (true, OversamplingRatio::OVERSAMPLE16X, 4),
Averaging::Samples32 => (true, OversamplingRatio::OVERSAMPLE32X, 5),
Averaging::Samples64 => (true, OversamplingRatio::OVERSAMPLE64X, 6),
Averaging::Samples128 => (true, OversamplingRatio::OVERSAMPLE128X, 7),
Averaging::Samples256 => (true, OversamplingRatio::OVERSAMPLE256X, 8),
};
T::regs().cfgr2().modify(|w| {
w.set_ovsr(samples);
w.set_ovss(right_shift);
w.set_ovse(enable)
})
}
#[cfg(stm32wba)]
pub fn set_averaging(&mut self, averaging: Averaging) {
let (enable, samples, right_shift) = match averaging {
Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0),
Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1),
Averaging::Samples4 => (true, OversamplingRatio::OVERSAMPLE4X, Ovss::SHIFT2),
Averaging::Samples8 => (true, OversamplingRatio::OVERSAMPLE8X, Ovss::SHIFT3),
Averaging::Samples16 => (true, OversamplingRatio::OVERSAMPLE16X, Ovss::SHIFT4),
Averaging::Samples32 => (true, OversamplingRatio::OVERSAMPLE32X, Ovss::SHIFT5),
Averaging::Samples64 => (true, OversamplingRatio::OVERSAMPLE64X, Ovss::SHIFT6),
Averaging::Samples128 => (true, OversamplingRatio::OVERSAMPLE128X, Ovss::SHIFT7),
Averaging::Samples256 => (true, OversamplingRatio::OVERSAMPLE256X, Ovss::SHIFT8),
};
T::regs().cfgr2().modify(|w| {
@ -342,10 +385,20 @@ impl<'d, T: Instance> Adc4<'d, T> {
channel.setup();
// Select channel
T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32));
T::regs().chselrmod0().modify(|w| {
w.set_chsel(channel.channel() as usize, true);
});
#[cfg(stm32wba)]
{
T::regs().chselr().write_value(Chselr(0_u32));
T::regs().chselr().modify(|w| {
w.set_chsel0(channel.channel() as usize, true);
});
}
#[cfg(stm32u5)]
{
T::regs().chselrmod0().write_value(Chselr(0_u32));
T::regs().chselrmod0().modify(|w| {
w.set_chsel(channel.channel() as usize, true);
});
}
// Reset interrupts
T::regs().isr().modify(|reg| {
@ -415,13 +468,19 @@ impl<'d, T: Instance> Adc4<'d, T> {
T::regs().cfgr1().modify(|reg| {
reg.set_dmaen(true);
reg.set_dmacfg(Adc4Dmacfg::ONE_SHOT);
reg.set_dmacfg(Dmacfg::ONE_SHOT);
#[cfg(stm32u5)]
reg.set_chselrmod(false);
#[cfg(stm32wba)]
reg.set_chselrmod(Chselrmod::ENABLE_INPUT)
});
// Verify and activate sequence
let mut prev_channel: i16 = -1;
T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32));
#[cfg(stm32wba)]
T::regs().chselr().write_value(Chselr(0_u32));
#[cfg(stm32u5)]
T::regs().chselrmod0().write_value(Chselr(0_u32));
for channel in sequence {
let channel_num = channel.channel;
if channel_num as i16 <= prev_channel {
@ -429,6 +488,11 @@ impl<'d, T: Instance> Adc4<'d, T> {
};
prev_channel = channel_num as i16;
#[cfg(stm32wba)]
T::regs().chselr().modify(|w| {
w.set_chsel0(channel.channel as usize, true);
});
#[cfg(stm32u5)]
T::regs().chselrmod0().modify(|w| {
w.set_chsel(channel.channel as usize, true);
});

View File

@ -4,7 +4,7 @@
#![allow(missing_docs)] // TODO
#![cfg_attr(adc_f3_v2, allow(unused))]
#[cfg(not(any(adc_f3_v2)))]
#[cfg(not(any(adc_f3_v2, adc_wba)))]
#[cfg_attr(adc_f1, path = "f1.rs")]
#[cfg_attr(adc_f3, path = "f3.rs")]
#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
@ -20,14 +20,14 @@ mod _version;
use core::marker::PhantomData;
#[allow(unused)]
#[cfg(not(any(adc_f3_v2)))]
#[cfg(not(any(adc_f3_v2, adc_wba)))]
pub use _version::*;
use embassy_hal_internal::{impl_peripheral, PeripheralType};
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
use embassy_sync::waitqueue::AtomicWaker;
#[cfg(adc_u5)]
#[path = "u5_adc4.rs"]
#[cfg(any(adc_u5, adc_wba))]
#[path = "adc4.rs"]
pub mod adc4;
pub use crate::pac::adc::vals;
@ -36,15 +36,18 @@ pub use crate::pac::adc::vals::Res as Resolution;
pub use crate::pac::adc::vals::SampleTime;
use crate::peripherals;
#[cfg(not(adc_wba))]
dma_trait!(RxDma, Instance);
#[cfg(adc_u5)]
dma_trait!(RxDma4, adc4::Instance);
#[cfg(adc_wba)]
dma_trait!(RxDma4, adc4::Instance);
/// Analog to Digital driver.
pub struct Adc<'d, T: Instance> {
#[allow(unused)]
adc: crate::Peri<'d, T>,
#[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))]
#[cfg(not(any(adc_f3_v2, adc_f3_v1_1, adc_wba)))]
sample_time: SampleTime,
}
@ -63,6 +66,7 @@ impl State {
}
trait SealedInstance {
#[cfg(not(adc_wba))]
#[allow(unused)]
fn regs() -> crate::pac::adc::Adc;
#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
@ -73,7 +77,7 @@ trait SealedInstance {
}
pub(crate) trait SealedAdcChannel<T> {
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
fn setup(&mut self) {}
#[allow(unused)]
@ -110,7 +114,8 @@ pub(crate) fn blocking_delay_us(us: u32) {
adc_h5,
adc_h7rs,
adc_u5,
adc_c0
adc_c0,
adc_wba,
)))]
#[allow(private_bounds)]
pub trait Instance: SealedInstance + crate::PeripheralType {
@ -132,7 +137,8 @@ pub trait Instance: SealedInstance + crate::PeripheralType {
adc_h5,
adc_h7rs,
adc_u5,
adc_c0
adc_c0,
adc_wba,
))]
#[allow(private_bounds)]
pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral {
@ -144,7 +150,7 @@ pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeri
pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
#[allow(unused_mut)]
fn degrade_adc(mut self) -> AnyAdcChannel<T> {
#[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
#[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
self.setup();
AnyAdcChannel {
@ -176,6 +182,36 @@ impl<T> AnyAdcChannel<T> {
self.channel
}
}
#[cfg(adc_wba)]
foreach_adc!(
(ADC4, $common_inst:ident, $clock:ident) => {
impl crate::adc::adc4::SealedInstance for peripherals::ADC4 {
fn regs() -> crate::pac::adc::Adc4 {
crate::pac::ADC4
}
}
impl crate::adc::adc4::Instance for peripherals::ADC4 {
type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL;
}
};
($inst:ident, $common_inst:ident, $clock:ident) => {
impl crate::adc::SealedInstance for peripherals::$inst {
fn regs() -> crate::pac::adc::Adc {
crate::pac::$inst
}
fn common_regs() -> crate::pac::adccommon::AdcCommon {
return crate::pac::$common_inst
}
}
impl crate::adc::Instance for peripherals::$inst {
type Interrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL;
}
};
);
#[cfg(adc_u5)]
foreach_adc!(
@ -208,15 +244,21 @@ foreach_adc!(
};
);
#[cfg(not(adc_u5))]
#[cfg(not(any(adc_u5, adc_wba)))]
foreach_adc!(
($inst:ident, $common_inst:ident, $clock:ident) => {
impl crate::adc::SealedInstance for peripherals::$inst {
#[cfg(not(adc_wba))]
fn regs() -> crate::pac::adc::Adc {
crate::pac::$inst
}
#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
#[cfg(adc_wba)]
fn regs() -> crate::pac::adc::Adc4 {
crate::pac::$inst
}
#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5, adc_wba)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon {
return crate::pac::$common_inst
}
@ -238,7 +280,7 @@ macro_rules! impl_adc_pin {
($inst:ident, $pin:ident, $ch:expr) => {
impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {}
impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
fn setup(&mut self) {
<crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self);
}

View File

@ -176,6 +176,7 @@ pub(crate) unsafe fn init(config: Config) {
// TODO
lse: None,
lsi: None,
pll1_p: None,
pll1_q: None,
);
}