Skip to content
Open
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
2 changes: 1 addition & 1 deletion boards/atsame54_xpro/examples/mcan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ type Aux = mcan::bus::Aux<
clock::types::Can1,
hal::can::Dependencies<
clock::types::Can1,
clock::gclk::Gclk0Id,
clock::pclk::PclkSource<clock::gclk::Gclk0Id>,
bsp::Ata6561Rx,
bsp::Ata6561Tx,
bsp::pac::Can1,
Expand Down
6 changes: 3 additions & 3 deletions boards/examples/m4-adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ fn main() -> ! {
// Overruns if clock divider < 32 in debug mode
.with_clock_divider(Prescaler::Div32)
.with_vref(atsamd_hal::adc::Reference::Arefa)
.enable(peripherals.adc0, apb_adc0, &pclk_adc0)
.enable(peripherals.adc0, apb_adc0, pclk_adc0)
.unwrap();
let mut adc_pin = pins.a0.into_alternate();

loop {
let res = adc.read(&mut adc_pin);
let _res = adc.read(&mut adc_pin);
#[cfg(feature = "use_semihosting")]
let _ = cortex_m_semihosting::hprintln!("ADC value: {}", res);
let _ = cortex_m_semihosting::hprintln!("ADC value: {}", _res);
}
}
8 changes: 4 additions & 4 deletions boards/metro_m4/examples/async_adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,21 @@ async fn main(_s: embassy_executor::Spawner) -> ! {
let apb_adc0 = buses.apb.enable(tokens.apbs.adc0);
// ...and enable the ADC0 PCLK. Both of these are required for the
// ADC to run.
let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0);
let (pclk_adc0, _gclk0) = Pclk::enable_dyn(tokens.pclks.adc0, clocks.gclk0);

let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12))
.with_clock_cycles_per_sample(5)
.with_clock_divider(Prescaler::Div32)
.with_vref(atsamd_hal::adc::Reference::Arefa)
.enable(peripherals.adc0, apb_adc0, &pclk_adc0)
.enable(peripherals.adc0, apb_adc0, pclk_adc0)
.unwrap()
.into_future(Irqs);

let mut adc_pin = pins.a0.into_alternate();

loop {
let res = adc.read(&mut adc_pin).await;
let _res = adc.read(&mut adc_pin).await;
#[cfg(feature = "use_semihosting")]
cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap();
cortex_m_semihosting::hprintln!("ADC Result: {}", _res).unwrap();
}
}
27 changes: 27 additions & 0 deletions hal/src/clock/v2/gclk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ impl<G: GclkId> GclkToken<G> {
/// The variants of this enum identify one generic clock generator.
///
/// `DynGclkId` is the value-level equivalent of [`GclkId`].
#[derive(Clone, Copy, PartialEq, Eq)]
#[hal_macro_helper]
pub enum DynGclkId {
Gclk0,
Expand All @@ -484,6 +485,32 @@ pub enum DynGclkId {
Gclk11,
}

impl core::fmt::Debug for DynGclkId {
#[hal_macro_helper]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Gclk0 => write!(f, "Gclk0"),
Self::Gclk1 => write!(f, "Gclk1"),
Self::Gclk2 => write!(f, "Gclk2"),
Self::Gclk3 => write!(f, "Gclk3"),
Self::Gclk4 => write!(f, "Gclk4"),
Self::Gclk5 => write!(f, "Gclk5"),
#[hal_cfg("gclk6")]
Self::Gclk6 => write!(f, "Gclk6"),
#[hal_cfg("gclk7")]
Self::Gclk7 => write!(f, "Gclk7"),
#[hal_cfg("gclk8")]
Self::Gclk8 => write!(f, "Gclk8"),
#[hal_cfg("gclk9")]
Self::Gclk9 => write!(f, "Gclk9"),
#[hal_cfg("gclk10")]
Self::Gclk10 => write!(f, "Gclk10"),
#[hal_cfg("gclk11")]
Self::Gclk11 => write!(f, "Gclk11"),
}
}
}

//==============================================================================
// GclkId
//==============================================================================
Expand Down
148 changes: 136 additions & 12 deletions hal/src/clock/v2/pclk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,28 @@ impl From<DynPclkSourceId> for Genselect {
}
}

