mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2025-01-23 01:36:35 +11:00
Initial commit on clocks
This commit is contained in:
parent
c4cd2ffe52
commit
ef7f8fe9b7
3 changed files with 461 additions and 0 deletions
226
rp2040-hal/src/clocks/macros.rs
Normal file
226
rp2040-hal/src/clocks/macros.rs
Normal file
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
234
rp2040-hal/src/clocks/mod.rs
Normal file
234
rp2040-hal/src/clocks/mod.rs
Normal file
|
@ -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);
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue