Dirbaio comments round 2

This commit is contained in:
Caleb Jamison 2023-05-09 17:45:24 -04:00
parent 6bea078487
commit 5cfe1a1fb4
2 changed files with 107 additions and 94 deletions

View File

@ -6,15 +6,22 @@ use crate::{pac, reset, Peripheral};
// TODO fix terrible use of global here // TODO fix terrible use of global here
static mut XIN_HZ: u32 = 0; 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,
};
#[non_exhaustive]
pub struct ClockConfig { pub struct ClockConfig {
rosc: Option<RoscConfig>, pub rosc: Option<RoscConfig>,
xosc: Option<XoscConfig>, pub xosc: Option<XoscConfig>,
ref_clk: RefClkConfig, pub ref_clk: RefClkConfig,
sys_clk: SysClkConfig, pub sys_clk: SysClkConfig,
peri_clk_src: Option<ClkPeriCtrlAuxsrc>, pub peri_clk_src: Option<ClkPeriCtrlAuxsrc>,
usb_clk: Option<UsbClkConfig>, pub usb_clk: Option<UsbClkConfig>,
adc_clk: Option<AdcClkConfig>, pub adc_clk: Option<AdcClkConfig>,
rtc_clk: Option<RtcClkConfig>, pub rtc_clk: Option<RtcClkConfig>,
} }
impl ClockConfig { impl ClockConfig {
@ -54,15 +61,18 @@ impl ClockConfig {
usb_clk: Some(UsbClkConfig { usb_clk: Some(UsbClkConfig {
src: ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB, src: ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB,
div: 1, div: 1,
phase: 0,
}), }),
adc_clk: Some(AdcClkConfig { adc_clk: Some(AdcClkConfig {
src: ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB, src: ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB,
div: 1, div: 1,
phase: 0,
}), }),
rtc_clk: Some(RtcClkConfig { rtc_clk: Some(RtcClkConfig {
src: ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB, src: ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB,
div_int: 1024, div_int: 1024,
div_frac: 0, div_frac: 0,
phase: 0,
}), }),
} }
} }
@ -89,27 +99,29 @@ impl ClockConfig {
adc_clk: Some(AdcClkConfig { adc_clk: Some(AdcClkConfig {
src: ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH, src: ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH,
div: 1, div: 1,
phase: 0,
}), }),
rtc_clk: Some(RtcClkConfig { rtc_clk: Some(RtcClkConfig {
src: ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH, src: ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH,
div_int: 1024, div_int: 1024,
div_frac: 0, div_frac: 0,
phase: 0,
}), }),
} }
} }
} }
pub struct RoscConfig { pub struct RoscConfig {
range: pac::rosc::vals::FreqRange, pub range: pac::rosc::vals::FreqRange,
drive_strength: [u8; 8], pub drive_strength: [u8; 8],
div: u16, pub div: u16,
} }
pub struct XoscConfig { pub struct XoscConfig {
hz: u32, pub hz: u32,
clock_type: ExternalClock, pub clock_type: ExternalClock,
sys_pll: Option<PllConfig>, pub sys_pll: Option<PllConfig>,
usb_pll: Option<PllConfig>, pub usb_pll: Option<PllConfig>,
} }
pub struct PllConfig { pub struct PllConfig {
@ -124,8 +136,8 @@ pub enum ExternalClock {
Clock, Clock,
} }
pub struct RefClkConfig { pub struct RefClkConfig {
src: RefClkSrc, pub src: RefClkSrc,
div: u8, pub div: u8,
} }
pub enum RefClkSrc { pub enum RefClkSrc {
@ -140,25 +152,28 @@ pub enum SysClkSrc {
} }
pub struct SysClkConfig { pub struct SysClkConfig {
src: SysClkSrc, pub src: SysClkSrc,
div_int: u32, pub div_int: u32,
div_frac: u8, pub div_frac: u8,
} }
pub struct UsbClkConfig { pub struct UsbClkConfig {
src: ClkUsbCtrlAuxsrc, pub src: ClkUsbCtrlAuxsrc,
div: u8, pub div: u8,
pub phase: u8,
} }
pub struct AdcClkConfig { pub struct AdcClkConfig {
src: ClkAdcCtrlAuxsrc, pub src: ClkAdcCtrlAuxsrc,
div: u8, pub div: u8,
pub phase: u8,
} }
pub struct RtcClkConfig { pub struct RtcClkConfig {
src: ClkRtcCtrlAuxsrc, pub src: ClkRtcCtrlAuxsrc,
div_int: u32, pub div_int: u32,
div_frac: u8, pub div_frac: u8,
pub phase: u8,
} }
/// safety: must be called exactly once at bootup /// safety: must be called exactly once at bootup
@ -289,6 +304,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
// CLK USB = PLL USB (48MHz) / 1 = 48MHz // CLK USB = PLL USB (48MHz) / 1 = 48MHz
c.clk_usb_div().write(|w| w.set_int(conf.div)); c.clk_usb_div().write(|w| w.set_int(conf.div));
c.clk_usb_ctrl().write(|w| { c.clk_usb_ctrl().write(|w| {
w.set_phase(conf.phase);
w.set_enable(true); w.set_enable(true);
w.set_auxsrc(conf.src); w.set_auxsrc(conf.src);
}); });
@ -300,6 +316,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
// CLK ADC = PLL USB (48MHZ) / 1 = 48MHz // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz
c.clk_adc_div().write(|w| w.set_int(conf.div)); c.clk_adc_div().write(|w| w.set_int(conf.div));
c.clk_adc_ctrl().write(|w| { c.clk_adc_ctrl().write(|w| {
w.set_phase(conf.phase);
w.set_enable(true); w.set_enable(true);
w.set_auxsrc(conf.src); w.set_auxsrc(conf.src);
}); });
@ -317,6 +334,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
w.set_frac(conf.div_frac); w.set_frac(conf.div_frac);
}); });
c.clk_rtc_ctrl().write(|w| { c.clk_rtc_ctrl().write(|w| {
w.set_phase(conf.phase);
w.set_enable(true); w.set_enable(true);
w.set_auxsrc(conf.src); w.set_auxsrc(conf.src);
}); });
@ -544,33 +562,6 @@ pub fn clk_rtc_freq() -> u32 {
base / int base / int
} }
pub fn clk_gpout_freq<T: GpoutPin>(gpout: &Gpout<T>) -> u32 {
let c = pac::CLOCKS;
let src = unsafe { c.clk_gpout_ctrl(gpout.gpout.gpout_number()).read().auxsrc() };
let base = match src {
ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(),
ClkGpoutCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(),
ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(),
ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq(),
ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(),
_ => unreachable!(),
};
let div = unsafe { c.clk_gpout_div(gpout.gpout.gpout_number()).read() };
let int = if div.int() == 0 { 65536 } else { div.int() };
// TODO handle fractional clock div
let _frac = div.frac();
base / int
}
unsafe fn start_xosc(crystal_hz: u32) { unsafe fn start_xosc(crystal_hz: u32) {
pac::XOSC pac::XOSC
.ctrl() .ctrl()
@ -641,20 +632,16 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) {
p.pwr().modify(|w| w.set_postdivpd(false)); p.pwr().modify(|w| w.set_postdivpd(false));
} }
pub trait GpinPin { pub trait GpinPin: crate::gpio::Pin {
fn gpin_number(&self) -> usize; fn number(&self) -> usize;
fn pin_number(&self) -> usize;
} }
macro_rules! impl_gpinpin { macro_rules! impl_gpinpin {
($name:ident, $pin_num:expr, $gpin_num:expr) => { ($name:ident, $pin_num:expr, $gpin_num:expr) => {
impl GpinPin for crate::peripherals::$name { impl GpinPin for crate::peripherals::$name {
fn gpin_number(&self) -> usize { fn number(&self) -> usize {
$gpin_num $gpin_num
} }
fn pin_number(&self) -> usize {
$pin_num
}
} }
}; };
} }
@ -663,53 +650,50 @@ impl_gpinpin!(PIN_20, 20, 0);
impl_gpinpin!(PIN_22, 22, 1); impl_gpinpin!(PIN_22, 22, 1);
pub struct Gpin<'d, T: GpinPin> { pub struct Gpin<'d, T: GpinPin> {
gpout: PeripheralRef<'d, T>, gpin: PeripheralRef<'d, T>,
} }
impl<'d, T: GpinPin> Gpin<'d, T> { impl<'d, T: GpinPin> Gpin<'d, T> {
pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { pub fn new(gpin: impl Peripheral<P = T> + 'd) -> Self {
into_ref!(gpout); into_ref!(gpin);
unsafe { unsafe {
let p = pac::IO_BANK0.gpio(gpout.pin_number()).ctrl(); gpin.io().ctrl().write(|w| w.set_funcsel(0x08));
p.write(|w| w.set_funcsel(0x08));
} }
Self { gpout } Self { gpin }
} }
} }
impl<'d, T: GpinPin> Drop for Gpin<'d, T> { impl<'d, T: GpinPin> Drop for Gpin<'d, T> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
let p = pac::IO_BANK0.gpio(self.gpout.pin_number()).ctrl(); self.gpin
p.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); .io()
.ctrl()
.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
} }
} }
} }
pub trait GpoutPin { pub trait GpoutPin: crate::gpio::Pin {
fn gpout_number(&self) -> usize; fn number(&self) -> usize;
fn pin_number(&self) -> usize;
} }
macro_rules! impl_gpoutpin { macro_rules! impl_gpoutpin {
($name:ident, $pin_num:expr, $gpout_num:expr) => { ($name:ident, $gpout_num:expr) => {
impl GpoutPin for crate::peripherals::$name { impl GpoutPin for crate::peripherals::$name {
fn gpout_number(&self) -> usize { fn number(&self) -> usize {
$gpout_num $gpout_num
} }
fn pin_number(&self) -> usize {
$pin_num
}
} }
}; };
} }
impl_gpoutpin!(PIN_21, 21, 0); impl_gpoutpin!(PIN_21, 0);
impl_gpoutpin!(PIN_23, 23, 1); impl_gpoutpin!(PIN_23, 1);
impl_gpoutpin!(PIN_24, 24, 2); impl_gpoutpin!(PIN_24, 2);
impl_gpoutpin!(PIN_25, 25, 3); impl_gpoutpin!(PIN_25, 3);
pub struct Gpout<'d, T: GpoutPin> { pub struct Gpout<'d, T: GpoutPin> {
gpout: PeripheralRef<'d, T>, gpout: PeripheralRef<'d, T>,
@ -720,8 +704,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
into_ref!(gpout); into_ref!(gpout);
unsafe { unsafe {
let p = pac::IO_BANK0.gpio(gpout.pin_number()).ctrl(); gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
p.write(|w| w.set_funcsel(0x08));
} }
Self { gpout } Self { gpout }
@ -730,7 +713,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
pub fn set_div(&self, int: u32, frac: u8) { pub fn set_div(&self, int: u32, frac: u8) {
unsafe { unsafe {
let c = pac::CLOCKS; let c = pac::CLOCKS;
c.clk_gpout_div(self.gpout.gpout_number()).write(|w| { c.clk_gpout_div(self.gpout.number()).write(|w| {
w.set_int(int); w.set_int(int);
w.set_frac(frac); w.set_frac(frac);
}); });
@ -740,7 +723,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
pub fn set_src(&self, src: ClkGpoutCtrlAuxsrc) { pub fn set_src(&self, src: ClkGpoutCtrlAuxsrc) {
unsafe { unsafe {
let c = pac::CLOCKS; let c = pac::CLOCKS;
c.clk_gpout_ctrl(self.gpout.gpout_number()).modify(|w| { c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
w.set_auxsrc(src); w.set_auxsrc(src);
}); });
} }
@ -749,7 +732,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
pub fn enable(&self) { pub fn enable(&self) {
unsafe { unsafe {
let c = pac::CLOCKS; let c = pac::CLOCKS;
c.clk_gpout_ctrl(self.gpout.gpout_number()).modify(|w| { c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
w.set_enable(true); w.set_enable(true);
}); });
} }
@ -758,18 +741,48 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
pub fn disable(&self) { pub fn disable(&self) {
unsafe { unsafe {
let c = pac::CLOCKS; let c = pac::CLOCKS;
c.clk_gpout_ctrl(self.gpout.gpout_number()).modify(|w| { c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
w.set_enable(false); w.set_enable(false);
}); });
} }
} }
pub fn get_freq(&self) -> u32 {
let c = pac::CLOCKS;
let src = unsafe { c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc() };
let base = match src {
ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(),
ClkGpoutCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(),
ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(),
ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq(),
ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(),
_ => unreachable!(),
};
let div = unsafe { c.clk_gpout_div(self.gpout.number()).read() };
let int = if div.int() == 0 { 65536 } else { div.int() };
// TODO handle fractional clock div
let _frac = div.frac();
base / int
}
} }
impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { impl<'d, T: GpoutPin> Drop for Gpout<'d, T> {
fn drop(&mut self) { fn drop(&mut self) {
self.disable();
unsafe { unsafe {
let p = pac::IO_BANK0.gpio(self.gpout.pin_number()).ctrl(); self.gpout
p.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); .io()
.ctrl()
.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
} }
} }
} }

View File

@ -4,7 +4,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_rp::{clocks, pac}; use embassy_rp::clocks;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -17,17 +17,17 @@ async fn main(_spawner: Spawner) {
gpout3.enable(); gpout3.enable();
loop { loop {
gpout3.set_src(pac::clocks::vals::ClkGpoutCtrlAuxsrc::CLK_SYS); gpout3.set_src(clocks::GpoutSrc::CLK_SYS);
info!( info!(
"Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}", "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}",
clocks::clk_gpout_freq(&gpout3) gpout3.get_freq()
); );
Timer::after(Duration::from_secs(2)).await; Timer::after(Duration::from_secs(2)).await;
gpout3.set_src(pac::clocks::vals::ClkGpoutCtrlAuxsrc::CLK_REF); gpout3.set_src(clocks::GpoutSrc::CLK_REF);
info!( info!(
"Pin 25 is now outputing CLK_REF/1000, should be toggling at {}", "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}",
clocks::clk_gpout_freq(&gpout3) gpout3.get_freq()
); );
Timer::after(Duration::from_secs(2)).await; Timer::after(Duration::from_secs(2)).await;
} }