rp/clocks: don't expose unstable pac items

exposing pac items kind of undermines the unstable-pac feature. directly
exposing register structure is also pretty inconvenient since the clock
switching code takes care of the src/aux difference in behavior, so a
user needn't really be forced to write down decomposed register values.
This commit is contained in:
pennae 2023-05-16 18:13:15 +02:00
parent d97a771479
commit f97b591831
2 changed files with 148 additions and 70 deletions

View file

@ -6,11 +6,18 @@ use crate::{pac, reset, Peripheral};
// TODO fix terrible use of global here
static mut XIN_HZ: u32 = 0;
pub use rp_pac::clocks::vals::{
ClkAdcCtrlAuxsrc as AdcAuxsrc, ClkGpoutCtrlAuxsrc as GpoutSrc, ClkPeriCtrlAuxsrc as PeriClkAuxsrc,
ClkRefCtrlAuxsrc as RefAuxsrc, ClkRtcCtrlAuxsrc as RtcAuxsrc, ClkSysCtrlAuxsrc as SysAuxsrc,
ClkUsbCtrlAuxsrc as UsbAuxsrc,
};
#[repr(u8)]
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PeriClkSrc {
Sys = ClkPeriCtrlAuxsrc::CLK_SYS.0,
PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS.0,
PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB.0,
Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH.0,
Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC.0,
Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0.0,
Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1.0,
}
#[non_exhaustive]
pub struct ClockConfig {
@ -18,7 +25,7 @@ pub struct ClockConfig {
pub xosc: Option<XoscConfig>,
pub ref_clk: RefClkConfig,
pub sys_clk: SysClkConfig,
pub peri_clk_src: Option<ClkPeriCtrlAuxsrc>,
pub peri_clk_src: Option<PeriClkSrc>,
pub usb_clk: Option<UsbClkConfig>,
pub adc_clk: Option<AdcClkConfig>,
pub rtc_clk: Option<RtcClkConfig>,
@ -28,7 +35,7 @@ impl ClockConfig {
pub fn crystal(crystal_hz: u32) -> Self {
Self {
rosc: Some(RoscConfig {
range: pac::rosc::vals::FreqRange::MEDIUM,
range: RoscRange::Medium,
drive_strength: [0; 8],
div: 16,
}),
@ -52,23 +59,23 @@ impl ClockConfig {
div: 1,
},
sys_clk: SysClkConfig {
src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS),
src: SysClkSrc::PllSys,
div_int: 1,
div_frac: 0,
},
peri_clk_src: Some(ClkPeriCtrlAuxsrc::CLK_SYS),
peri_clk_src: Some(PeriClkSrc::Sys),
usb_clk: Some(UsbClkConfig {
src: ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB,
src: UsbClkSrc::PllUsb,
div: 1,
phase: 0,
}),
adc_clk: Some(AdcClkConfig {
src: ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB,
src: AdcClkSrc::PllUsb,
div: 1,
phase: 0,
}),
rtc_clk: Some(RtcClkConfig {
src: ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB,
src: RtcClkSrc::PllUsb,
div_int: 1024,
div_frac: 0,
phase: 0,
@ -79,7 +86,7 @@ impl ClockConfig {
pub fn rosc() -> Self {
Self {
rosc: Some(RoscConfig {
range: pac::rosc::vals::FreqRange::HIGH,
range: RoscRange::High,
drive_strength: [0; 8],
div: 1,
}),
@ -89,19 +96,19 @@ impl ClockConfig {
div: 1,
},
sys_clk: SysClkConfig {
src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::ROSC_CLKSRC),
src: SysClkSrc::Rosc,
div_int: 1,
div_frac: 0,
},
peri_clk_src: Some(ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH),
peri_clk_src: Some(PeriClkSrc::Rosc),
usb_clk: None,
adc_clk: Some(AdcClkConfig {
src: ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH,
src: AdcClkSrc::Rosc,
div: 1,
phase: 0,
}),
rtc_clk: Some(RtcClkConfig {
src: ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH,
src: RtcClkSrc::Rosc,
div_int: 1024,
div_frac: 0,
phase: 0,
@ -110,8 +117,18 @@ impl ClockConfig {
}
}
#[repr(u16)]
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RoscRange {
Low = pac::rosc::vals::FreqRange::LOW.0,
Medium = pac::rosc::vals::FreqRange::MEDIUM.0,
High = pac::rosc::vals::FreqRange::HIGH.0,
TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0,
}
pub struct RoscConfig {
pub range: pac::rosc::vals::FreqRange,
pub range: RoscRange,
pub drive_strength: [u8; 8],
pub div: u16,
}
@ -134,15 +151,30 @@ pub struct RefClkConfig {
pub div: u8,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RefClkSrc {
// main sources
Xosc,
Rosc,
Aux(ClkRefCtrlAuxsrc),
// aux sources
PllUsb,
Gpin0,
Gpin1,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SysClkSrc {
// main sources
Ref,
Aux(ClkSysCtrlAuxsrc),
// aux sources
PllSys,
PllUsb,
Rosc,
Xosc,
Gpin0,
Gpin1,
}
pub struct SysClkConfig {
@ -151,20 +183,56 @@ pub struct SysClkConfig {
pub div_frac: u8,
}
#[repr(u8)]
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum UsbClkSrc {
PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB.0,
PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS.0,
Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH.0,
Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC.0,
Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0.0,
Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1.0,
}
pub struct UsbClkConfig {
pub src: ClkUsbCtrlAuxsrc,
pub src: UsbClkSrc,
pub div: u8,
pub phase: u8,
}
#[repr(u8)]
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AdcClkSrc {
PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB.0,
PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS.0,
Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH.0,
Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC.0,
Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0.0,
Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1.0,
}
pub struct AdcClkConfig {
pub src: ClkAdcCtrlAuxsrc,
pub src: AdcClkSrc,
pub div: u8,
pub phase: u8,
}
#[repr(u8)]
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RtcClkSrc {
PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB.0,
PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS.0,
Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH.0,
Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC.0,
Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0.0,
Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1.0,
}
pub struct RtcClkConfig {
pub src: ClkRtcCtrlAuxsrc,
pub src: RtcClkSrc,
pub div_int: u32,
pub div_frac: u8,
pub phase: u8,
@ -229,27 +297,21 @@ pub(crate) unsafe fn init(config: ClockConfig) {
}
}
match config.ref_clk.src {
RefClkSrc::Xosc => {
c.clk_ref_ctrl().write(|w| {
w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC);
});
while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::XOSC_CLKSRC.0 {}
let (ref_src, ref_aux) = {
use {ClkRefCtrlAuxsrc as Aux, ClkRefCtrlSrc as Src};
match config.ref_clk.src {
RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB),
RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB),
RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB),
RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0),
RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1),
}
RefClkSrc::Rosc => {
c.clk_ref_ctrl().write(|w| {
w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH);
});
while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::ROSC_CLKSRC_PH.0 {}
}
RefClkSrc::Aux(src) => {
c.clk_ref_ctrl().write(|w| {
w.set_auxsrc(src);
w.set_src(ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX);
});
while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX.0 {}
}
}
};
c.clk_ref_ctrl().write(|w| {
w.set_src(ref_src);
w.set_auxsrc(ref_aux);
});
while c.clk_ref_selected().read() != 1 << ref_src.0 {}
c.clk_ref_div().write(|w| {
w.set_int(config.ref_clk.div);
});
@ -259,26 +321,27 @@ pub(crate) unsafe fn init(config: ClockConfig) {
w.set_enable(true);
});
match config.sys_clk.src {
SysClkSrc::Ref => {
c.clk_sys_ctrl().write(|w| {
w.set_src(ClkSysCtrlSrc::CLK_REF);
});
while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {}
}
SysClkSrc::Aux(src) => {
c.clk_sys_ctrl().write(|w| {
w.set_src(ClkSysCtrlSrc::CLK_REF);
});
while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {}
c.clk_sys_ctrl().write(|w| {
w.set_auxsrc(src);
w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX);
});
while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX.0 {}
let (sys_src, sys_aux) = {
use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src};
match config.sys_clk.src {
SysClkSrc::Ref => (Src::CLK_REF, Aux::CLKSRC_PLL_SYS),
SysClkSrc::PllSys => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_SYS),
SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB),
SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC),
SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC),
SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0),
SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1),
}
};
if sys_src != ClkSysCtrlSrc::CLK_REF {
c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {}
}
c.clk_sys_ctrl().write(|w| {
w.set_auxsrc(sys_aux);
w.set_src(sys_src);
});
while c.clk_sys_selected().read() != 1 << sys_src.0 {}
c.clk_sys_div().write(|w| {
w.set_int(config.sys_clk.div_int);
w.set_frac(config.sys_clk.div_frac);
@ -289,7 +352,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
if let Some(src) = config.peri_clk_src {
c.clk_peri_ctrl().write(|w| {
w.set_enable(true);
w.set_auxsrc(src);
w.set_auxsrc(ClkPeriCtrlAuxsrc(src as _));
});
} else {
peris.set_spi0(false);
@ -304,7 +367,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
c.clk_usb_ctrl().write(|w| {
w.set_phase(conf.phase);
w.set_enable(true);
w.set_auxsrc(conf.src);
w.set_auxsrc(ClkUsbCtrlAuxsrc(conf.src as _));
});
} else {
peris.set_usbctrl(false);
@ -316,7 +379,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
c.clk_adc_ctrl().write(|w| {
w.set_phase(conf.phase);
w.set_enable(true);
w.set_auxsrc(conf.src);
w.set_auxsrc(ClkAdcCtrlAuxsrc(conf.src as _));
});
} else {
peris.set_adc(false);
@ -334,7 +397,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
c.clk_rtc_ctrl().write(|w| {
w.set_phase(conf.phase);
w.set_enable(true);
w.set_auxsrc(conf.src);
w.set_auxsrc(ClkRtcCtrlAuxsrc(conf.src as _));
});
} else {
peris.set_rtc(false);
@ -369,7 +432,7 @@ unsafe fn configure_rosc(config: RoscConfig) {
p.ctrl().write(|w| {
w.set_enable(pac::rosc::vals::Enable::ENABLE);
w.set_freq_range(config.range);
w.set_freq_range(pac::rosc::vals::FreqRange(config.range as u16));
});
}
@ -671,6 +734,21 @@ impl_gpoutpin!(PIN_23, 1);
impl_gpoutpin!(PIN_24, 2);
impl_gpoutpin!(PIN_25, 3);
#[repr(u8)]
pub enum GpoutSrc {
PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS.0,
Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0.0,
Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1.0,
PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB.0,
Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC.0,
Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC.0,
Sys = ClkGpoutCtrlAuxsrc::CLK_SYS.0,
Usb = ClkGpoutCtrlAuxsrc::CLK_USB.0,
Adc = ClkGpoutCtrlAuxsrc::CLK_ADC.0,
Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC.0,
Ref = ClkGpoutCtrlAuxsrc::CLK_REF.0,
}
pub struct Gpout<'d, T: GpoutPin> {
gpout: PeripheralRef<'d, T>,
}
@ -696,11 +774,11 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
}
}
pub fn set_src(&self, src: ClkGpoutCtrlAuxsrc) {
pub fn set_src(&self, src: GpoutSrc) {
unsafe {
let c = pac::CLOCKS;
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
w.set_auxsrc(src);
w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _));
});
}
}

View file

@ -17,14 +17,14 @@ async fn main(_spawner: Spawner) {
gpout3.enable();
loop {
gpout3.set_src(clocks::GpoutSrc::CLK_SYS);
gpout3.set_src(clocks::GpoutSrc::Sys);
info!(
"Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}",
gpout3.get_freq()
);
Timer::after(Duration::from_secs(2)).await;
gpout3.set_src(clocks::GpoutSrc::CLK_REF);
gpout3.set_src(clocks::GpoutSrc::Ref);
info!(
"Pin 25 is now outputing CLK_REF/1000, should be toggling at {}",
gpout3.get_freq()