From ef7f8fe9b7844364e1f59f048cce52f791434225 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sat, 1 May 2021 23:18:37 +0200 Subject: [PATCH] Initial commit on clocks --- rp2040-hal/src/clocks/macros.rs | 226 ++++++++++++++++++++++++++++++ rp2040-hal/src/clocks/mod.rs | 234 ++++++++++++++++++++++++++++++++ rp2040-hal/src/lib.rs | 1 + 3 files changed, 461 insertions(+) create mode 100644 rp2040-hal/src/clocks/macros.rs create mode 100644 rp2040-hal/src/clocks/mod.rs diff --git a/rp2040-hal/src/clocks/macros.rs b/rp2040-hal/src/clocks/macros.rs new file mode 100644 index 0000000..33c3128 --- /dev/null +++ b/rp2040-hal/src/clocks/macros.rs @@ -0,0 +1,226 @@ +#[macro_use] + +macro_rules! int_division { + ($name:ident, $div:ident, $u:ty) => { + + impl IntegerDivision for $name { + fn set_int_div(&mut self, div: usize) { + unsafe { self.shared_dev.get() }.$div.write(|w| unsafe { + w.int().bits(div as $u); + w + }); + } + } + }; +} + + +macro_rules! frac_division { + ($name:ident, $div:ident, $u:ty) => { + + impl FractionDivision for $name { + fn set_frac_div(&mut self, div: usize) { + unsafe { self.shared_dev.get() }.$div.write(|w| unsafe { + w.frac().bits(div as $u); + w + }); + } + } + }; +} + + +macro_rules! clock_generator { + ($name:ident, $ctrl:ident) => { + impl ClockGenerator for $name { + fn enable(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.enable().set_bit(); + w + }); + } + + fn disable(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.enable().clear_bit(); + w + }); + } + + fn kill(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.kill().set_bit(); + w + }); + } + } + }; +} + + +macro_rules! xosc_source { + ($name:ident, $ctrl:ident) => { + + impl XOSCClockSource for $name { + fn set_xosc_src(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.src().xosc_clksrc(); + w + }); + } + } + }; +} + + +macro_rules! rosc_source { + ($name:ident, $ctrl:ident) => { + impl ROSCClockSource for $name { + fn set_rosc_src(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.src().rosc_clksrc_ph(); + w + }); + } + } + }; +} + + +macro_rules! selfaux_source { + ($name:ident, $ctrl:ident, $self:ident) => { + impl SelfAuxClockSource for $name { + fn set_self_aux_src(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.src().$self(); + w + }); + } + } + }; +} + + +macro_rules! clockref_source { + ($name:ident, $ctrl:ident) => { + impl ClockREFClockSource for $name { + fn set_clkref_src(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.src().clk_ref(); + w + }); + } + } + }; +} + + +macro_rules! clocksys_auxsource { + ($name:ident, $ctrl:ident) => { + impl ClockSYSClockAuxSource for $name { + fn set_clksys_auxsrc(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.auxsrc().clk_sys(); + w + }); + } + } + }; +} + +macro_rules! xosc_auxsource { + ($name:ident, $ctrl:ident) => { + impl XOSCClockAuxSource for $name { + fn set_xosc_auxsrc(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.auxsrc().xosc_clksrc(); + w + }); + } + } + }; +} + + +macro_rules! rosc_auxsource { + ($name:ident, $ctrl:ident) => { + impl ROSCClockAuxSource for $name { + fn set_rosc_auxsrc(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.auxsrc().rosc_clksrc(); + w + }); + } + } + }; +} + + +macro_rules! rosc_ph_auxsource { + ($name:ident, $ctrl:ident) => { + impl ROSCPHClockAuxSource for $name { + fn set_rosc_ph_auxsrc(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.auxsrc().rosc_clksrc_ph(); + w + }); + } + } + }; +} + + +macro_rules! gpin0_auxsource { + ($name:ident, $ctrl:ident) => { + impl Gpin0ClockAuxSource for $name { + fn set_gpin0_auxsrc(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.auxsrc().clksrc_gpin0(); + w + }); + } + } + }; +} + + +macro_rules! gpin1_auxsource { + ($name:ident, $ctrl:ident) => { + impl Gpin1ClockAuxSource for $name { + fn set_gpin1_auxsrc(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.auxsrc().clksrc_gpin1(); + w + }); + } + } + }; +} + + +macro_rules! pll_usb_auxsource { + ($name:ident, $ctrl:ident) => { + impl PLLUSBClockAuxSource for $name { + fn set_pll_usb_auxsrc(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.auxsrc().clksrc_pll_usb(); + w + }); + } + } + }; +} + + +macro_rules! pll_sys_auxsource { + ($name:ident, $ctrl:ident) => { + impl PLLSYSClockAuxSource for $name { + fn set_pll_sys_auxsrc(&mut self) { + unsafe { self.shared_dev.get() }.$ctrl.write(|w| { + w.auxsrc().clksrc_pll_sys(); + w + }); + } + } + }; +} diff --git a/rp2040-hal/src/clocks/mod.rs b/rp2040-hal/src/clocks/mod.rs new file mode 100644 index 0000000..241d327 --- /dev/null +++ b/rp2040-hal/src/clocks/mod.rs @@ -0,0 +1,234 @@ +//! Clocks (CLOCKS) +// See [Chapter 2 Section 15](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details + +use crate::pac::*; + +#[macro_use] +mod macros; + +#[derive(Copy, Clone)] +/// Provides refs to the CLOCKS block. +pub struct ShareableClocks { + _internal: () +} + +impl ShareableClocks { + fn new(_clocks: &mut CLOCKS) -> Self { + ShareableClocks { + _internal: () + } + } + + unsafe fn get(&self) -> &clocks::RegisterBlock { + &*CLOCKS::ptr() + } +} + +/// Abstraction layer providing Clock Management. +pub struct ClocksManager { + clocks:CLOCKS, + shared_clocks: ShareableClocks +} +impl ClocksManager { + + /// Exchanges CLOCKS block against Self. + pub fn new(mut clocks_block: CLOCKS) -> Self { + let shared_clocks = ShareableClocks::new(&mut clocks_block); + ClocksManager { + clocks: clocks_block, + shared_clocks: shared_clocks + } + } + + /// Releases the CLOCKS block + pub fn free(self) -> CLOCKS { + self.clocks + } + + /// Getter for the Reference Clock. + pub fn ref_clock(&self) -> ReferenceClock { + ReferenceClock { + shared_dev: self.shared_clocks.clone(), + } + } + + /// Getter for the System Clock + pub fn sys_clock(&self) -> SystemClock { + SystemClock { + shared_dev: self.shared_clocks.clone() + } + } + + /// Getter for the PeripheralClock + pub fn peripheral_clock(&self) -> PeripheralClock { + PeripheralClock { + shared_dev: self.shared_clocks.clone() + } + } +} + + +/// For clocks with an integer divider. +pub trait IntegerDivision { + + /// Set integer divider value. + fn set_int_div(&mut self, div: usize); +} + +/// For clocks with a fraction divider. +pub trait FractionDivision { + /// Set fraction divider value. + fn set_frac_div(&mut self, div: usize); +} + +/// For clocks that can have XOSC as source. +pub trait XOSCClockSource { + /// Set XOSC as a source. + fn set_xosc_src(&mut self); +} +/// For clocks that can have ROSC as source. +pub trait ROSCClockSource { + + /// set ROSC as a source. + fn set_rosc_src(&mut self); +} +/// For clocks that can have ... itself (?) as a source (is that the "glitchless mux" ?) +pub trait SelfAuxClockSource { + + /// Set ... + fn set_self_aux_src(&mut self); +} +/// For clocks that can have the Reference Clock as source. +pub trait ClockREFClockSource { + + /// Set Reference Clock as + fn set_clkref_src(&mut self); +} +/// For clocks that can have the System Clock as an auxilliary source. +pub trait ClockSYSClockAuxSource { + + /// Set System Clock as source. + fn set_clksys_auxsrc(&mut self); +} +/// For clocks that can have XOSC as an auxilliary source. +pub trait XOSCClockAuxSource { + + /// Set XOSC as auxilliary source. + fn set_xosc_auxsrc(&mut self); +} +/// For clocks that can have ROSC as an auxilliary source. +pub trait ROSCClockAuxSource { + + /// Set ROSC as auxilliary source. + fn set_rosc_auxsrc(&mut self); +} +/// For clocks that can have ROSC_PH as an auxilliary source. +pub trait ROSCPHClockAuxSource { + + /// Set ROSC_PH as auxilliary source. + fn set_rosc_ph_auxsrc(&mut self); +} +/// For clocks that can have PLL_USB as an auxilliary source. +pub trait PLLUSBClockAuxSource { + + /// Set PLL_USB as auxilliary source. + fn set_pll_usb_auxsrc(&mut self); +} +/// For clocks that can have PLL_SYS as an auxilliary source. +pub trait PLLSYSClockAuxSource { + + /// Set PLL_SYS as auxilliary source. + fn set_pll_sys_auxsrc(&mut self); +} +/// For clocks that can have gpin0 as an auxilliary source. +pub trait Gpin0ClockAuxSource { + + /// Set clock to be received from gpin0 (auxilliary) + fn set_gpin0_auxsrc(&mut self); +} +/// For clocks that can have gpin1 as an auxilliary source. +pub trait Gpin1ClockAuxSource { + + /// Set clock to be received from gpin1 + fn set_gpin1_auxsrc(&mut self); +} + + +/// For clocks having a generator. +pub trait ClockGenerator { + + /// Enables the clock. + fn enable(&mut self); + + /// Disables the clock. + fn disable(&mut self); + + /// Kills the clock. + fn kill(&mut self); +} + +/// Reference Clock +pub struct ReferenceClock { + shared_dev: ShareableClocks, +} +xosc_source!(ReferenceClock, clk_ref_ctrl); +rosc_source!(ReferenceClock, clk_ref_ctrl); +selfaux_source!(ReferenceClock, clk_ref_ctrl, clksrc_clk_ref_aux); +gpin0_auxsource!(ReferenceClock, clk_ref_ctrl); +gpin1_auxsource!(ReferenceClock, clk_ref_ctrl); +pll_usb_auxsource!(ReferenceClock, clk_ref_ctrl); +int_division!(ReferenceClock, clk_ref_div, u8); + +/// System Clock +pub struct SystemClock { + shared_dev: ShareableClocks +} +impl SystemClock { + + /// WIP - Helper function to reset source (blocking) + pub fn reset_source_await(&self) { + + let shared_dev = unsafe { self.shared_dev.get() }; + + shared_dev.clk_sys_ctrl.write(|w| { + w.src().clear_bit(); + w + }); + + self.await_select(0x1); + } + + /// WIP - Helper function to select new source (blocking) + pub fn await_select(&self, clock:u8) { + let shared_dev = unsafe { self.shared_dev.get() }; + + while shared_dev.clk_sys_selected.read().bits() != clock as u32 { + cortex_m::asm::nop(); + } + } +} + +selfaux_source!(SystemClock, clk_sys_ctrl, clksrc_clk_sys_aux); +clockref_source!(SystemClock, clk_sys_ctrl); +gpin0_auxsource!(SystemClock, clk_sys_ctrl); +gpin1_auxsource!(SystemClock, clk_sys_ctrl); +pll_usb_auxsource!(SystemClock, clk_sys_ctrl); +pll_sys_auxsource!(SystemClock, clk_sys_ctrl); +xosc_auxsource!(SystemClock, clk_sys_ctrl); +rosc_auxsource!(SystemClock, clk_sys_ctrl); +int_division!(SystemClock, clk_sys_div, u32); +frac_division!(SystemClock, clk_sys_div, u8); + + +/// Peripheral Clock +pub struct PeripheralClock { + shared_dev: ShareableClocks +} +gpin0_auxsource!(PeripheralClock, clk_peri_ctrl); +gpin1_auxsource!(PeripheralClock, clk_peri_ctrl); +pll_usb_auxsource!(PeripheralClock, clk_peri_ctrl); +pll_sys_auxsource!(PeripheralClock, clk_peri_ctrl); +xosc_auxsource!(PeripheralClock, clk_peri_ctrl); +rosc_ph_auxsource!(PeripheralClock, clk_peri_ctrl); +clocksys_auxsource!(PeripheralClock, clk_peri_ctrl); +clock_generator!(PeripheralClock, clk_peri_ctrl); diff --git a/rp2040-hal/src/lib.rs b/rp2040-hal/src/lib.rs index c0dbc5f..24b0fbe 100644 --- a/rp2040-hal/src/lib.rs +++ b/rp2040-hal/src/lib.rs @@ -14,6 +14,7 @@ extern crate nb; pub extern crate rp2040_pac as pac; pub mod adc; +pub mod clocks; pub mod gpio; pub mod i2c; pub mod pll;