aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.