Address Dirbaio comments

Gpout still incomplete.
This commit is contained in:
Caleb Jamison 2023-05-08 19:13:50 -04:00
parent 59132514cf
commit 14eecf2fc4

View File

@ -6,32 +6,25 @@ use crate::{pac, reset};
static mut XIN_HZ: u32 = 0; static mut XIN_HZ: u32 = 0;
pub struct ClockConfig { pub struct ClockConfig {
rosc_config: Option<RoscConfig>, rosc: Option<RoscConfig>,
xosc_config: Option<XoscConfig>, xosc: Option<XoscConfig>,
ref_clk_config: (RefClkSrc, u8), ref_clk: RefClkConfig,
sys_clk_config: (SysClkSrc, u32), sys_clk: SysClkConfig,
peri_clk_src: Option<ClkPeriCtrlAuxsrc>, peri_clk_src: Option<ClkPeriCtrlAuxsrc>,
usb_clk_config: Option<(ClkUsbCtrlAuxsrc, u8)>, usb_clk: Option<UsbClkConfig>,
adc_clk_config: Option<(ClkAdcCtrlAuxsrc, u8)>, adc_clk: Option<AdcClkConfig>,
rtc_clk_config: Option<(ClkRtcCtrlAuxsrc, u32)>, rtc_clk: Option<RtcClkConfig>,
} }
impl ClockConfig { impl ClockConfig {
pub fn crystal(crystal_hz: u32) -> Self { pub fn crystal(crystal_hz: u32) -> Self {
Self { Self {
rosc_config: Some(RoscConfig { rosc: Some(RoscConfig {
range: pac::rosc::vals::FreqRange::MEDIUM, range: pac::rosc::vals::FreqRange::MEDIUM,
drive_strength_0: 0, drive_strength: [0; 8],
drive_strength_1: 0,
drive_strength_2: 0,
drive_strength_3: 0,
drive_strength_4: 0,
drive_strength_5: 0,
drive_strength_6: 0,
drive_strength_7: 0,
div: 16, div: 16,
}), }),
xosc_config: Some(XoscConfig { xosc: Some(XoscConfig {
hz: crystal_hz, hz: crystal_hz,
clock_type: ExternalClock::Crystal, clock_type: ExternalClock::Crystal,
sys_pll: Some(PllConfig { sys_pll: Some(PllConfig {
@ -47,42 +40,68 @@ impl ClockConfig {
post_div2: 2, post_div2: 2,
}), }),
}), }),
ref_clk_config: (RefClkSrc::Xosc, 1), ref_clk: RefClkConfig {
sys_clk_config: (SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS), 1), src: RefClkSrc::Xosc,
div: 1,
},
sys_clk: SysClkConfig {
src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS),
div_int: 1,
div_frac: 0,
},
peri_clk_src: Some(ClkPeriCtrlAuxsrc::CLK_SYS), peri_clk_src: Some(ClkPeriCtrlAuxsrc::CLK_SYS),
usb_clk_config: Some((ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB, 1)), usb_clk: Some(UsbClkConfig {
adc_clk_config: Some((ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB, 1)), src: ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB,
rtc_clk_config: Some((ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB, 1024)), div: 1,
}),
adc_clk: Some(AdcClkConfig {
src: ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB,
div: 1,
}),
rtc_clk: Some(RtcClkConfig {
src: ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB,
div_int: 1024,
div_frac: 0,
}),
} }
} }
pub fn rosc() -> Self { pub fn rosc() -> Self {
Self { Self {
rosc_config: Some(RoscConfig { rosc: Some(RoscConfig {
range: pac::rosc::vals::FreqRange::HIGH, range: pac::rosc::vals::FreqRange::HIGH,
drive_strength_0: 0, drive_strength: [0; 8],
drive_strength_1: 0,
drive_strength_2: 0,
drive_strength_3: 0,
drive_strength_4: 0,
drive_strength_5: 0,
drive_strength_6: 0,
drive_strength_7: 0,
div: 1, div: 1,
}), }),
xosc_config: None, xosc: None,
ref_clk_config: (RefClkSrc::Rosc, 4), ref_clk: RefClkConfig {
sys_clk_config: (SysClkSrc::Aux(ClkSysCtrlAuxsrc::ROSC_CLKSRC), 1), src: RefClkSrc::Rosc,
div: 1,
},
sys_clk: SysClkConfig {
src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::ROSC_CLKSRC),
div_int: 1,
div_frac: 0,
},
peri_clk_src: Some(ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH), peri_clk_src: Some(ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH),
usb_clk_config: None, usb_clk: None,
adc_clk_config: Some((ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH, 1)), adc_clk: Some(AdcClkConfig {
rtc_clk_config: Some((ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH, 1024)), src: ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH,
div: 1,
}),
rtc_clk: Some(RtcClkConfig {
src: ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH,
div_int: 1024,
div_frac: 0,
}),
} }
} }
} }
pub enum ExternalClock {
Crystal, pub struct RoscConfig {
Clock, range: pac::rosc::vals::FreqRange,
drive_strength: [u8; 8],
div: u16,
} }
pub struct XoscConfig { pub struct XoscConfig {
@ -92,19 +111,6 @@ pub struct XoscConfig {
usb_pll: Option<PllConfig>, usb_pll: Option<PllConfig>,
} }
pub struct RoscConfig {
range: pac::rosc::vals::FreqRange,
drive_strength_0: u8,
drive_strength_1: u8,
drive_strength_2: u8,
drive_strength_3: u8,
drive_strength_4: u8,
drive_strength_5: u8,
drive_strength_6: u8,
drive_strength_7: u8,
div: u16,
}
pub struct PllConfig { pub struct PllConfig {
pub refdiv: u32, pub refdiv: u32,
pub vco_freq: u32, pub vco_freq: u32,
@ -112,9 +118,13 @@ pub struct PllConfig {
pub post_div2: u8, pub post_div2: u8,
} }
pub enum ExternalClock {
Crystal,
Clock,
}
pub struct RefClkConfig { pub struct RefClkConfig {
pub src: RefClkSrc, src: RefClkSrc,
pub div: u8, div: u8,
} }
pub enum RefClkSrc { pub enum RefClkSrc {
@ -123,16 +133,33 @@ pub enum RefClkSrc {
Aux(ClkRefCtrlAuxsrc), Aux(ClkRefCtrlAuxsrc),
} }
pub struct SysClkConfig {
pub src: SysClkSrc,
pub div: u32,
}
pub enum SysClkSrc { pub enum SysClkSrc {
Ref, Ref,
Aux(ClkSysCtrlAuxsrc), Aux(ClkSysCtrlAuxsrc),
} }
pub struct SysClkConfig {
src: SysClkSrc,
div_int: u32,
div_frac: u8,
}
pub struct UsbClkConfig {
src: ClkUsbCtrlAuxsrc,
div: u8,
}
pub struct AdcClkConfig {
src: ClkAdcCtrlAuxsrc,
div: u8,
}
pub struct RtcClkConfig {
src: ClkRtcCtrlAuxsrc,
div_int: u32,
div_frac: u8,
}
/// safety: must be called exactly once at bootup /// safety: must be called exactly once at bootup
pub(crate) unsafe fn init(config: ClockConfig) { pub(crate) unsafe fn init(config: ClockConfig) {
// Reset everything except: // Reset everything except:
@ -160,11 +187,11 @@ pub(crate) unsafe fn init(config: ClockConfig) {
c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH)); c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH));
while c.clk_ref_selected().read() != 1 {} while c.clk_ref_selected().read() != 1 {}
if let Some(config) = config.rosc_config { if let Some(config) = config.rosc {
configure_rosc(config); configure_rosc(config);
} }
if let Some(config) = config.xosc_config { if let Some(config) = config.xosc {
XIN_HZ = config.hz; XIN_HZ = config.hz;
pac::WATCHDOG.tick().write(|w| { pac::WATCHDOG.tick().write(|w| {
@ -188,21 +215,18 @@ pub(crate) unsafe fn init(config: ClockConfig) {
} }
} }
let (src, div) = config.ref_clk_config; match config.ref_clk.src {
match src {
RefClkSrc::Xosc => { RefClkSrc::Xosc => {
c.clk_ref_ctrl().write(|w| { c.clk_ref_ctrl().write(|w| {
w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC); w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC);
}); });
while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::XOSC_CLKSRC.0 {} while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::XOSC_CLKSRC.0 {}
c.clk_ref_div().write(|w| w.set_int(div));
} }
RefClkSrc::Rosc => { RefClkSrc::Rosc => {
c.clk_ref_ctrl().write(|w| { c.clk_ref_ctrl().write(|w| {
w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH); w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH);
}); });
while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::ROSC_CLKSRC_PH.0 {} while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::ROSC_CLKSRC_PH.0 {}
c.clk_ref_div().write(|w| w.set_int(div));
} }
RefClkSrc::Aux(src) => { RefClkSrc::Aux(src) => {
c.clk_ref_ctrl().write(|w| { c.clk_ref_ctrl().write(|w| {
@ -210,23 +234,23 @@ pub(crate) unsafe fn init(config: ClockConfig) {
w.set_src(ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX); w.set_src(ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX);
}); });
while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX.0 {} while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX.0 {}
c.clk_ref_div().write(|w| w.set_int(div));
} }
} }
c.clk_ref_div().write(|w| {
w.set_int(config.ref_clk.div);
});
pac::WATCHDOG.tick().write(|w| { pac::WATCHDOG.tick().write(|w| {
w.set_cycles((clk_ref_freq() / 1_000_000) as u16); w.set_cycles((clk_ref_freq() / 1_000_000) as u16);
w.set_enable(true); w.set_enable(true);
}); });
let (src, div) = config.sys_clk_config; match config.sys_clk.src {
match src {
SysClkSrc::Ref => { SysClkSrc::Ref => {
c.clk_sys_ctrl().write(|w| { c.clk_sys_ctrl().write(|w| {
w.set_src(ClkSysCtrlSrc::CLK_REF); w.set_src(ClkSysCtrlSrc::CLK_REF);
}); });
while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {}
c.clk_sys_div().write(|w| w.set_int(div));
} }
SysClkSrc::Aux(src) => { SysClkSrc::Aux(src) => {
c.clk_sys_ctrl().write(|w| { c.clk_sys_ctrl().write(|w| {
@ -234,7 +258,6 @@ pub(crate) unsafe fn init(config: ClockConfig) {
}); });
while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {}
c.clk_sys_div().write(|w| w.set_int(div));
c.clk_sys_ctrl().write(|w| { c.clk_sys_ctrl().write(|w| {
w.set_auxsrc(src); w.set_auxsrc(src);
w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX);
@ -242,6 +265,10 @@ pub(crate) unsafe fn init(config: ClockConfig) {
while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX.0 {} while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX.0 {}
} }
} }
c.clk_sys_div().write(|w| {
w.set_int(config.sys_clk.div_int);
w.set_frac(config.sys_clk.div_frac);
});
let mut peris = reset::ALL_PERIPHERALS; let mut peris = reset::ALL_PERIPHERALS;
@ -257,37 +284,40 @@ pub(crate) unsafe fn init(config: ClockConfig) {
peris.set_uart1(false); peris.set_uart1(false);
} }
if let Some((src, div)) = config.usb_clk_config { if let Some(conf) = config.usb_clk {
// CLK USB = PLL USB (48MHz) / 1 = 48MHz // CLK USB = PLL USB (48MHz) / 1 = 48MHz
c.clk_usb_div().write(|w| w.set_int(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_enable(true); w.set_enable(true);
w.set_auxsrc(src); w.set_auxsrc(conf.src);
}); });
} else { } else {
peris.set_usbctrl(false); peris.set_usbctrl(false);
} }
if let Some((src, div)) = config.adc_clk_config { if let Some(conf) = config.adc_clk {
// CLK ADC = PLL USB (48MHZ) / 1 = 48MHz // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz
c.clk_adc_div().write(|w| w.set_int(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_enable(true); w.set_enable(true);
w.set_auxsrc(src); w.set_auxsrc(conf.src);
}); });
} else { } else {
peris.set_adc(false); peris.set_adc(false);
} }
if let Some((src, div)) = config.rtc_clk_config { if let Some(conf) = config.rtc_clk {
// CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz
c.clk_rtc_ctrl().modify(|w| { c.clk_rtc_ctrl().modify(|w| {
w.set_enable(false); w.set_enable(false);
}); });
c.clk_rtc_div().write(|w| w.set_int(div)); c.clk_rtc_div().write(|w| {
w.set_int(conf.div_int);
w.set_frac(conf.div_frac);
});
c.clk_rtc_ctrl().write(|w| { c.clk_rtc_ctrl().write(|w| {
w.set_enable(true); w.set_enable(true);
w.set_auxsrc(src); w.set_auxsrc(conf.src);
}); });
} else { } else {
peris.set_rtc(false); peris.set_rtc(false);
@ -302,18 +332,18 @@ unsafe fn configure_rosc(config: RoscConfig) {
p.freqa().write(|w| { p.freqa().write(|w| {
w.set_passwd(pac::rosc::vals::Passwd::PASS); w.set_passwd(pac::rosc::vals::Passwd::PASS);
w.set_ds0(config.drive_strength_0); w.set_ds0(config.drive_strength[0]);
w.set_ds1(config.drive_strength_1); w.set_ds1(config.drive_strength[1]);
w.set_ds2(config.drive_strength_2); w.set_ds2(config.drive_strength[2]);
w.set_ds3(config.drive_strength_3); w.set_ds3(config.drive_strength[3]);
}); });
p.freqb().write(|w| { p.freqb().write(|w| {
w.set_passwd(pac::rosc::vals::Passwd::PASS); w.set_passwd(pac::rosc::vals::Passwd::PASS);
w.set_ds4(config.drive_strength_4); w.set_ds4(config.drive_strength[4]);
w.set_ds5(config.drive_strength_5); w.set_ds5(config.drive_strength[5]);
w.set_ds6(config.drive_strength_6); w.set_ds6(config.drive_strength[6]);
w.set_ds7(config.drive_strength_7); w.set_ds7(config.drive_strength[7]);
}); });
p.div().write(|w| { p.div().write(|w| {
@ -637,17 +667,31 @@ 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 struct Gpout0 { pub trait GpoutPin {}
_pin: crate::peripherals::PIN_21,
impl GpoutPin for crate::peripherals::PIN_21 {}
impl GpoutPin for crate::peripherals::PIN_23 {}
impl GpoutPin for crate::peripherals::PIN_24 {}
impl GpoutPin for crate::peripherals::PIN_25 {}
use embassy_hal_common::{into_ref, PeripheralRef};
use crate::Peripheral;
pub struct Gpout<'d, T: GpoutPin> {
_pin: PeripheralRef<'d, T>,
} }
impl Gpout0 { impl<'d, T: GpoutPin> Gpout<'d, T> {
pub fn new(pin: crate::peripherals::PIN_21) -> Self { pub fn new(_pin: impl Peripheral<P = T> + 'd) -> Self {
into_ref!(_pin);
unsafe { unsafe {
let p = pac::IO_BANK0.gpio(21).ctrl(); let p = pac::IO_BANK0.gpio(21).ctrl();
p.write(|w| w.set_funcsel(pac::io::vals::Gpio21ctrlFuncsel::CLOCKS_GPOUT_0.0)) p.write(|w| w.set_funcsel(pac::io::vals::Gpio21ctrlFuncsel::CLOCKS_GPOUT_0.0));
} }
Self { _pin: pin }
Self { _pin }
} }
pub fn set_div(&self, int: u32, frac: u8) { pub fn set_div(&self, int: u32, frac: u8) {
@ -677,6 +721,15 @@ impl Gpout0 {
}); });
} }
} }
pub fn disable(&self) {
unsafe {
let c = pac::CLOCKS;
c.clk_gpout0_ctrl().modify(|w| {
w.set_enable(true);
});
}
}
} }
/// Random number generator based on the ROSC RANDOMBIT register. /// Random number generator based on the ROSC RANDOMBIT register.