Skip to content

Commit db96799

Browse files
committed
Add method to initialise ADC1 and ADC2 together.
See #93 Remove forced switching of adc_ker_ck_input to per_ck. Instead read and check the current adc_ker_ck_input
1 parent 47a9c3f commit db96799

File tree

2 files changed

+110
-43
lines changed

2 files changed

+110
-43
lines changed

examples/adc.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#![deny(unsafe_code)]
21
#![no_main]
32
#![no_std]
43

@@ -29,14 +28,21 @@ fn main() -> ! {
2928
println!(log, "Setup RCC... ");
3029
let rcc = dp.RCC.constrain();
3130

32-
// setting this per_ck to 4 Mhz here (which is gonna choose the CSI that runs at exactly 4 Mhz) as the adc requires per_ck as its
33-
// own kernel clock and wouldn't work at all if per_ck wouldnt be enabled or loose a few bits if it was too fast
34-
// (the maximum for this is 36 Mhz)
31+
// We need to configure a clock for adc_ker_ck_input. The default
32+
// adc_ker_ck_input is pll2_p_ck, but we will use per_ck. Here we
33+
// set per_ck to 4MHz.
34+
//
35+
// The maximum adc_ker_ck_input frequency is 100MHz for revision V and 36MHz
36+
// otherwise
3537
let ccdr = rcc
3638
.sys_ck(100.mhz())
3739
.per_ck(4.mhz())
3840
.freeze(vos, &dp.SYSCFG);
3941

42+
// Switch adc_ker_ck_input multiplexer to per_ck
43+
let d3ccipr = &unsafe { &*pac::RCC::ptr() }.d3ccipr;
44+
d3ccipr.modify(|_, w| unsafe { w.adcsel().bits(0b10) });
45+
4046
println!(log, "");
4147
println!(log, "stm32h7xx-hal example - ADC");
4248
println!(log, "");

src/adc.rs

Lines changed: 100 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
//! Analog to Digital Converter (ADC)
2+
//!
3+
//! ADC1 and ADC2 share a reset line. To initialise both of them, use the
4+
//! `adc12` method.
25
36
use crate::hal::adc::{Channel, OneShot};
47
use crate::hal::blocking::delay::DelayUs;
58

69
use core::marker::PhantomData;
710

8-
use crate::stm32;
911
use crate::stm32::{ADC1, ADC2, ADC3, ADC3_COMMON};
1012

1113
use crate::delay::Delay;
@@ -17,7 +19,10 @@ use crate::gpio::gpiof::{
1719
};
1820
use crate::gpio::gpioh::{PH2, PH3, PH4, PH5};
1921
use crate::gpio::Analog;
22+
use crate::rcc::rec::AdcClkSelGetter;
2023
use crate::rcc::{rec, CoreClocks, ResetEnable};
24+
use crate::time::Hertz;
25+
use stm32h7::Variant::Val;
2126

2227
#[cfg(not(feature = "revision_v"))]
2328
const ADC_KER_CK_MAX: u32 = 36_000_000;
@@ -287,13 +292,84 @@ pub trait AdcExt<ADC>: Sized {
287292
#[derive(Copy, Clone, Debug, PartialEq)]
288293
pub struct StoredConfig(AdcSampleTime, Resolution, AdcLshift);
289294

295+
/// Get and check the adc_ker_ck_input
296+
fn check_clock(prec: &impl AdcClkSelGetter, clocks: &CoreClocks) -> Hertz {
297+
// Select Kernel Clock
298+
let adc_clock = match prec.get_kernel_clk_mux() {
299+
Val(rec::AdcClkSel::PER) => clocks.per_ck(),
300+
_ => unreachable!(),
301+
}
302+
.expect("adc_ker_ck_input is not running!");
303+
304+
// Check against datasheet requirements
305+
assert!(
306+
adc_clock.0 <= ADC_KER_CK_MAX,
307+
"adc_ker_ck_input is too fast"
308+
);
309+
310+
adc_clock
311+
}
312+
313+
// ADC12 is a unique case where a single reset line is used to control two
314+
// peripherals that have separate peripheral definitons in the SVD.
315+
316+
/// Initialise ADC12 together
317+
///
318+
/// Sets all configurable parameters to one-shot defaults,
319+
/// performs a boot-time calibration.
320+
pub fn adc12(
321+
adc1: ADC1,
322+
adc2: ADC2,
323+
delay: &mut Delay,
324+
prec: rec::Adc12,
325+
clocks: &CoreClocks,
326+
) -> (Adc<ADC1, Disabled>, Adc<ADC2, Disabled>) {
327+
let mut a1 = Adc::<ADC1, Disabled>::default_from_rb(adc1);
328+
let mut a2 = Adc::<ADC2, Disabled>::default_from_rb(adc2);
329+
330+
// Check adc_ker_ck_input
331+
check_clock(&prec, clocks);
332+
333+
// Enable AHB clock
334+
let prec = prec.enable();
335+
336+
// Power Down
337+
a1.power_down();
338+
a2.power_down();
339+
340+
// Reset peripheral
341+
prec.reset();
342+
343+
// Power Up, Preconfigure and Calibrate
344+
a1.power_up(delay);
345+
a2.power_up(delay);
346+
a1.preconfigure();
347+
a2.preconfigure();
348+
a1.calibrate();
349+
a2.calibrate();
350+
351+
(a1, a2)
352+
}
353+
354+
/// Freeing both the periperhal and PREC is possible for ADC3
355+
impl<ED> Adc<ADC3, ED> {
356+
/// Releases the ADC peripheral
357+
pub fn free(self) -> (ADC3, rec::Adc3) {
358+
(
359+
self.rb,
360+
rec::Adc3 {
361+
_marker: PhantomData,
362+
},
363+
)
364+
}
365+
}
366+
290367
#[allow(unused_macros)]
291368
macro_rules! adc_hal {
292369
($(
293370
$ADC:ident: (
294371
$adcX: ident,
295-
$Rec:ident,
296-
$COMMON:ident
372+
$Rec:ident
297373
)
298374
),+ $(,)*) => {
299375
$(
@@ -317,46 +393,37 @@ macro_rules! adc_hal {
317393
pub fn $adcX(adc: $ADC, delay: &mut Delay,
318394
prec: rec::$Rec, clocks: &CoreClocks
319395
) -> Self {
320-
let mut s = Self {
321-
rb: adc,
322-
sample_time: AdcSampleTime::default(),
323-
resolution: Resolution::SIXTEENBIT,
324-
lshift: AdcLshift::default(),
325-
_enabled: PhantomData,
326-
};
396+
let mut a = Self::default_from_rb(adc);
327397

328-
// Select Kernel Clock
329-
s.enable_clock(
330-
clocks.per_ck().expect("per_ck is not running!").0
331-
);
398+
// Check adc_ker_ck_input
399+
check_clock(&prec, clocks);
332400

333401
// Enable AHB clock
334402
let prec = prec.enable();
335403

336404
// Power Down
337-
s.power_down();
405+
a.power_down();
338406

339-
// Reset periperal
407+
// Reset peripheral
340408
prec.reset();
341409

342410
// Power Up, Preconfigure and Calibrate
343-
s.power_up(delay);
344-
s.preconfigure();
345-
s.calibrate();
411+
a.power_up(delay);
412+
a.preconfigure();
413+
a.calibrate();
346414

347-
s
415+
a
348416
}
349-
350-
fn enable_clock(&mut self, per_ck: u32) {
351-
// Set per_ck as adc clock, TODO: we might want to
352-
// change this so we can also use other clocks as
353-
// input for this
354-
assert!(per_ck <= ADC_KER_CK_MAX, "per_ck is not running or too fast");
355-
let d3ccipr = &unsafe { &*stm32::RCC::ptr() }.d3ccipr;
356-
357-
d3ccipr.modify(|_, w| unsafe { w.adcsel().bits(0b10) });
417+
/// Creates ADC with default settings
418+
fn default_from_rb(rb: $ADC) -> Self {
419+
Self {
420+
rb,
421+
sample_time: AdcSampleTime::default(),
422+
resolution: Resolution::SIXTEENBIT,
423+
lshift: AdcLshift::default(),
424+
_enabled: PhantomData,
425+
}
358426
}
359-
360427
/// Disables Deeppowerdown-mode and enables voltage regulator
361428
///
362429
/// Note: After power-up, a [`calibration`](#method.calibrate) shall be run
@@ -571,12 +638,6 @@ macro_rules! adc_hal {
571638
}
572639

573640
impl<ED> Adc<$ADC, ED> {
574-
575-
/// Releases the ADC peripheral
576-
pub fn free(self) -> ($ADC, rec::$Rec) {
577-
(self.rb, rec::$Rec { _marker: PhantomData })
578-
}
579-
580641
/// Save current ADC config
581642
pub fn save_cfg(&mut self) -> StoredConfig {
582643
StoredConfig(self.get_sample_time(), self.get_resolution(), self.get_lshift())
@@ -714,7 +775,7 @@ macro_rules! adc_hal {
714775
}
715776

716777
adc_hal!(
717-
ADC1: (adc1, Adc12, ADC12_COMMON),
718-
ADC2: (adc2, Adc12, ADC12_COMMON),
719-
ADC3: (adc3, Adc3, ADC3_COMMON),
778+
ADC1: (adc1, Adc12), // ADC1
779+
ADC2: (adc2, Adc12), // ADC2
780+
ADC3: (adc3, Adc3), // ADC3
720781
);

0 commit comments

Comments
 (0)