Skip to content

Commit 87b30c2

Browse files
committed
PCLK source ID can be either type-checked or runtime-checked
1 parent 29ff978 commit 87b30c2

7 files changed

Lines changed: 198 additions & 29 deletions

File tree

boards/atsame54_xpro/examples/mcan.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ type Aux = mcan::bus::Aux<
8383
clock::types::Can1,
8484
hal::can::Dependencies<
8585
clock::types::Can1,
86-
clock::gclk::Gclk0Id,
86+
clock::pclk::PclkSource<clock::gclk::Gclk0Id>,
8787
bsp::Ata6561Rx,
8888
bsp::Ata6561Tx,
8989
bsp::pac::Can1,

boards/examples/m4-adc.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,20 @@ fn main() -> ! {
4444
let apb_adc0 = buses.apb.enable(tokens.apbs.adc0);
4545
// ...and enable the ADC0 PCLK. Both of these are required for the
4646
// ADC to run.
47-
let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0);
47+
let (pclk_adc0, _gclk0) = Pclk::enable_dyn(tokens.pclks.adc0, clocks.gclk0);
4848

4949
let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12))
5050
.with_clock_cycles_per_sample(5)
5151
// Overruns if clock divider < 32 in debug mode
5252
.with_clock_divider(Prescaler::Div32)
5353
.with_vref(atsamd_hal::adc::Reference::Arefa)
54-
.enable(peripherals.adc0, apb_adc0, &pclk_adc0)
54+
.enable(peripherals.adc0, apb_adc0, pclk_adc0)
5555
.unwrap();
5656
let mut adc_pin = pins.a0.into_alternate();
5757

5858
loop {
59-
let res = adc.read(&mut adc_pin);
59+
let _res = adc.read(&mut adc_pin);
6060
#[cfg(feature = "use_semihosting")]
61-
let _ = cortex_m_semihosting::hprintln!("ADC value: {}", res);
61+
let _ = cortex_m_semihosting::hprintln!("ADC value: {}", _res);
6262
}
6363
}

hal/src/clock/v2/gclk.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ impl<G: GclkId> GclkToken<G> {
462462
/// The variants of this enum identify one generic clock generator.
463463
///
464464
/// `DynGclkId` is the value-level equivalent of [`GclkId`].
465+
#[derive(Clone, Copy, PartialEq, Eq)]
465466
#[hal_macro_helper]
466467
pub enum DynGclkId {
467468
Gclk0,
@@ -484,6 +485,32 @@ pub enum DynGclkId {
484485
Gclk11,
485486
}
486487

488+
impl core::fmt::Debug for DynGclkId {
489+
#[hal_macro_helper]
490+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
491+
match self {
492+
Self::Gclk0 => write!(f, "Gclk0"),
493+
Self::Gclk1 => write!(f, "Gclk1"),
494+
Self::Gclk2 => write!(f, "Gclk2"),
495+
Self::Gclk3 => write!(f, "Gclk3"),
496+
Self::Gclk4 => write!(f, "Gclk4"),
497+
Self::Gclk5 => write!(f, "Gclk5"),
498+
#[hal_cfg("gclk6")]
499+
Self::Gclk6 => write!(f, "Gclk6"),
500+
#[hal_cfg("gclk7")]
501+
Self::Gclk7 => write!(f, "Gclk7"),
502+
#[hal_cfg("gclk8")]
503+
Self::Gclk8 => write!(f, "Gclk8"),
504+
#[hal_cfg("gclk9")]
505+
Self::Gclk9 => write!(f, "Gclk9"),
506+
#[hal_cfg("gclk10")]
507+
Self::Gclk10 => write!(f, "Gclk10"),
508+
#[hal_cfg("gclk11")]
509+
Self::Gclk11 => write!(f, "Gclk11"),
510+
}
511+
}
512+
}
513+
487514
//==============================================================================
488515
// GclkId
489516
//==============================================================================

hal/src/clock/v2/pclk.rs

Lines changed: 136 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,22 @@ impl From<DynPclkSourceId> for Genselect {
547547
}
548548
}
549549

