aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-05-16 22:45:50 +0200
committerpennae <[email protected]>2023-05-17 21:36:19 +0200
commitf79d8cb2d3998662eb4555d424cc75f3899a3151 (patch)
tree39997a67fd4ad6a52c4384b660d567134fe272f5 /embassy-rp
parent0d4ab559a717cef0b9a86186142f403252f38a9b (diff)
rp/clocks: store clock frequencies in ram
don't recalculate clock frequencies every time they are asked for. while this is not very often in practice it does consume a bunch of flash space that cannot be optimized away, and was pulled in unconditionally previously. while we technically only need the configured rosc, xosc and gpin frequencies it is easier to store all frequencies (and much cheaper at runtime too).
Diffstat (limited to 'embassy-rp')
-rw-r--r--embassy-rp/src/clocks.rs384
-rw-r--r--embassy-rp/src/rtc/mod.rs7
2 files changed, 184 insertions, 207 deletions
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 2305a1e34..9e581f105 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -1,10 +1,39 @@
1use core::sync::atomic::{AtomicU16, AtomicU32, Ordering};
2
1use embassy_hal_common::{into_ref, PeripheralRef}; 3use embassy_hal_common::{into_ref, PeripheralRef};
2use pac::clocks::vals::*; 4use pac::clocks::vals::*;
3 5
4use crate::{pac, reset, Peripheral}; 6use crate::{pac, reset, Peripheral};
5 7
6// TODO fix terrible use of global here 8struct Clocks {
7static mut XIN_HZ: u32 = 0; 9 xosc: AtomicU32,
10 sys: AtomicU32,
11 reference: AtomicU32,
12 pll_sys: AtomicU32,
13 pll_usb: AtomicU32,
14 usb: AtomicU32,
15 adc: AtomicU32,
16 gpin0: AtomicU32,
17 gpin1: AtomicU32,
18 rosc: AtomicU32,
19 peri: AtomicU32,
20 rtc: AtomicU16,
21}
22
23static CLOCKS: Clocks = Clocks {
24 xosc: AtomicU32::new(0),
25 sys: AtomicU32::new(0),
26 reference: AtomicU32::new(0),
27 pll_sys: AtomicU32::new(0),
28 pll_usb: AtomicU32::new(0),
29 usb: AtomicU32::new(0),
30 adc: AtomicU32::new(0),
31 gpin0: AtomicU32::new(0),
32 gpin1: AtomicU32::new(0),
33 rosc: AtomicU32::new(0),
34 peri: AtomicU32::new(0),
35 rtc: AtomicU16::new(0),
36};
8 37
9#[repr(u8)] 38#[repr(u8)]
10#[non_exhaustive] 39#[non_exhaustive]
@@ -29,12 +58,15 @@ pub struct ClockConfig {
29 pub usb_clk: Option<UsbClkConfig>, 58 pub usb_clk: Option<UsbClkConfig>,
30 pub adc_clk: Option<AdcClkConfig>, 59 pub adc_clk: Option<AdcClkConfig>,
31 pub rtc_clk: Option<RtcClkConfig>, 60 pub rtc_clk: Option<RtcClkConfig>,
61 pub gpin0_hz: Option<u32>,
62 pub gpin1_hz: Option<u32>,
32} 63}
33 64
34impl ClockConfig { 65impl ClockConfig {
35 pub fn crystal(crystal_hz: u32) -> Self { 66 pub fn crystal(crystal_hz: u32) -> Self {
36 Self { 67 Self {
37 rosc: Some(RoscConfig { 68 rosc: Some(RoscConfig {
69 hz: 6_500_000,
38 range: RoscRange::Medium, 70 range: RoscRange::Medium,
39 drive_strength: [0; 8], 71 drive_strength: [0; 8],
40 div: 16, 72 div: 16,
@@ -83,12 +115,15 @@ impl ClockConfig {
83 div_frac: 0, 115 div_frac: 0,
84 phase: 0, 116 phase: 0,
85 }), 117 }),
118 gpin0_hz: None,
119 gpin1_hz: None,
86 } 120 }
87 } 121 }
88 122
89 pub fn rosc() -> Self { 123 pub fn rosc() -> Self {
90 Self { 124 Self {
91 rosc: Some(RoscConfig { 125 rosc: Some(RoscConfig {
126 hz: 140_000_000,
92 range: RoscRange::High, 127 range: RoscRange::High,
93 drive_strength: [0; 8], 128 drive_strength: [0; 8],
94 div: 1, 129 div: 1,
@@ -118,6 +153,8 @@ impl ClockConfig {
118 div_frac: 171, 153 div_frac: 171,
119 phase: 0, 154 phase: 0,
120 }), 155 }),
156 gpin0_hz: None,
157 gpin1_hz: None,
121 } 158 }
122 } 159 }
123} 160}
@@ -133,6 +170,11 @@ pub enum RoscRange {
133} 170}
134 171
135pub struct RoscConfig { 172pub struct RoscConfig {
173 /// Final frequency of the oscillator, after the divider has been applied.
174 /// The oscillator has a nominal frequency of 6.5MHz at medium range with
175 /// divider 16 and all drive strengths set to 0, other values should be
176 /// measured in situ.
177 pub hz: u32,
136 pub range: RoscRange, 178 pub range: RoscRange,
137 pub drive_strength: [u8; 8], 179 pub drive_strength: [u8; 8],
138 pub div: u16, 180 pub div: u16,
@@ -145,7 +187,7 @@ pub struct XoscConfig {
145} 187}
146 188
147pub struct PllConfig { 189pub struct PllConfig {
148 pub refdiv: u32, 190 pub refdiv: u8,
149 pub fbdiv: u16, 191 pub fbdiv: u16,
150 pub post_div1: u8, 192 pub post_div1: u8,
151 pub post_div2: u8, 193 pub post_div2: u8,
@@ -277,41 +319,60 @@ pub(crate) unsafe fn init(config: ClockConfig) {
277 reset::reset(peris); 319 reset::reset(peris);
278 reset::unreset_wait(peris); 320 reset::unreset_wait(peris);
279 321
280 if let Some(config) = config.rosc { 322 let gpin0_freq = config.gpin0_hz.unwrap_or(0);
281 configure_rosc(config); 323 CLOCKS.gpin0.store(gpin0_freq, Ordering::Relaxed);
282 } 324 let gpin1_freq = config.gpin1_hz.unwrap_or(0);
283 325 CLOCKS.gpin1.store(gpin1_freq, Ordering::Relaxed);
284 if let Some(config) = config.xosc {
285 XIN_HZ = config.hz;
286 326
287 pac::WATCHDOG.tick().write(|w| { 327 let rosc_freq = match config.rosc {
288 w.set_cycles((config.hz / 1_000_000) as u16); 328 Some(config) => configure_rosc(config),
289 w.set_enable(true); 329 None => 0,
290 }); 330 };
331 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed);
291 332
292 // start XOSC 333 let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc {
293 // datasheet mentions support for clock inputs into XIN, but doesn't go into 334 Some(config) => {
294 // how this is achieved. pico-sdk doesn't support this at all. 335 pac::WATCHDOG.tick().write(|w| {
295 start_xosc(config.hz); 336 w.set_cycles((config.hz / 1_000_000) as u16);
337 w.set_enable(true);
338 });
296 339
297 if let Some(sys_pll_config) = config.sys_pll { 340 // start XOSC
298 configure_pll(pac::PLL_SYS, config.hz, sys_pll_config); 341 // datasheet mentions support for clock inputs into XIN, but doesn't go into
299 } 342 // how this is achieved. pico-sdk doesn't support this at all.
300 if let Some(usb_pll_config) = config.usb_pll { 343 start_xosc(config.hz);
301 configure_pll(pac::PLL_USB, config.hz, usb_pll_config); 344
345 let pll_sys_freq = match config.sys_pll {
346 Some(sys_pll_config) => configure_pll(pac::PLL_SYS, config.hz, sys_pll_config),
347 None => 0,
348 };
349 let pll_usb_freq = match config.usb_pll {
350 Some(usb_pll_config) => configure_pll(pac::PLL_USB, config.hz, usb_pll_config),
351 None => 0,
352 };
353
354 (config.hz, pll_sys_freq, pll_usb_freq)
302 } 355 }
303 } 356 None => (0, 0, 0),
357 };
358 CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed);
359 CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed);
360 CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed);
304 361
305 let (ref_src, ref_aux) = { 362 let (ref_src, ref_aux, clk_ref_freq) = {
306 use {ClkRefCtrlAuxsrc as Aux, ClkRefCtrlSrc as Src}; 363 use {ClkRefCtrlAuxsrc as Aux, ClkRefCtrlSrc as Src};
364 let div = config.ref_clk.div as u32;
365 assert!(div >= 1 && div <= 4);
307 match config.ref_clk.src { 366 match config.ref_clk.src {
308 RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB), 367 RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div),
309 RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB), 368 RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div),
310 RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB), 369 RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div),
311 RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0), 370 RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div),
312 RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1), 371 RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div),
313 } 372 }
314 }; 373 };
374 assert!(clk_ref_freq != 0);
375 CLOCKS.reference.store(clk_ref_freq, Ordering::Relaxed);
315 c.clk_ref_ctrl().write(|w| { 376 c.clk_ref_ctrl().write(|w| {
316 w.set_src(ref_src); 377 w.set_src(ref_src);
317 w.set_auxsrc(ref_aux); 378 w.set_auxsrc(ref_aux);
@@ -322,22 +383,27 @@ pub(crate) unsafe fn init(config: ClockConfig) {
322 }); 383 });
323 384
324 pac::WATCHDOG.tick().write(|w| { 385 pac::WATCHDOG.tick().write(|w| {
325 w.set_cycles((clk_ref_freq() / 1_000_000) as u16); 386 w.set_cycles((clk_ref_freq / 1_000_000) as u16);
326 w.set_enable(true); 387 w.set_enable(true);
327 }); 388 });
328 389
329 let (sys_src, sys_aux) = { 390 let (sys_src, sys_aux, clk_sys_freq) = {
330 use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src}; 391 use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src};
331 match config.sys_clk.src { 392 let (src, aux, freq) = match config.sys_clk.src {
332 SysClkSrc::Ref => (Src::CLK_REF, Aux::CLKSRC_PLL_SYS), 393 SysClkSrc::Ref => (Src::CLK_REF, Aux::CLKSRC_PLL_SYS, clk_ref_freq),
333 SysClkSrc::PllSys => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_SYS), 394 SysClkSrc::PllSys => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_SYS, pll_sys_freq),
334 SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB), 395 SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq),
335 SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC), 396 SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq),
336 SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC), 397 SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq),
337 SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0), 398 SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq),
338 SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1), 399 SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq),
339 } 400 };
401 assert!(config.sys_clk.div_int <= 0x1000000);
402 let div = config.sys_clk.div_int as u64 * 256 + config.sys_clk.div_frac as u64;
403 (src, aux, ((freq as u64 * 256) / div) as u32)
340 }; 404 };
405 assert!(clk_sys_freq != 0);
406 CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed);
341 if sys_src != ClkSysCtrlSrc::CLK_REF { 407 if sys_src != ClkSysCtrlSrc::CLK_REF {
342 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); 408 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
343 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} 409 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {}
@@ -359,11 +425,23 @@ pub(crate) unsafe fn init(config: ClockConfig) {
359 w.set_enable(true); 425 w.set_enable(true);
360 w.set_auxsrc(ClkPeriCtrlAuxsrc(src as _)); 426 w.set_auxsrc(ClkPeriCtrlAuxsrc(src as _));
361 }); 427 });
428 let peri_freq = match src {
429 PeriClkSrc::Sys => clk_sys_freq,
430 PeriClkSrc::PllSys => pll_sys_freq,
431 PeriClkSrc::PllUsb => pll_usb_freq,
432 PeriClkSrc::Rosc => rosc_freq,
433 PeriClkSrc::Xosc => xosc_freq,
434 PeriClkSrc::Gpin0 => gpin0_freq,
435 PeriClkSrc::Gpin1 => gpin1_freq,
436 };
437 assert!(peri_freq != 0);
438 CLOCKS.peri.store(peri_freq, Ordering::Relaxed);
362 } else { 439 } else {
363 peris.set_spi0(false); 440 peris.set_spi0(false);
364 peris.set_spi1(false); 441 peris.set_spi1(false);
365 peris.set_uart0(false); 442 peris.set_uart0(false);
366 peris.set_uart1(false); 443 peris.set_uart1(false);
444 CLOCKS.peri.store(0, Ordering::Relaxed);
367 } 445 }
368 446
369 if let Some(conf) = config.usb_clk { 447 if let Some(conf) = config.usb_clk {
@@ -373,8 +451,20 @@ pub(crate) unsafe fn init(config: ClockConfig) {
373 w.set_enable(true); 451 w.set_enable(true);
374 w.set_auxsrc(ClkUsbCtrlAuxsrc(conf.src as _)); 452 w.set_auxsrc(ClkUsbCtrlAuxsrc(conf.src as _));
375 }); 453 });
454 let usb_freq = match conf.src {
455 UsbClkSrc::PllUsb => pll_usb_freq,
456 UsbClkSrc::PllSys => pll_sys_freq,
457 UsbClkSrc::Rosc => rosc_freq,
458 UsbClkSrc::Xosc => xosc_freq,
459 UsbClkSrc::Gpin0 => gpin0_freq,
460 UsbClkSrc::Gpin1 => gpin1_freq,
461 };
462 assert!(usb_freq != 0);
463 assert!(conf.div >= 1 && conf.div <= 4);
464 CLOCKS.usb.store(usb_freq / conf.div as u32, Ordering::Relaxed);
376 } else { 465 } else {
377 peris.set_usbctrl(false); 466 peris.set_usbctrl(false);
467 CLOCKS.usb.store(0, Ordering::Relaxed);
378 } 468 }
379 469
380 if let Some(conf) = config.adc_clk { 470 if let Some(conf) = config.adc_clk {
@@ -384,8 +474,20 @@ pub(crate) unsafe fn init(config: ClockConfig) {
384 w.set_enable(true); 474 w.set_enable(true);
385 w.set_auxsrc(ClkAdcCtrlAuxsrc(conf.src as _)); 475 w.set_auxsrc(ClkAdcCtrlAuxsrc(conf.src as _));
386 }); 476 });
477 let adc_in_freq = match conf.src {
478 AdcClkSrc::PllUsb => pll_usb_freq,
479 AdcClkSrc::PllSys => pll_sys_freq,
480 AdcClkSrc::Rosc => rosc_freq,
481 AdcClkSrc::Xosc => xosc_freq,
482 AdcClkSrc::Gpin0 => gpin0_freq,
483 AdcClkSrc::Gpin1 => gpin1_freq,
484 };
485 assert!(adc_in_freq != 0);
486 assert!(conf.div >= 1 && conf.div <= 4);
487 CLOCKS.adc.store(adc_in_freq / conf.div as u32, Ordering::Relaxed);
387 } else { 488 } else {
388 peris.set_adc(false); 489 peris.set_adc(false);
490 CLOCKS.adc.store(0, Ordering::Relaxed);
389 } 491 }
390 492
391 if let Some(conf) = config.rtc_clk { 493 if let Some(conf) = config.rtc_clk {
@@ -401,15 +503,30 @@ pub(crate) unsafe fn init(config: ClockConfig) {
401 w.set_enable(true); 503 w.set_enable(true);
402 w.set_auxsrc(ClkRtcCtrlAuxsrc(conf.src as _)); 504 w.set_auxsrc(ClkRtcCtrlAuxsrc(conf.src as _));
403 }); 505 });
506 let rtc_in_freq = match conf.src {
507 RtcClkSrc::PllUsb => pll_usb_freq,
508 RtcClkSrc::PllSys => pll_sys_freq,
509 RtcClkSrc::Rosc => rosc_freq,
510 RtcClkSrc::Xosc => xosc_freq,
511 RtcClkSrc::Gpin0 => gpin0_freq,
512 RtcClkSrc::Gpin1 => gpin1_freq,
513 };
514 assert!(rtc_in_freq != 0);
515 assert!(config.sys_clk.div_int <= 0x1000000);
516 CLOCKS.rtc.store(
517 ((rtc_in_freq as u64 * 256) / (conf.div_int as u64 * 256 + conf.div_frac as u64)) as u16,
518 Ordering::Relaxed,
519 );
404 } else { 520 } else {
405 peris.set_rtc(false); 521 peris.set_rtc(false);
522 CLOCKS.rtc.store(0, Ordering::Relaxed);
406 } 523 }
407 524
408 // Peripheral clocks should now all be running 525 // Peripheral clocks should now all be running
409 reset::unreset_wait(peris); 526 reset::unreset_wait(peris);
410} 527}
411 528
412unsafe fn configure_rosc(config: RoscConfig) { 529unsafe fn configure_rosc(config: RoscConfig) -> u32 {
413 let p = pac::ROSC; 530 let p = pac::ROSC;
414 531
415 p.freqa().write(|w| { 532 p.freqa().write(|w| {
@@ -436,193 +553,55 @@ unsafe fn configure_rosc(config: RoscConfig) {
436 w.set_enable(pac::rosc::vals::Enable::ENABLE); 553 w.set_enable(pac::rosc::vals::Enable::ENABLE);
437 w.set_freq_range(pac::rosc::vals::FreqRange(config.range as u16)); 554 w.set_freq_range(pac::rosc::vals::FreqRange(config.range as u16));
438 }); 555 });
439}
440 556
441pub fn estimate_rosc_freq() -> u32 { 557 config.hz
442 let p = pac::ROSC; 558}
443
444 let base = match unsafe { p.ctrl().read().freq_range() } {
445 pac::rosc::vals::FreqRange::LOW => 84_000_000,
446 pac::rosc::vals::FreqRange::MEDIUM => 104_000_000,
447 pac::rosc::vals::FreqRange::HIGH => 140_000_000,
448 pac::rosc::vals::FreqRange::TOOHIGH => 208_000_000,
449 _ => unreachable!(),
450 };
451 let mut div = unsafe { p.div().read().0 - pac::rosc::vals::Div::PASS.0 as u32 };
452 if div == 0 {
453 div = 32
454 }
455 559
456 base / div 560pub fn rosc_freq() -> u32 {
561 CLOCKS.rosc.load(Ordering::Relaxed)
457} 562}
458 563
459pub fn xosc_freq() -> u32 { 564pub fn xosc_freq() -> u32 {
460 unsafe { XIN_HZ } 565 CLOCKS.xosc.load(Ordering::Relaxed)
461} 566}
462 567
463pub fn gpin0_freq() -> u32 { 568pub fn gpin0_freq() -> u32 {
464 todo!() 569 CLOCKS.gpin0.load(Ordering::Relaxed)
465} 570}
466pub fn gpin1_freq() -> u32 { 571pub fn gpin1_freq() -> u32 {
467 todo!() 572 CLOCKS.gpin1.load(Ordering::Relaxed)
468} 573}
469 574
470pub fn pll_sys_freq() -> u32 { 575pub fn pll_sys_freq() -> u32 {
471 let p = pac::PLL_SYS; 576 CLOCKS.pll_sys.load(Ordering::Relaxed)
472
473 let input_freq = xosc_freq();
474 let cs = unsafe { p.cs().read() };
475
476 let refdiv = cs.refdiv() as u32;
477 let fbdiv = unsafe { p.fbdiv_int().read().fbdiv_int() } as u32;
478 let (postdiv1, postdiv2) = unsafe {
479 let prim = p.prim().read();
480 (prim.postdiv1() as u32, prim.postdiv2() as u32)
481 };
482
483 (((input_freq / refdiv) * fbdiv) / postdiv1) / postdiv2
484} 577}
485 578
486pub fn pll_usb_freq() -> u32 { 579pub fn pll_usb_freq() -> u32 {
487 let p = pac::PLL_USB; 580 CLOCKS.pll_usb.load(Ordering::Relaxed)
488
489 let input_freq = xosc_freq();
490 let cs = unsafe { p.cs().read() };
491
492 let refdiv = cs.refdiv() as u32;
493 let fbdiv = unsafe { p.fbdiv_int().read().fbdiv_int() } as u32;
494 let (postdiv1, postdiv2) = unsafe {
495 let prim = p.prim().read();
496 (prim.postdiv1() as u32, prim.postdiv2() as u32)
497 };
498
499 (((input_freq / refdiv) * fbdiv) / postdiv1) / postdiv2
500} 581}
501 582
502pub fn clk_sys_freq() -> u32 { 583pub fn clk_sys_freq() -> u32 {
503 let c = pac::CLOCKS; 584 CLOCKS.sys.load(Ordering::Relaxed)
504 let ctrl = unsafe { c.clk_sys_ctrl().read() };
505
506 let base = match ctrl.src() {
507 ClkSysCtrlSrc::CLK_REF => clk_ref_freq(),
508 ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX => match ctrl.auxsrc() {
509 ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
510 ClkSysCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
511 ClkSysCtrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(),
512 ClkSysCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
513 ClkSysCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
514 ClkSysCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
515 _ => unreachable!(),
516 },
517 _ => unreachable!(),
518 };
519
520 let div = unsafe { c.clk_sys_div().read() };
521 let int = if div.int() == 0 { 65536 } else { div.int() };
522 // TODO handle fractional clock div
523 let _frac = div.frac();
524
525 base / int
526} 585}
527 586
528pub fn clk_ref_freq() -> u32 { 587pub fn clk_ref_freq() -> u32 {
529 let c = pac::CLOCKS; 588 CLOCKS.reference.load(Ordering::Relaxed)
530 let ctrl = unsafe { c.clk_ref_ctrl().read() };
531
532 let base = match ctrl.src() {
533 ClkRefCtrlSrc::ROSC_CLKSRC_PH => estimate_rosc_freq(),
534 ClkRefCtrlSrc::XOSC_CLKSRC => xosc_freq(),
535 ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX => match ctrl.auxsrc() {
536 ClkRefCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
537 ClkRefCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
538 ClkRefCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
539 _ => unreachable!(),
540 },
541 _ => unreachable!(),
542 };
543
544 let div = unsafe { c.clk_ref_div().read() };
545 let int = if div.int() == 0 { 4 } else { div.int() as u32 };
546
547 base / int
548} 589}
549 590
550pub fn clk_peri_freq() -> u32 { 591pub fn clk_peri_freq() -> u32 {
551 let c = pac::CLOCKS; 592 CLOCKS.peri.load(Ordering::Relaxed)
552 let src = unsafe { c.clk_peri_ctrl().read().auxsrc() };
553
554 match src {
555 ClkPeriCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
556 ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
557 ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
558 ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(),
559 ClkPeriCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
560 ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
561 ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
562 _ => unreachable!(),
563 }
564} 593}
565 594
566pub fn clk_usb_freq() -> u32 { 595pub fn clk_usb_freq() -> u32 {
567 let c = pac::CLOCKS; 596 CLOCKS.usb.load(Ordering::Relaxed)
568 let ctrl = unsafe { c.clk_usb_ctrl().read() };
569
570 let base = match ctrl.auxsrc() {
571 ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
572 ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
573 ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(),
574 ClkUsbCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
575 ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
576 ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
577 _ => unreachable!(),
578 };
579
580 let div = unsafe { c.clk_ref_div().read() };
581 let int = if div.int() == 0 { 4 } else { div.int() as u32 };
582
583 base / int
584} 597}
585 598
586pub fn clk_adc_freq() -> u32 { 599pub fn clk_adc_freq() -> u32 {
587 let c = pac::CLOCKS; 600 CLOCKS.adc.load(Ordering::Relaxed)
588 let ctrl = unsafe { c.clk_adc_ctrl().read() };
589
590 let base = match ctrl.auxsrc() {
591 ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
592 ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
593 ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(),
594 ClkAdcCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
595 ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
596 ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
597 _ => unreachable!(),
598 };
599
600 let div = unsafe { c.clk_adc_div().read() };
601 let int = if div.int() == 0 { 4 } else { div.int() as u32 };
602
603 base / int
604} 601}
605 602
606pub fn clk_rtc_freq() -> u32 { 603pub fn clk_rtc_freq() -> u16 {
607 let c = pac::CLOCKS; 604 CLOCKS.rtc.load(Ordering::Relaxed)
608 let src = unsafe { c.clk_rtc_ctrl().read().auxsrc() };
609
610 let base = match src {
611 ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
612 ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
613 ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(),
614 ClkRtcCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
615 ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
616 ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
617 _ => unreachable!(),
618 };
619
620 let div = unsafe { c.clk_rtc_div().read() };
621 let int = if div.int() == 0 { 65536 } else { div.int() };
622 // TODO handle fractional clock div
623 let _frac = div.frac();
624
625 base / int
626} 605}
627 606
628unsafe fn start_xosc(crystal_hz: u32) { 607unsafe fn start_xosc(crystal_hz: u32) {
@@ -640,14 +619,15 @@ unsafe fn start_xosc(crystal_hz: u32) {
640} 619}
641 620
642#[inline(always)] 621#[inline(always)]
643unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { 622unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
644 let ref_freq = input_freq / config.refdiv; 623 let ref_freq = input_freq / config.refdiv as u32;
645
646 assert!(config.fbdiv >= 16 && config.fbdiv <= 320); 624 assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
647 assert!(config.post_div1 >= 1 && config.post_div1 <= 7); 625 assert!(config.post_div1 >= 1 && config.post_div1 <= 7);
648 assert!(config.post_div2 >= 1 && config.post_div2 <= 7); 626 assert!(config.post_div2 >= 1 && config.post_div2 <= 7);
649 assert!(config.post_div2 <= config.post_div1); 627 assert!(config.refdiv >= 1 && config.refdiv <= 63);
650 assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000); 628 assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000);
629 let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32);
630 assert!(vco_freq >= 750_000_000 && vco_freq <= 1800_000_000);
651 631
652 // Load VCO-related dividers before starting VCO 632 // Load VCO-related dividers before starting VCO
653 p.cs().write(|w| w.set_refdiv(config.refdiv as _)); 633 p.cs().write(|w| w.set_refdiv(config.refdiv as _));
@@ -671,6 +651,8 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) {
671 651
672 // Turn on post divider 652 // Turn on post divider
673 p.pwr().modify(|w| w.set_postdivpd(false)); 653 p.pwr().modify(|w| w.set_postdivpd(false));
654
655 vco_freq / ((config.post_div1 * config.post_div2) as u32)
674} 656}
675 657
676pub trait GpinPin: crate::gpio::Pin { 658pub trait GpinPin: crate::gpio::Pin {
@@ -812,12 +794,12 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
812 ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), 794 ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
813 ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), 795 ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
814 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), 796 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
815 ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(), 797 ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => rosc_freq(),
816 ClkGpoutCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(), 798 ClkGpoutCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
817 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(), 799 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
818 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(), 800 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(),
819 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(), 801 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(),
820 ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq(), 802 ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _,
821 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(), 803 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(),
822 _ => unreachable!(), 804 _ => unreachable!(),
823 }; 805 };
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index c173909c7..c213ad174 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -26,12 +26,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
26 into_ref!(inner); 26 into_ref!(inner);
27 27
28 // Set the RTC divider 28 // Set the RTC divider
29 unsafe { 29 unsafe { inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)) };
30 inner
31 .regs()
32 .clkdiv_m1()
33 .write(|w| w.set_clkdiv_m1(clk_rtc_freq() as u16 - 1))
34 };
35 30
36 let mut result = Self { inner }; 31 let mut result = Self { inner };
37 result.set_leap_year_check(true); // should be on by default, make sure this is the case. 32 result.set_leap_year_check(true); // should be on by default, make sure this is the case.