use core::{convert::Infallible, marker::PhantomData};
use fugit::{HertzU32, RateExtU32};
use crate::{
pac::{self, CLOCKS, PLL_SYS, PLL_USB, RESETS, XOSC},
pll::{
common_configs::{PLL_SYS_150MHZ, PLL_USB_48MHZ},
setup_pll_blocking, Error as PllError, Locked, PhaseLockedLoop,
},
typelevel::Sealed,
watchdog::Watchdog,
xosc::{setup_xosc_blocking, CrystalOscillator, Error as XoscError, Stable},
};
#[macro_use]
mod macros;
mod clock_sources;
use clock_sources::PllSys;
use self::clock_sources::{GPin0, GPin1, LpOsc, PllUsb, Rosc, Xosc};
bitfield::bitfield! {
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Default)]
pub struct ClockGate(u64);
pub sys_clock, set_sys_clock: 0;
pub sys_accessctrl, set_sys_accessctrl: 1;
pub adc_adc, set_adc_adc: 2;
pub sys_adc, set_sys_adc: 3;
pub sys_bootram, set_sys_bootram: 4;
pub sys_busctrl, set_sys_busctrl: 5;
pub sys_busfabric, set_sys_busfabric: 6;
pub sys_dma, set_sys_dma: 7;
pub sys_glitch_detector, set_sys_glitch_detector: 8;
pub hstx, set_hstx: 9;
pub sys_hstx, set_sys_hstx: 10;
pub sys_i2c0, set_sys_i2c0: 11;
pub sys_i2c1, set_sys_i2c1: 12;
pub sys_io, set_sys_io: 13;
pub sys_jtag, set_sys_jtag: 14;
pub ref_otp, set_ref_otp: 15;
pub sys_otp, set_sys_otp: 16;
pub sys_pads, set_sys_pads: 17;
pub sys_pio0, set_sys_pio0: 18;
pub sys_pio1, set_sys_pio1: 19;
pub sys_pio2, set_sys_pio2: 20;
pub sys_pll_sys, set_sys_pll_sys: 21;
pub sys_pll_usb, set_sys_pll_usb: 22;
pub ref_powman, set_ref_powman: 23;
pub sys_powman, set_sys_powman: 24;
pub sys_pwm, set_sys_pwm: 25;
pub sys_resets, set_sys_resets: 26;
pub sys_rom, set_sys_rom: 27;
pub sys_rosc, set_sys_rosc: 28;
pub sys_psm, set_sys_psm: 29;
pub sys_sha256, set_sys_sha256: 30;
pub sys_sio, set_sys_sio: 31;
pub peri_spi0, set_peri_spi0: 32;
pub sys_spi0, set_sys_spi0: 33;
pub peri_spi1, set_peri_spi1: 34;
pub sys_spi1, set_sys_spi1: 35;
pub sys_sram0, set_sys_sram0: 36;
pub sys_sram1, set_sys_sram1: 37;
pub sys_sram2, set_sys_sram2: 38;
pub sys_sram3, set_sys_sram3: 39;
pub sys_sram4, set_sys_sram4: 40;
pub sys_sram5, set_sys_sram5: 41;
pub sys_sram6, set_sys_sram6: 42;
pub sys_sram7, set_sys_sram7: 43;
pub sys_sram8, set_sys_sram8: 44;
pub sys_sram9, set_sys_sram9: 45;
pub sys_syscfg, set_sys_syscfg: 46;
pub sys_sysinfo, set_sys_sysinfo: 47;
pub sys_tbman, set_sys_tbman: 48;
pub ref_ticks, set_ref_ticks: 49;
pub sys_ticks, set_sys_ticks: 50;
pub sys_timer0, set_sys_timer0: 51;
pub sys_timer1, set_sys_timer1: 52;
pub sys_trng, set_sys_trng: 53;
pub peri_uart0, set_peri_uart0: 54;
pub sys_uart0, set_sys_uart0: 55;
pub peri_uart1, set_peri_uart1: 56;
pub sys_uart1, set_sys_uart1: 57;
pub sys_usbctrl, set_sys_usbctrl: 58;
pub usb, set_usb: 59;
pub sys_watchdog, set_sys_watchdog: 60;
pub sys_xip, set_sys_xip: 61;
pub sys_xosc, set_sys_xosc: 62;
}
impl core::fmt::Debug for ClockGate {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ClockGate")
.field("sys_clock", &self.sys_clock())
.field("sys_accessctrl", &self.sys_accessctrl())
.field("adc_adc", &self.adc_adc())
.field("sys_adc", &self.sys_adc())
.field("sys_bootram", &self.sys_bootram())
.field("sys_busctrl", &self.sys_busctrl())
.field("sys_busfabric", &self.sys_busfabric())
.field("sys_dma", &self.sys_dma())
.field("sys_glitch_detector", &self.sys_glitch_detector())
.field("hstx", &self.hstx())
.field("sys_hstx", &self.sys_hstx())
.field("sys_i2c0", &self.sys_i2c0())
.field("sys_i2c1", &self.sys_i2c1())
.field("sys_io", &self.sys_io())
.field("sys_jtag", &self.sys_jtag())
.field("ref_otp", &self.ref_otp())
.field("sys_otp", &self.sys_otp())
.field("sys_pads", &self.sys_pads())
.field("sys_pio0", &self.sys_pio0())
.field("sys_pio1", &self.sys_pio1())
.field("sys_pio2", &self.sys_pio2())
.field("sys_pll_sys", &self.sys_pll_sys())
.field("sys_pll_usb", &self.sys_pll_usb())
.field("ref_powman", &self.ref_powman())
.field("sys_powman", &self.sys_powman())
.field("sys_pwm", &self.sys_pwm())
.field("sys_resets", &self.sys_resets())
.field("sys_rom", &self.sys_rom())
.field("sys_rosc", &self.sys_rosc())
.field("sys_psm", &self.sys_psm())
.field("sys_sha256", &self.sys_sha256())
.field("sys_sio", &self.sys_sio())
.field("peri_spi0", &self.peri_spi0())
.field("sys_spi0", &self.sys_spi0())
.field("peri_spi1", &self.peri_spi1())
.field("sys_spi1", &self.sys_spi1())
.field("sys_sram0", &self.sys_sram0())
.field("sys_sram1", &self.sys_sram1())
.field("sys_sram2", &self.sys_sram2())
.field("sys_sram3", &self.sys_sram3())
.field("sys_sram4", &self.sys_sram4())
.field("sys_sram5", &self.sys_sram5())
.field("sys_sram6", &self.sys_sram6())
.field("sys_sram7", &self.sys_sram7())
.field("sys_sram8", &self.sys_sram8())
.field("sys_sram9", &self.sys_sram9())
.field("sys_syscfg", &self.sys_syscfg())
.field("sys_sysinfo", &self.sys_sysinfo())
.field("sys_tbman", &self.sys_tbman())
.field("ref_ticks", &self.ref_ticks())
.field("sys_ticks", &self.sys_ticks())
.field("sys_timer0", &self.sys_timer0())
.field("sys_timer1", &self.sys_timer1())
.field("sys_trng", &self.sys_trng())
.field("peri_uart0", &self.peri_uart0())
.field("sys_uart0", &self.sys_uart0())
.field("peri_uart1", &self.peri_uart1())
.field("sys_uart1", &self.sys_uart1())
.field("sys_usbctrl", &self.sys_usbctrl())
.field("usb", &self.usb())
.field("sys_watchdog", &self.sys_watchdog())
.field("sys_xip", &self.sys_xip())
.field("sys_xosc", &self.sys_xosc())
.finish()
}
}
#[derive(Copy, Clone)]
struct ShareableClocks {
_internal: (),
}
impl ShareableClocks {
fn new(_clocks: &mut CLOCKS) -> Self {
ShareableClocks { _internal: () }
}
unsafe fn get(&self) -> &pac::clocks::RegisterBlock {
&*CLOCKS::ptr()
}
}
#[non_exhaustive]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ClockError {
CantIncreaseFreq,
FrequencyTooHigh,
FrequencyTooLow,
}
pub trait Clock: Sealed + Sized {
type Variant;
fn freq(&self) -> HertzU32;
fn configure_clock<S: ValidSrc<Self>>(
&mut self,
src: &S,
freq: HertzU32,
) -> Result<(), ClockError>;
}
trait ClockDivision {
fn set_div(&mut self, div: u32);
fn get_div(&self) -> u32;
}
trait GlitchlessClock {
type Clock: Clock;
fn await_select(
&self,
clock_token: &ChangingClockToken<Self::Clock>,
) -> nb::Result<(), Infallible>;
}
pub struct ChangingClockToken<G: Clock> {
clock_nr: u8,
clock: PhantomData<G>,
}
pub trait StoppableClock: Sealed {
fn enable(&mut self);
fn disable(&mut self);
fn kill(&mut self);
}
pub trait ClockSource: Sealed {
fn get_freq(&self) -> HertzU32;
}
pub trait ValidSrc<C: Clock>: Sealed + ClockSource {
fn is_aux(&self) -> bool;
fn variant(&self) -> C::Variant;
}
clocks! {
struct GpioOutput0Clock {
init_freq: 0,
reg: clk_gpout0,
auxsrc: {
PllSys: CLKSRC_PLL_SYS,
GPin0: CLKSRC_GPIN0,
GPin1: CLKSRC_GPIN1,
PllUsb: CLKSRC_PLL_USB,
Rosc: ROSC_CLKSRC,
Xosc: XOSC_CLKSRC,
LpOsc: LPOSC_CLKSRC,
SystemClock: CLK_SYS,
UsbClock: CLK_USB,
AdcClock: CLK_ADC,
ReferenceClock: CLK_REF,
PeripheralClock: CLK_PERI,
HstxClock: CLK_HSTX
}
}
struct GpioOutput1Clock {
init_freq: 0,
reg: clk_gpout1,
auxsrc: {
PllSys: CLKSRC_PLL_SYS,
GPin0: CLKSRC_GPIN0,
GPin1: CLKSRC_GPIN1,
PllUsb: CLKSRC_PLL_USB,
Rosc: ROSC_CLKSRC,
Xosc: XOSC_CLKSRC,
LpOsc: LPOSC_CLKSRC,
SystemClock: CLK_SYS,
UsbClock: CLK_USB,
AdcClock: CLK_ADC,
ReferenceClock: CLK_REF,
PeripheralClock: CLK_PERI,
HstxClock: CLK_HSTX
}
}
struct GpioOutput2Clock {
init_freq: 0,
reg: clk_gpout2,
auxsrc: {
PllSys: CLKSRC_PLL_SYS,
GPin0: CLKSRC_GPIN0,
GPin1: CLKSRC_GPIN1,
PllUsb: CLKSRC_PLL_USB,
Rosc: ROSC_CLKSRC_PH,
Xosc: XOSC_CLKSRC,
LpOsc: LPOSC_CLKSRC,
SystemClock: CLK_SYS,
UsbClock: CLK_USB,
AdcClock: CLK_ADC,
ReferenceClock: CLK_REF,
PeripheralClock: CLK_PERI,
HstxClock: CLK_HSTX
}
}
struct GpioOutput3Clock {
init_freq: 0,
reg: clk_gpout3,
auxsrc: {
PllSys: CLKSRC_PLL_SYS,
GPin0: CLKSRC_GPIN0,
GPin1: CLKSRC_GPIN1,
PllUsb: CLKSRC_PLL_USB,
Rosc: ROSC_CLKSRC_PH,
Xosc: XOSC_CLKSRC,
LpOsc: LPOSC_CLKSRC,
SystemClock: CLK_SYS,
UsbClock: CLK_USB,
AdcClock: CLK_ADC,
ReferenceClock: CLK_REF,
PeripheralClock: CLK_PERI,
HstxClock: CLK_HSTX
}
}
struct ReferenceClock {
init_freq: 12_000_000,
reg: clk_ref,
src: {
Rosc: ROSC_CLKSRC_PH,
Xosc: XOSC_CLKSRC,
LpOsc: LPOSC_CLKSRC
},
auxsrc: {
PllUsb:CLKSRC_PLL_USB,
GPin0:CLKSRC_GPIN0,
GPin1:CLKSRC_GPIN1
}
}
struct SystemClock {
init_freq: 12_000_000, reg: clk_sys,
src: {
ReferenceClock: CLK_REF,
SystemClock: CLKSRC_CLK_SYS_AUX
},
auxsrc: {
PllSys: CLKSRC_PLL_SYS,
PllUsb: CLKSRC_PLL_USB,
Rosc: ROSC_CLKSRC,
Xosc: XOSC_CLKSRC,
GPin0: CLKSRC_GPIN0,
GPin1: CLKSRC_GPIN1
}
}
struct PeripheralClock {
init_freq: 12_000_000, reg: clk_peri,
auxsrc: {
SystemClock: CLK_SYS,
PllSys: CLKSRC_PLL_SYS,
PllUsb:CLKSRC_PLL_USB,
Rosc: ROSC_CLKSRC_PH,
Xosc: XOSC_CLKSRC,
GPin0: CLKSRC_GPIN0,
GPin1: CLKSRC_GPIN1
},
div: false
}
struct HstxClock {
init_freq: 0,
reg: clk_hstx,
auxsrc: {
SystemClock: CLK_SYS,
PllUsb: CLKSRC_PLL_USB,
PllSys: CLKSRC_PLL_SYS,
GPin0: CLKSRC_GPIN0,
GPin1: CLKSRC_GPIN1
}
}
struct UsbClock {
init_freq: 0,
reg: clk_usb,
auxsrc: {
PllUsb: CLKSRC_PLL_USB,
PllSys: CLKSRC_PLL_SYS,
Rosc: ROSC_CLKSRC_PH,
Xosc: XOSC_CLKSRC,
GPin0: CLKSRC_GPIN0,
GPin1: CLKSRC_GPIN1
}
}
struct AdcClock {
init_freq: 0,
reg: clk_adc,
auxsrc: {
PllUsb: CLKSRC_PLL_USB,
PllSys: CLKSRC_PLL_SYS,
Rosc: ROSC_CLKSRC_PH,
Xosc: XOSC_CLKSRC,
GPin0: CLKSRC_GPIN0,
GPin1: CLKSRC_GPIN1
}
}
}
impl SystemClock {
fn get_default_clock_source(&self) -> pac::clocks::clk_sys_ctrl::SRC_A {
pac::clocks::clk_sys_ctrl::SRC_A::CLK_REF
}
fn get_aux_source(&self) -> pac::clocks::clk_sys_ctrl::SRC_A {
pac::clocks::clk_sys_ctrl::SRC_A::CLKSRC_CLK_SYS_AUX
}
}
impl ReferenceClock {
fn get_default_clock_source(&self) -> pac::clocks::clk_ref_ctrl::SRC_A {
pac::clocks::clk_ref_ctrl::SRC_A::ROSC_CLKSRC_PH
}
fn get_aux_source(&self) -> pac::clocks::clk_ref_ctrl::SRC_A {
pac::clocks::clk_ref_ctrl::SRC_A::CLKSRC_CLK_REF_AUX
}
}
impl ClocksManager {
pub fn init_default(
&mut self,
xosc: &CrystalOscillator<Stable>,
pll_sys: &PhaseLockedLoop<Locked, PLL_SYS>,
pll_usb: &PhaseLockedLoop<Locked, PLL_USB>,
) -> Result<(), ClockError> {
self.reference_clock
.configure_clock(xosc, xosc.get_freq())?;
self.system_clock
.configure_clock(pll_sys, pll_sys.get_freq())?;
self.usb_clock
.configure_clock(pll_usb, pll_usb.get_freq())?;
self.adc_clock
.configure_clock(pll_usb, pll_usb.get_freq())?;
self.hstx_clock
.configure_clock(pll_sys, pll_sys.get_freq())?;
self.peripheral_clock
.configure_clock(&self.system_clock, self.system_clock.freq())
}
pub fn configure_sleep_enable(&mut self, clock_gate: ClockGate) {
self.clocks
.sleep_en0()
.write(|w| unsafe { w.bits(clock_gate.0 as u32) });
self.clocks
.sleep_en1()
.write(|w| unsafe { w.bits((clock_gate.0 >> 32) as u32) });
}
pub fn sleep_enable(&self) -> ClockGate {
ClockGate(
(u64::from(self.clocks.sleep_en1().read().bits()) << 32)
| u64::from(self.clocks.sleep_en0().read().bits()),
)
}
pub fn wake_enable(&self) -> ClockGate {
ClockGate(
(u64::from(self.clocks.wake_en1().read().bits()) << 32)
| u64::from(self.clocks.wake_en0().read().bits()),
)
}
pub fn free(self) -> CLOCKS {
self.clocks
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum InitError {
XoscErr(XoscError),
PllError(PllError),
ClockError(ClockError),
}
pub fn init_clocks_and_plls(
xosc_crystal_freq: u32,
xosc_dev: XOSC,
clocks_dev: CLOCKS,
pll_sys_dev: PLL_SYS,
pll_usb_dev: PLL_USB,
resets: &mut RESETS,
watchdog: &mut Watchdog,
) -> Result<ClocksManager, InitError> {
let xosc = setup_xosc_blocking(xosc_dev, xosc_crystal_freq.Hz()).map_err(InitError::XoscErr)?;
watchdog.enable_tick_generation((xosc_crystal_freq / 1_000_000) as u16);
let mut clocks = ClocksManager::new(clocks_dev);
let pll_sys = setup_pll_blocking(
pll_sys_dev,
xosc.operating_frequency(),
PLL_SYS_150MHZ,
&mut clocks,
resets,
)
.map_err(InitError::PllError)?;
let pll_usb = setup_pll_blocking(
pll_usb_dev,
xosc.operating_frequency(),
PLL_USB_48MHZ,
&mut clocks,
resets,
)
.map_err(InitError::PllError)?;
clocks
.init_default(&xosc, &pll_sys, &pll_usb)
.map_err(InitError::ClockError)?;
Ok(clocks)
}
fn fractional_div(numerator: u32, denominator: u32) -> Option<u32> {
let numerator: u64 = u64::from(numerator) * 65536;
let denominator: u64 = u64::from(denominator);
let result = numerator / denominator;
result.try_into().ok()
}