550+
impl PclkSourceId for DynPclkSourceId {
551+
fn source_id(&self) -> DynGclkId {
552+
*self
553+
}
554+
}
555+
556+
impl Sealed for DynPclkSourceId {}
557+
558+
//==============================================================================
559+
// PclkSourceId
560+
//==============================================================================
561+
562+
pub struct PclkSource<G: GclkId> {
563+
_src: PhantomData<G>,
564+
}
565+
550566
//==============================================================================
551567
// PclkSourceId
552568
//==============================================================================
@@ -566,9 +582,25 @@ impl From<DynPclkSourceId> for Genselect {
566582
/// [`Gclk`]: super::gclk::Gclk
567583
/// [type-level programming]: crate::typelevel
568584
/// [type-level enums]: crate::typelevel#type-level-enums
569-
pub trait PclkSourceId: GclkId {}
585+
pub trait PclkSourceId: Sealed {
586+
fn source_id(&self) -> DynGclkId;
587+
}
588+
589+
impl<G: GclkId> PclkSourceId for G {
590+
#[inline]
591+
fn source_id(&self) -> DynGclkId {
592+
Self::DYN
593+
}
594+
}
570595

571-
impl<G: GclkId> PclkSourceId for G {}
596+
impl<G: GclkId> PclkSourceId for PclkSource<G> {
597+
#[inline]
598+
fn source_id(&self) -> DynGclkId {
599+
G::DYN
600+
}
601+
}
602+
603+
impl<G: GclkId> Sealed for PclkSource<G> {}
572604

573605
//==============================================================================
574606
// Pclk
@@ -606,24 +638,41 @@ where
606638
I: PclkSourceId,
607639
{
608640
token: PclkToken<P>,
609-
src: PhantomData<I>,
641+
src: I,
610642
freq: Hertz,
611643
}
612644

613-
impl<P, I> Pclk<P, I>
645+
/// [`Pclk`] with a dynamic source ID ([`DynPclkSourceId`]).
646+
pub type DynPclk<P> = Pclk<P, DynPclkSourceId>;
647+
648+
impl<P, G> From<Pclk<P, PclkSource<G>>> for DynPclk<P>
614649
where
615650
P: PclkId,
616-
I: PclkSourceId,
651+
G: GclkId,
652+
{
653+
fn from(value: Pclk<P, PclkSource<G>>) -> Self {
654+
Pclk {
655+
token: value.token,
656+
freq: value.freq,
657+
src: G::DYN,
658+
}
659+
}
660+
}
661+
662+
impl<P, G> Pclk<P, PclkSource<G>>
663+
where
664+
P: PclkId,
665+
G: GclkId,
617666
{
618667
pub(super) fn new(token: PclkToken<P>, freq: Hertz) -> Self {
619668
Self {
620669
token,
621-
src: PhantomData,
670+
src: PclkSource { _src: PhantomData },
622671
freq,
623672
}
624673
}
625674

626-
/// Create and enable a [`Pclk`]
675+
/// Create and enable a [`Pclk`] with a type-checked source ID.
627676
///
628677
/// Creating a [`Pclk`] immediately enables the corresponding peripheral
629678
/// channel clock. It also [`Increment`]s the [`Source`]'s [`Enabled`]
@@ -636,15 +685,15 @@ where
636685
#[inline]
637686
pub fn enable<S>(mut token: PclkToken<P>, gclk: S) -> (Self, S::Inc)
638687
where
639-
S: Source<Id = I> + Increment,
688+
S: Source<Id = G> + Increment,
640689
{
641690
let freq = gclk.freq();
642-
token.enable(I::DYN);
643-
let pclk = Pclk::new(token, freq);
691+
token.enable(G::DYN);
692+
let pclk = Self::new(token, freq);
644693
(pclk, gclk.inc())
645694
}
646695

647-
/// Disable and destroy a [`Pclk`]
696+
/// Disable and destroy a [`Pclk`].
648697
///
649698
/// Consume the [`Pclk`], release the [`PclkToken`], and [`Decrement`] the
650699
/// [`EnabledGclk`]'s counter
@@ -654,12 +703,87 @@ where
654703
#[inline]
655704
pub fn disable<S>(mut self, gclk: S) -> (PclkToken<P>, S::Dec)
656705
where
657-
S: Source<Id = I> + Decrement,
706+
S: Source<Id = G> + Decrement,
707+
{
708+
self.token.disable();
709+
(self.token, gclk.dec())
710+
}
711+
}
712+
713+
impl<P> DynPclk<P>
714+
where
715+
P: PclkId,
716+
{
717+
pub(super) fn new<G: GclkId>(token: PclkToken<P>, freq: Hertz) -> Self {
718+
Self {
719+
token,
720+
src: G::DYN,
721+
freq,
722+
}
723+
}
724+
725+
/// Create and enable a [`Pclk`] with an underlying [`DynPclkSourceId`]
726+
/// source ID type.
727+
///
728+
/// Some peripherals require a dynamic PCLK source ID type parameter; use
729+
/// this method to create a [`Pclk`] where this type parameter is
730+
/// type-erased.
731+
///
732+
/// Creating a [`Pclk`] immediately enables the corresponding peripheral
733+
/// channel clock. It also [`Increment`]s the [`Source`]'s [`Enabled`]
734+
/// counter.
735+
///
736+
/// Note that the [`Source`] will always be an [`EnabledGclk`].
737+
///
738+
/// [`Enabled`]: super::Enabled
739+
/// [`EnabledGclk`]: super::gclk::EnabledGclk
740+
#[inline]
741+
pub fn enable_dyn<S, G: GclkId>(mut token: PclkToken<P>, gclk: S) -> (Self, S::Inc)
742+
where
743+
S: Source<Id = G> + Increment,
658744
{
745+
let freq = gclk.freq();
746+
token.enable(G::DYN);
747+
let pclk = Self::new::<G>(token, freq);
748+
(pclk, gclk.inc())
749+
}
750+
751+
/// Disable and destroy a [`Pclk`].
752+
///
753+
/// Consume the [`Pclk`], release the [`PclkToken`], and [`Decrement`] the
754+
/// [`EnabledGclk`]'s counter.
755+
///
756+
/// # Panics
757+
///
758+
/// Panics if the [`Pclk`]'s underlying GCLK source ID does not match the ID
759+
/// of the provided [`Source`].
760+
///
761+
/// [`Enabled`]: super::Enabled
762+
/// [`EnabledGclk`]: super::gclk::EnabledGclk
763+
#[inline]
764+
pub fn disable<S, G: GclkId>(mut self, gclk: S) -> (PclkToken<P>, S::Dec)
765+
where
766+
S: Source<Id = G> + Decrement,
767+
{
768+
// Make sure that we can only decrement the source we are actually using
769+
assert_eq!(
770+
G::DYN,
771+
self.src,
772+
"Expected GCLK ID {:?}, found {:?}",
773+
G::DYN,
774+
self.src
775+
);
776+
659777
self.token.disable();
660778
(self.token, gclk.dec())
661779
}
780+
}
662781

782+
impl<P, I> Pclk<P, I>
783+
where
784+
P: PclkId,
785+
I: PclkSourceId,
786+
{
663787
/// Return the [`Pclk`] frequency
664788
#[inline]
665789
pub fn freq(&self) -> Hertz {

hal/src/clock/v2/reset_thumbv6m.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ use atsamd_hal_macros::hal_macro_helper;
66

77
use typenum::U1;
88

9-
use crate::pac::{Gclk, Pm, Sysctrl};
9+
use crate::{
10+
clock::v2::pclk::PclkSource,
11+
pac::{Gclk, Pm, Sysctrl},
12+
};
1013

1114
use super::*;
1215

@@ -97,7 +100,7 @@ pub struct Clocks {
97100
/// Always-enabled OSCULP oscillators
98101
pub osculp: OscUlpClocks,
99102
/// [`Pclk`](pclk::Pclk) for the watchdog timer, sourced from [`Gclk2`](gclk::Gclk2)
100-
pub wdt: pclk::Pclk<types::Wdt, gclk::Gclk2Id>,
103+
pub wdt: pclk::Pclk<types::Wdt, PclkSource<gclk::Gclk2Id>>,
101104
}
102105

103106
/// Type-level tokens for unused clocks at power-on reset
@@ -155,7 +158,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl
155158
let osculp32k = Enabled::<_, U0>::new(osculp32k::OscUlp32k::new());
156159
let (gclk2, osculp32k) = gclk::Gclk2::from_source(gclk::GclkToken::new(), osculp32k);
157160
let gclk2 = Enabled::new(gclk2);
158-
let wdt = pclk::Pclk::new(pclk::PclkToken::new(), gclk2.freq());
161+
let wdt = pclk::Pclk::<_, PclkSource<_>>::new(pclk::PclkToken::new(), gclk2.freq());
159162
let osculp = OscUlpClocks {
160163
base,
161164
osculp1k,

hal/src/peripherals/adc/builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,11 @@ impl AdcBuilder {
247247
/// Turn the builder into an ADC
248248
#[hal_cfg("adc-d5x")]
249249
#[inline]
250-
pub fn enable<I: AdcInstance, PS: crate::clock::v2::pclk::PclkSourceId>(
250+
pub fn enable<I: AdcInstance>(
251251
self,
252252
adc: I::Instance,
253253
clk: crate::clock::v2::apb::ApbClk<I::ClockId>,
254-
pclk: &crate::clock::v2::pclk::Pclk<I::ClockId, PS>,
254+
pclk: crate::clock::v2::pclk::Pclk<I::ClockId, crate::clock::v2::pclk::DynPclkSourceId>,
255255
) -> Result<Adc<I>, BuilderError> {
256256
let settings = self.to_settings()?;
257257
Adc::new(adc, settings, clk, pclk).map_err(|e| e.into())

hal/src/peripherals/adc/mod.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,13 @@ pub use builder::*;
4848
#[hal_cfg(any("adc-d11", "adc-d21"))]
4949
use crate::pac::adc as adc0;
5050
#[hal_cfg("adc-d5x")]
51-
use crate::pac::adc0;
51+
use crate::{
52+
clock::v2::{
53+
apb::ApbClk,
54+
pclk::{DynPclkSourceId, Pclk},
55+
},
56+
pac::adc0,
57+
};
5258

5359
pub use adc0::refctrl::Refselselect as Reference;
5460

@@ -174,7 +180,8 @@ pub struct Adc<I: AdcInstance> {
174180
#[hal_cfg("adc-d5x")]
175181
pub struct Adc<I: AdcInstance> {
176182
adc: I::Instance,
177-
_apbclk: crate::clock::v2::apb::ApbClk<I::ClockId>,
183+
_apbclk: ApbClk<I::ClockId>,
184+
_pclk: Pclk<I::ClockId, DynPclkSourceId>,
178185
cfg: AdcSettings,
179186
discard: bool,
180187
}
@@ -203,11 +210,11 @@ impl<I: AdcInstance> Adc<I> {
203210
/// frequency for the ADC is restricted to 90Mhz for stable performance.
204211
#[hal_cfg("adc-d5x")]
205212
#[inline]
206-
pub(crate) fn new<PS: crate::clock::v2::pclk::PclkSourceId>(
213+
pub(crate) fn new(
207214
adc: I::Instance,
208215
settings: AdcSettings,
209-
clk: crate::clock::v2::apb::ApbClk<I::ClockId>,
210-
pclk: &crate::clock::v2::pclk::Pclk<I::ClockId, PS>,
216+
clk: ApbClk<I::ClockId>,
217+
pclk: Pclk<I::ClockId, DynPclkSourceId>,
211218
) -> Result<Self, Error> {
212219
// TODO: Ideally, the ADC struct would take ownership of the Pclk type here.
213220
// However, since clock::v2 is not implemented for all chips yet, the
@@ -226,6 +233,7 @@ impl<I: AdcInstance> Adc<I> {
226233
let mut new_adc = Self {
227234
adc,
228235
_apbclk: clk,
236+
_pclk: pclk,
229237
cfg: settings,
230238
discard: true,
231239
};
@@ -422,10 +430,17 @@ impl<I: AdcInstance> Adc<I> {
422430

423431
/// Return the underlying ADC PAC object and the enabled APB ADC clock.
424432
#[hal_cfg("adc-d5x")]
433+
#[allow(clippy::type_complexity)]
425434
#[inline]
426-
pub fn free(mut self) -> (I::Instance, crate::clock::v2::apb::ApbClk<I::ClockId>) {
435+
pub fn free(
436+
mut self,
437+
) -> (
438+
I::Instance,
439+
ApbClk<I::ClockId>,
440+
Pclk<I::ClockId, DynPclkSourceId>,
441+
) {
427442
self.software_reset();
428-
(self.adc, self._apbclk)
443+
(self.adc, self._apbclk, self._pclk)
429444
}
430445

431446
/// Reset the peripheral.

0 commit comments

Comments
 (0)