impl PclkSourceId for DynPclkSourceId {
fn source_id(&self) -> DynGclkId {
*self
}
}

impl Sealed for DynPclkSourceId {}

//==============================================================================
// PclkSourceId
//==============================================================================

pub struct PclkSource<G: GclkId> {
_src: PhantomData<G>,
}

impl<G: GclkId> GclkId for PclkSource<G> {
const DYN: DynGclkId = G::DYN;
const NUM: usize = G::NUM;
type Divider = G::Divider;
}

//==============================================================================
// PclkSourceId
//==============================================================================
Expand All @@ -566,9 +588,19 @@ impl From<DynPclkSourceId> for Genselect {
/// [`Gclk`]: super::gclk::Gclk
/// [type-level programming]: crate::typelevel
/// [type-level enums]: crate::typelevel#type-level-enums
pub trait PclkSourceId: GclkId {}
pub trait PclkSourceId: Sealed {
fn source_id(&self) -> DynGclkId;
}

impl<G: GclkId> PclkSourceId for G {}
// PclkSource implements PclkSourceId via its GclkId implementation
impl<G: GclkId> PclkSourceId for G {
#[inline]
fn source_id(&self) -> DynGclkId {
Self::DYN
}
}

impl<G: GclkId> Sealed for PclkSource<G> {}

//==============================================================================
// Pclk
Expand Down Expand Up @@ -606,24 +638,41 @@ where
I: PclkSourceId,
{
token: PclkToken<P>,
src: PhantomData<I>,
src: I,
freq: Hertz,
}

impl<P, I> Pclk<P, I>
/// [`Pclk`] with a dynamic source ID ([`DynPclkSourceId`]).
pub type DynPclk<P> = Pclk<P, DynPclkSourceId>;

impl<P, G> From<Pclk<P, PclkSource<G>>> for DynPclk<P>
where
P: PclkId,
I: PclkSourceId,
G: GclkId,
{
fn from(value: Pclk<P, PclkSource<G>>) -> Self {
Pclk {
token: value.token,
freq: value.freq,
src: G::DYN,
}
}
}

impl<P, G> Pclk<P, PclkSource<G>>
where
P: PclkId,
G: GclkId,
{
pub(super) fn new(token: PclkToken<P>, freq: Hertz) -> Self {
Self {
token,
src: PhantomData,
src: PclkSource { _src: PhantomData },
freq,
}
}

/// Create and enable a [`Pclk`]
/// Create and enable a [`Pclk`] with a type-checked source ID.
///
/// Creating a [`Pclk`] immediately enables the corresponding peripheral
/// channel clock. It also [`Increment`]s the [`Source`]'s [`Enabled`]
Expand All @@ -636,15 +685,15 @@ where
#[inline]
pub fn enable<S>(mut token: PclkToken<P>, gclk: S) -> (Self, S::Inc)
where
S: Source<Id = I> + Increment,
S: Source<Id = G> + Increment,
{
let freq = gclk.freq();
token.enable(I::DYN);
let pclk = Pclk::new(token, freq);
token.enable(G::DYN);
let pclk = Self::new(token, freq);
(pclk, gclk.inc())
}

/// Disable and destroy a [`Pclk`]
/// Disable and destroy a [`Pclk`].
///
/// Consume the [`Pclk`], release the [`PclkToken`], and [`Decrement`] the
/// [`EnabledGclk`]'s counter
Expand All @@ -654,12 +703,87 @@ where
#[inline]
pub fn disable<S>(mut self, gclk: S) -> (PclkToken<P>, S::Dec)
where
S: Source<Id = I> + Decrement,
S: Source<Id = G> + Decrement,
{
self.token.disable();
(self.token, gclk.dec())
}
}

impl<P> DynPclk<P>
where
P: PclkId,
{
pub(super) fn new<G: GclkId>(token: PclkToken<P>, freq: Hertz) -> Self {
Self {
token,
src: G::DYN,
freq,
}
}

/// Create and enable a [`Pclk`] with an underlying [`DynPclkSourceId`]
/// source ID type.
///
/// Some peripherals require a dynamic PCLK source ID type parameter; use
/// this method to create a [`Pclk`] where this type parameter is
/// type-erased.
///
/// Creating a [`Pclk`] immediately enables the corresponding peripheral
/// channel clock. It also [`Increment`]s the [`Source`]'s [`Enabled`]
/// counter.
///
/// Note that the [`Source`] will always be an [`EnabledGclk`].
///
/// [`Enabled`]: super::Enabled
/// [`EnabledGclk`]: super::gclk::EnabledGclk
#[inline]
pub fn enable_dyn<S, G: GclkId>(mut token: PclkToken<P>, gclk: S) -> (Self, S::Inc)
where
S: Source<Id = G> + Increment,
{
let freq = gclk.freq();
token.enable(G::DYN);
let pclk = Self::new::<G>(token, freq);
(pclk, gclk.inc())
}

/// Disable and destroy a [`Pclk`].
///
/// Consume the [`Pclk`], release the [`PclkToken`], and [`Decrement`] the
/// [`EnabledGclk`]'s counter.
///
/// # Panics
///
/// Panics if the [`Pclk`]'s underlying GCLK source ID does not match the ID
/// of the provided [`Source`].
///
/// [`Enabled`]: super::Enabled
/// [`EnabledGclk`]: super::gclk::EnabledGclk
#[inline]
pub fn disable<S, G: GclkId>(mut self, gclk: S) -> (PclkToken<P>, S::Dec)
where
S: Source<Id = G> + Decrement,
{
// Make sure that we can only decrement the source we are actually using
assert_eq!(
G::DYN,
self.src,
"Expected GCLK ID {:?}, found {:?}",
G::DYN,
self.src
);

self.token.disable();
(self.token, gclk.dec())
}
}

impl<P, I> Pclk<P, I>
where
P: PclkId,
I: PclkSourceId,
{
/// Return the [`Pclk`] frequency
#[inline]
pub fn freq(&self) -> Hertz {
Expand Down
9 changes: 6 additions & 3 deletions hal/src/clock/v2/reset_thumbv6m.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use atsamd_hal_macros::hal_macro_helper;

use typenum::U1;

use crate::pac::{Gclk, Pm, Sysctrl};
use crate::{
clock::v2::pclk::PclkSource,
pac::{Gclk, Pm, Sysctrl},
};

use super::*;

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

/// Type-level tokens for unused clocks at power-on reset
Expand Down Expand Up @@ -155,7 +158,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl
let osculp32k = Enabled::<_, U0>::new(osculp32k::OscUlp32k::new());
let (gclk2, osculp32k) = gclk::Gclk2::from_source(gclk::GclkToken::new(), osculp32k);
let gclk2 = Enabled::new(gclk2);
let wdt = pclk::Pclk::new(pclk::PclkToken::new(), gclk2.freq());
let wdt = pclk::Pclk::<_, PclkSource<_>>::new(pclk::PclkToken::new(), gclk2.freq());
let osculp = OscUlpClocks {
base,
osculp1k,
Expand Down
11 changes: 7 additions & 4 deletions hal/src/peripherals/adc/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,17 +244,20 @@ impl AdcBuilder {
Ok(adc_clk_freq / clocks_per_sample)
}

/// Turn the builder into an ADC
/// Turn the builder into an ADC.
///
/// This function will convert the provided
/// [`Pclk`](crate::clock::v2::pclk::Pclk) into a [`DynPclk`](crate::clock::v2::pclk::DynPclk).
#[hal_cfg("adc-d5x")]
#[inline]
pub fn enable<I: AdcInstance, PS: crate::clock::v2::pclk::PclkSourceId>(
pub fn enable<I: AdcInstance>(
self,
adc: I::Instance,
clk: crate::clock::v2::apb::ApbClk<I::ClockId>,
pclk: &crate::clock::v2::pclk::Pclk<I::ClockId, PS>,
pclk: impl Into<crate::clock::v2::pclk::DynPclk<I::ClockId>>,
) -> Result<Adc<I>, BuilderError> {
let settings = self.to_settings()?;
Adc::new(adc, settings, clk, pclk).map_err(|e| e.into())
Adc::new(adc, settings, clk, pclk.into()).map_err(|e| e.into())
}

#[hal_cfg(any("adc-d11", "adc-d21"))]
Expand Down
Loading