aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-05-17 22:20:44 +0000
committerGitHub <[email protected]>2023-05-17 22:20:44 +0000
commit4b303949bff82cb328b75e37e9e03038d8d0e778 (patch)
tree4e06a78cf075a26aedf7cc3edde8840468d1cd5d
parent908ec5faef00345c680a3e6e64b30f107f2cd26f (diff)
parentfc746a88b50f2d57a573d7a9ec8b8f3fbc0c9b08 (diff)
Merge #1465
1465: rp: continue clock rework r=Dirbaio a=pennae vastly reduce the code size of initial clock config (over 700 bytes saved!), at the cost of about 48 bytes of ram used to store the frequencies of all clocks in the system. also stop exporting unstable pac items for clock config, fix a few settings that were out of spec, and add missing features (most notably gpin source information). Co-authored-by: pennae <[email protected]>
-rw-r--r--embassy-rp/src/clocks.rs722
-rw-r--r--embassy-rp/src/rtc/mod.rs7
-rw-r--r--examples/rp/src/bin/gpout.rs4
3 files changed, 396 insertions, 337 deletions
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 1354ccd27..67439fda3 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -1,51 +1,96 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{AtomicU16, AtomicU32, Ordering};
3
1use embassy_hal_common::{into_ref, PeripheralRef}; 4use embassy_hal_common::{into_ref, PeripheralRef};
2use pac::clocks::vals::*; 5use pac::clocks::vals::*;
3 6
7use crate::gpio::sealed::Pin;
8use crate::gpio::AnyPin;
4use crate::{pac, reset, Peripheral}; 9use crate::{pac, reset, Peripheral};
5 10
6// TODO fix terrible use of global here 11// NOTE: all gpin handling is commented out for future reference.
7static mut XIN_HZ: u32 = 0; 12// gpin is not usually safe to use during the boot init() call, so it won't
8 13// be very useful until we have runtime clock reconfiguration. once this
9pub use rp_pac::clocks::vals::{ 14// happens we can resurrect the commented-out gpin bits.
10 ClkAdcCtrlAuxsrc as AdcAuxsrc, ClkGpoutCtrlAuxsrc as GpoutSrc, ClkPeriCtrlAuxsrc as PeriClkAuxsrc, 15struct Clocks {
11 ClkRefCtrlAuxsrc as RefAuxsrc, ClkRtcCtrlAuxsrc as RtcAuxsrc, ClkSysCtrlAuxsrc as SysAuxsrc, 16 xosc: AtomicU32,
12 ClkUsbCtrlAuxsrc as UsbAuxsrc, 17 sys: AtomicU32,
18 reference: AtomicU32,
19 pll_sys: AtomicU32,
20 pll_usb: AtomicU32,
21 usb: AtomicU32,
22 adc: AtomicU32,
23 // gpin0: AtomicU32,
24 // gpin1: AtomicU32,
25 rosc: AtomicU32,
26 peri: AtomicU32,
27 rtc: AtomicU16,
28}
29
30static CLOCKS: Clocks = Clocks {
31 xosc: AtomicU32::new(0),
32 sys: AtomicU32::new(0),
33 reference: AtomicU32::new(0),
34 pll_sys: AtomicU32::new(0),
35 pll_usb: AtomicU32::new(0),
36 usb: AtomicU32::new(0),
37 adc: AtomicU32::new(0),
38 // gpin0: AtomicU32::new(0),
39 // gpin1: AtomicU32::new(0),
40 rosc: AtomicU32::new(0),
41 peri: AtomicU32::new(0),
42 rtc: AtomicU16::new(0),
13}; 43};
14 44
45#[repr(u8)]
46#[non_exhaustive]
47#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub enum PeriClkSrc {
49 Sys = ClkPeriCtrlAuxsrc::CLK_SYS.0,
50 PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS.0,
51 PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB.0,
52 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH.0,
53 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC.0,
54 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0.0,
55 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1.0,
56}
57
15#[non_exhaustive] 58#[non_exhaustive]
16pub struct ClockConfig { 59pub struct ClockConfig {
17 pub rosc: Option<RoscConfig>, 60 pub rosc: Option<RoscConfig>,
18 pub xosc: Option<XoscConfig>, 61 pub xosc: Option<XoscConfig>,
19 pub ref_clk: RefClkConfig, 62 pub ref_clk: RefClkConfig,
20 pub sys_clk: SysClkConfig, 63 pub sys_clk: SysClkConfig,
21 pub peri_clk_src: Option<ClkPeriCtrlAuxsrc>, 64 pub peri_clk_src: Option<PeriClkSrc>,
22 pub usb_clk: Option<UsbClkConfig>, 65 pub usb_clk: Option<UsbClkConfig>,
23 pub adc_clk: Option<AdcClkConfig>, 66 pub adc_clk: Option<AdcClkConfig>,
24 pub rtc_clk: Option<RtcClkConfig>, 67 pub rtc_clk: Option<RtcClkConfig>,
68 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
69 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>,
25} 70}
26 71
27impl ClockConfig { 72impl ClockConfig {
28 pub fn crystal(crystal_hz: u32) -> Self { 73 pub fn crystal(crystal_hz: u32) -> Self {
29 Self { 74 Self {
30 rosc: Some(RoscConfig { 75 rosc: Some(RoscConfig {
31 range: pac::rosc::vals::FreqRange::MEDIUM, 76 hz: 6_500_000,
77 range: RoscRange::Medium,
32 drive_strength: [0; 8], 78 drive_strength: [0; 8],
33 div: 16, 79 div: 16,
34 }), 80 }),
35 xosc: Some(XoscConfig { 81 xosc: Some(XoscConfig {
36 hz: crystal_hz, 82 hz: crystal_hz,
37 clock_type: ExternalClock::Crystal,
38 sys_pll: Some(PllConfig { 83 sys_pll: Some(PllConfig {
39 refdiv: 1, 84 refdiv: 1,
40 vco_freq: 1500_000_000, 85 fbdiv: 125,
41 post_div1: 6, 86 post_div1: 6,
42 post_div2: 2, 87 post_div2: 2,
43 }), 88 }),
44 usb_pll: Some(PllConfig { 89 usb_pll: Some(PllConfig {
45 refdiv: 1, 90 refdiv: 1,
46 vco_freq: 480_000_000, 91 fbdiv: 120,
47 post_div1: 5, 92 post_div1: 6,
48 post_div2: 2, 93 post_div2: 5,
49 }), 94 }),
50 }), 95 }),
51 ref_clk: RefClkConfig { 96 ref_clk: RefClkConfig {
@@ -53,34 +98,40 @@ impl ClockConfig {
53 div: 1, 98 div: 1,
54 }, 99 },
55 sys_clk: SysClkConfig { 100 sys_clk: SysClkConfig {
56 src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS), 101 src: SysClkSrc::PllSys,
57 div_int: 1, 102 div_int: 1,
58 div_frac: 0, 103 div_frac: 0,
59 }, 104 },
60 peri_clk_src: Some(ClkPeriCtrlAuxsrc::CLK_SYS), 105 peri_clk_src: Some(PeriClkSrc::Sys),
106 // CLK USB = PLL USB (48MHz) / 1 = 48MHz
61 usb_clk: Some(UsbClkConfig { 107 usb_clk: Some(UsbClkConfig {
62 src: ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB, 108 src: UsbClkSrc::PllUsb,
63 div: 1, 109 div: 1,
64 phase: 0, 110 phase: 0,
65 }), 111 }),
112 // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz
66 adc_clk: Some(AdcClkConfig { 113 adc_clk: Some(AdcClkConfig {
67 src: ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB, 114 src: AdcClkSrc::PllUsb,
68 div: 1, 115 div: 1,
69 phase: 0, 116 phase: 0,
70 }), 117 }),
118 // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz
71 rtc_clk: Some(RtcClkConfig { 119 rtc_clk: Some(RtcClkConfig {
72 src: ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB, 120 src: RtcClkSrc::PllUsb,
73 div_int: 1024, 121 div_int: 1024,
74 div_frac: 0, 122 div_frac: 0,
75 phase: 0, 123 phase: 0,
76 }), 124 }),
125 // gpin0: None,
126 // gpin1: None,
77 } 127 }
78 } 128 }
79 129
80 pub fn rosc() -> Self { 130 pub fn rosc() -> Self {
81 Self { 131 Self {
82 rosc: Some(RoscConfig { 132 rosc: Some(RoscConfig {
83 range: pac::rosc::vals::FreqRange::HIGH, 133 hz: 140_000_000,
134 range: RoscRange::High,
84 drive_strength: [0; 8], 135 drive_strength: [0; 8],
85 div: 1, 136 div: 1,
86 }), 137 }),
@@ -90,65 +141,104 @@ impl ClockConfig {
90 div: 1, 141 div: 1,
91 }, 142 },
92 sys_clk: SysClkConfig { 143 sys_clk: SysClkConfig {
93 src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::ROSC_CLKSRC), 144 src: SysClkSrc::Rosc,
94 div_int: 1, 145 div_int: 1,
95 div_frac: 0, 146 div_frac: 0,
96 }, 147 },
97 peri_clk_src: Some(ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH), 148 peri_clk_src: Some(PeriClkSrc::Rosc),
98 usb_clk: None, 149 usb_clk: None,
150 // CLK ADC = ROSC (140MHz) / 3 ≅ 48MHz
99 adc_clk: Some(AdcClkConfig { 151 adc_clk: Some(AdcClkConfig {
100 src: ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH, 152 src: AdcClkSrc::Rosc,
101 div: 1, 153 div: 3,
102 phase: 0, 154 phase: 0,
103 }), 155 }),
156 // CLK RTC = ROSC (140MHz) / 2986.667969 ≅ 46875Hz
104 rtc_clk: Some(RtcClkConfig { 157 rtc_clk: Some(RtcClkConfig {
105 src: ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH, 158 src: RtcClkSrc::Rosc,
106 div_int: 1024, 159 div_int: 2986,
107 div_frac: 0, 160 div_frac: 171,
108 phase: 0, 161 phase: 0,
109 }), 162 }),
163 // gpin0: None,
164 // gpin1: None,
110 } 165 }
111 } 166 }
167
168 // pub fn bind_gpin<P: GpinPin>(&mut self, gpin: Gpin<'static, P>, hz: u32) {
169 // match P::NR {
170 // 0 => self.gpin0 = Some((hz, gpin.map_into())),
171 // 1 => self.gpin1 = Some((hz, gpin.map_into())),
172 // _ => unreachable!(),
173 // }
174 // // pin is now provisionally bound. if the config is applied it must be forgotten,
175 // // or Gpin::drop will deconfigure the clock input.
176 // }
177}
178
179#[repr(u16)]
180#[non_exhaustive]
181#[derive(Clone, Copy, Debug, PartialEq, Eq)]
182pub enum RoscRange {
183 Low = pac::rosc::vals::FreqRange::LOW.0,
184 Medium = pac::rosc::vals::FreqRange::MEDIUM.0,
185 High = pac::rosc::vals::FreqRange::HIGH.0,
186 TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0,
112} 187}
113 188
114pub struct RoscConfig { 189pub struct RoscConfig {
115 pub range: pac::rosc::vals::FreqRange, 190 /// Final frequency of the oscillator, after the divider has been applied.
191 /// The oscillator has a nominal frequency of 6.5MHz at medium range with
192 /// divider 16 and all drive strengths set to 0, other values should be
193 /// measured in situ.
194 pub hz: u32,
195 pub range: RoscRange,
116 pub drive_strength: [u8; 8], 196 pub drive_strength: [u8; 8],
117 pub div: u16, 197 pub div: u16,
118} 198}
119 199
120pub struct XoscConfig { 200pub struct XoscConfig {
121 pub hz: u32, 201 pub hz: u32,
122 pub clock_type: ExternalClock,
123 pub sys_pll: Option<PllConfig>, 202 pub sys_pll: Option<PllConfig>,
124 pub usb_pll: Option<PllConfig>, 203 pub usb_pll: Option<PllConfig>,
125} 204}
126 205
127pub struct PllConfig { 206pub struct PllConfig {
128 pub refdiv: u32, 207 pub refdiv: u8,
129 pub vco_freq: u32, 208 pub fbdiv: u16,
130 pub post_div1: u8, 209 pub post_div1: u8,
131 pub post_div2: u8, 210 pub post_div2: u8,
132} 211}
133 212
134pub enum ExternalClock {
135 Crystal,
136 Clock,
137}
138pub struct RefClkConfig { 213pub struct RefClkConfig {
139 pub src: RefClkSrc, 214 pub src: RefClkSrc,
140 pub div: u8, 215 pub div: u8,
141} 216}
142 217
218#[non_exhaustive]
219#[derive(Clone, Copy, Debug, PartialEq, Eq)]
143pub enum RefClkSrc { 220pub enum RefClkSrc {
221 // main sources
144 Xosc, 222 Xosc,
145 Rosc, 223 Rosc,
146 Aux(ClkRefCtrlAuxsrc), 224 // aux sources
225 PllUsb,
226 // Gpin0,
227 // Gpin1,
147} 228}
148 229
230#[non_exhaustive]
231#[derive(Clone, Copy, Debug, PartialEq, Eq)]
149pub enum SysClkSrc { 232pub enum SysClkSrc {
233 // main sources
150 Ref, 234 Ref,
151 Aux(ClkSysCtrlAuxsrc), 235 // aux sources
236 PllSys,
237 PllUsb,
238 Rosc,
239 Xosc,
240 // Gpin0,
241 // Gpin1,
152} 242}
153 243
154pub struct SysClkConfig { 244pub struct SysClkConfig {
@@ -157,20 +247,56 @@ pub struct SysClkConfig {
157 pub div_frac: u8, 247 pub div_frac: u8,
158} 248}
159 249
250#[repr(u8)]
251#[non_exhaustive]
252#[derive(Clone, Copy, Debug, PartialEq, Eq)]
253pub enum UsbClkSrc {
254 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB.0,
255 PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS.0,
256 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH.0,
257 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC.0,
258 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0.0,
259 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1.0,
260}
261
160pub struct UsbClkConfig { 262pub struct UsbClkConfig {
161 pub src: ClkUsbCtrlAuxsrc, 263 pub src: UsbClkSrc,
162 pub div: u8, 264 pub div: u8,
163 pub phase: u8, 265 pub phase: u8,
164} 266}
165 267
268#[repr(u8)]
269#[non_exhaustive]
270#[derive(Clone, Copy, Debug, PartialEq, Eq)]
271pub enum AdcClkSrc {
272 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB.0,
273 PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS.0,
274 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH.0,
275 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC.0,
276 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0.0,
277 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1.0,
278}
279
166pub struct AdcClkConfig { 280pub struct AdcClkConfig {
167 pub src: ClkAdcCtrlAuxsrc, 281 pub src: AdcClkSrc,
168 pub div: u8, 282 pub div: u8,
169 pub phase: u8, 283 pub phase: u8,
170} 284}
171 285
286#[repr(u8)]
287#[non_exhaustive]
288#[derive(Clone, Copy, Debug, PartialEq, Eq)]
289pub enum RtcClkSrc {
290 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB.0,
291 PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS.0,
292 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH.0,
293 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC.0,
294 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0.0,
295 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1.0,
296}
297
172pub struct RtcClkConfig { 298pub struct RtcClkConfig {
173 pub src: ClkRtcCtrlAuxsrc, 299 pub src: RtcClkSrc,
174 pub div_int: u32, 300 pub div_int: u32,
175 pub div_frac: u8, 301 pub div_frac: u8,
176 pub phase: u8, 302 pub phase: u8,
@@ -184,6 +310,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
184 // - USB, SYSCFG (breaks usb-to-swd on core1) 310 // - USB, SYSCFG (breaks usb-to-swd on core1)
185 let mut peris = reset::ALL_PERIPHERALS; 311 let mut peris = reset::ALL_PERIPHERALS;
186 peris.set_io_qspi(false); 312 peris.set_io_qspi(false);
313 // peris.set_io_bank0(false); // might be suicide if we're clocked from gpin
187 peris.set_pads_qspi(false); 314 peris.set_pads_qspi(false);
188 peris.set_pll_sys(false); 315 peris.set_pll_sys(false);
189 peris.set_pll_usb(false); 316 peris.set_pll_usb(false);
@@ -203,84 +330,108 @@ pub(crate) unsafe fn init(config: ClockConfig) {
203 c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH)); 330 c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH));
204 while c.clk_ref_selected().read() != 1 {} 331 while c.clk_ref_selected().read() != 1 {}
205 332
206 if let Some(config) = config.rosc { 333 // Reset the PLLs
207 configure_rosc(config); 334 let mut peris = reset::Peripherals(0);
208 } 335 peris.set_pll_sys(true);
209 336 peris.set_pll_usb(true);
210 if let Some(config) = config.xosc { 337 reset::reset(peris);
211 XIN_HZ = config.hz; 338 reset::unreset_wait(peris);
212
213 pac::WATCHDOG.tick().write(|w| {
214 w.set_cycles((config.hz / 1_000_000) as u16);
215 w.set_enable(true);
216 });
217
218 // start XOSC
219 match config.clock_type {
220 ExternalClock::Crystal => start_xosc(config.hz),
221 // TODO The datasheet says the xosc needs to be put into a bypass mode to use an
222 // external clock, but is mum about how to do that.
223 ExternalClock::Clock => todo!(),
224 }
225
226 if let Some(sys_pll_config) = config.sys_pll {
227 configure_pll(pac::PLL_SYS, config.hz, sys_pll_config);
228 }
229 if let Some(usb_pll_config) = config.usb_pll {
230 configure_pll(pac::PLL_USB, config.hz, usb_pll_config);
231 }
232 }
233 339
234 match config.ref_clk.src { 340 // let gpin0_freq = config.gpin0.map_or(0, |p| {
235 RefClkSrc::Xosc => { 341 // core::mem::forget(p.1);
236 c.clk_ref_ctrl().write(|w| { 342 // p.0
237 w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC); 343 // });
238 }); 344 // CLOCKS.gpin0.store(gpin0_freq, Ordering::Relaxed);
239 while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::XOSC_CLKSRC.0 {} 345 // let gpin1_freq = config.gpin1.map_or(0, |p| {
240 } 346 // core::mem::forget(p.1);
241 RefClkSrc::Rosc => { 347 // p.0
242 c.clk_ref_ctrl().write(|w| { 348 // });
243 w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH); 349 // CLOCKS.gpin1.store(gpin1_freq, Ordering::Relaxed);
244 }); 350
245 while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::ROSC_CLKSRC_PH.0 {} 351 let rosc_freq = match config.rosc {
352 Some(config) => configure_rosc(config),
353 None => 0,
354 };
355 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed);
356
357 let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc {
358 Some(config) => {
359 // start XOSC
360 // datasheet mentions support for clock inputs into XIN, but doesn't go into
361 // how this is achieved. pico-sdk doesn't support this at all.
362 start_xosc(config.hz);
363
364 let pll_sys_freq = match config.sys_pll {
365 Some(sys_pll_config) => configure_pll(pac::PLL_SYS, config.hz, sys_pll_config),
366 None => 0,
367 };
368 let pll_usb_freq = match config.usb_pll {
369 Some(usb_pll_config) => configure_pll(pac::PLL_USB, config.hz, usb_pll_config),
370 None => 0,
371 };
372
373 (config.hz, pll_sys_freq, pll_usb_freq)
246 } 374 }
247 RefClkSrc::Aux(src) => { 375 None => (0, 0, 0),
248 c.clk_ref_ctrl().write(|w| { 376 };
249 w.set_auxsrc(src); 377 CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed);
250 w.set_src(ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX); 378 CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed);
251 }); 379 CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed);
252 while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX.0 {} 380
381 let (ref_src, ref_aux, clk_ref_freq) = {
382 use {ClkRefCtrlAuxsrc as Aux, ClkRefCtrlSrc as Src};
383 let div = config.ref_clk.div as u32;
384 assert!(div >= 1 && div <= 4);
385 match config.ref_clk.src {
386 RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div),
387 RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div),
388 RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div),
389 // RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div),
390 // RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div),
253 } 391 }
254 } 392 };
393 assert!(clk_ref_freq != 0);
394 CLOCKS.reference.store(clk_ref_freq, Ordering::Relaxed);
395 c.clk_ref_ctrl().write(|w| {
396 w.set_src(ref_src);
397 w.set_auxsrc(ref_aux);
398 });
399 while c.clk_ref_selected().read() != 1 << ref_src.0 {}
255 c.clk_ref_div().write(|w| { 400 c.clk_ref_div().write(|w| {
256 w.set_int(config.ref_clk.div); 401 w.set_int(config.ref_clk.div);
257 }); 402 });
258 403
259 pac::WATCHDOG.tick().write(|w| { 404 pac::WATCHDOG.tick().write(|w| {
260 w.set_cycles((clk_ref_freq() / 1_000_000) as u16); 405 w.set_cycles((clk_ref_freq / 1_000_000) as u16);
261 w.set_enable(true); 406 w.set_enable(true);
262 }); 407 });
263 408
264 match config.sys_clk.src { 409 let (sys_src, sys_aux, clk_sys_freq) = {
265 SysClkSrc::Ref => { 410 use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src};
266 c.clk_sys_ctrl().write(|w| { 411 let (src, aux, freq) = match config.sys_clk.src {
267 w.set_src(ClkSysCtrlSrc::CLK_REF); 412 SysClkSrc::Ref => (Src::CLK_REF, Aux::CLKSRC_PLL_SYS, clk_ref_freq),
268 }); 413 SysClkSrc::PllSys => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_SYS, pll_sys_freq),
269 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} 414 SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq),
270 } 415 SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq),
271 SysClkSrc::Aux(src) => { 416 SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq),
272 c.clk_sys_ctrl().write(|w| { 417 // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq),
273 w.set_src(ClkSysCtrlSrc::CLK_REF); 418 // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq),
274 }); 419 };
275 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} 420 assert!(config.sys_clk.div_int <= 0x1000000);
276 421 let div = config.sys_clk.div_int as u64 * 256 + config.sys_clk.div_frac as u64;
277 c.clk_sys_ctrl().write(|w| { 422 (src, aux, ((freq as u64 * 256) / div) as u32)
278 w.set_auxsrc(src); 423 };
279 w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); 424 assert!(clk_sys_freq != 0);
280 }); 425 CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed);
281 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX.0 {} 426 if sys_src != ClkSysCtrlSrc::CLK_REF {
282 } 427 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
428 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {}
283 } 429 }
430 c.clk_sys_ctrl().write(|w| {
431 w.set_auxsrc(sys_aux);
432 w.set_src(sys_src);
433 });
434 while c.clk_sys_selected().read() != 1 << sys_src.0 {}
284 c.clk_sys_div().write(|w| { 435 c.clk_sys_div().write(|w| {
285 w.set_int(config.sys_clk.div_int); 436 w.set_int(config.sys_clk.div_int);
286 w.set_frac(config.sys_clk.div_frac); 437 w.set_frac(config.sys_clk.div_frac);
@@ -291,44 +442,74 @@ pub(crate) unsafe fn init(config: ClockConfig) {
291 if let Some(src) = config.peri_clk_src { 442 if let Some(src) = config.peri_clk_src {
292 c.clk_peri_ctrl().write(|w| { 443 c.clk_peri_ctrl().write(|w| {
293 w.set_enable(true); 444 w.set_enable(true);
294 w.set_auxsrc(src); 445 w.set_auxsrc(ClkPeriCtrlAuxsrc(src as _));
295 }); 446 });
447 let peri_freq = match src {
448 PeriClkSrc::Sys => clk_sys_freq,
449 PeriClkSrc::PllSys => pll_sys_freq,
450 PeriClkSrc::PllUsb => pll_usb_freq,
451 PeriClkSrc::Rosc => rosc_freq,
452 PeriClkSrc::Xosc => xosc_freq,
453 // PeriClkSrc::Gpin0 => gpin0_freq,
454 // PeriClkSrc::Gpin1 => gpin1_freq,
455 };
456 assert!(peri_freq != 0);
457 CLOCKS.peri.store(peri_freq, Ordering::Relaxed);
296 } else { 458 } else {
297 peris.set_spi0(false); 459 peris.set_spi0(false);
298 peris.set_spi1(false); 460 peris.set_spi1(false);
299 peris.set_uart0(false); 461 peris.set_uart0(false);
300 peris.set_uart1(false); 462 peris.set_uart1(false);
463 CLOCKS.peri.store(0, Ordering::Relaxed);
301 } 464 }
302 465
303 if let Some(conf) = config.usb_clk { 466 if let Some(conf) = config.usb_clk {
304 // CLK USB = PLL USB (48MHz) / 1 = 48MHz
305 c.clk_usb_div().write(|w| w.set_int(conf.div)); 467 c.clk_usb_div().write(|w| w.set_int(conf.div));
306 c.clk_usb_ctrl().write(|w| { 468 c.clk_usb_ctrl().write(|w| {
307 w.set_phase(conf.phase); 469 w.set_phase(conf.phase);
308 w.set_enable(true); 470 w.set_enable(true);
309 w.set_auxsrc(conf.src); 471 w.set_auxsrc(ClkUsbCtrlAuxsrc(conf.src as _));
310 }); 472 });
473 let usb_freq = match conf.src {
474 UsbClkSrc::PllUsb => pll_usb_freq,
475 UsbClkSrc::PllSys => pll_sys_freq,
476 UsbClkSrc::Rosc => rosc_freq,
477 UsbClkSrc::Xosc => xosc_freq,
478 // UsbClkSrc::Gpin0 => gpin0_freq,
479 // UsbClkSrc::Gpin1 => gpin1_freq,
480 };
481 assert!(usb_freq != 0);
482 assert!(conf.div >= 1 && conf.div <= 4);
483 CLOCKS.usb.store(usb_freq / conf.div as u32, Ordering::Relaxed);
311 } else { 484 } else {
312 peris.set_usbctrl(false); 485 peris.set_usbctrl(false);
486 CLOCKS.usb.store(0, Ordering::Relaxed);
313 } 487 }
314 488
315 if let Some(conf) = config.adc_clk { 489 if let Some(conf) = config.adc_clk {
316 // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz
317 c.clk_adc_div().write(|w| w.set_int(conf.div)); 490 c.clk_adc_div().write(|w| w.set_int(conf.div));
318 c.clk_adc_ctrl().write(|w| { 491 c.clk_adc_ctrl().write(|w| {
319 w.set_phase(conf.phase); 492 w.set_phase(conf.phase);
320 w.set_enable(true); 493 w.set_enable(true);
321 w.set_auxsrc(conf.src); 494 w.set_auxsrc(ClkAdcCtrlAuxsrc(conf.src as _));
322 }); 495 });
496 let adc_in_freq = match conf.src {
497 AdcClkSrc::PllUsb => pll_usb_freq,
498 AdcClkSrc::PllSys => pll_sys_freq,
499 AdcClkSrc::Rosc => rosc_freq,
500 AdcClkSrc::Xosc => xosc_freq,
501 // AdcClkSrc::Gpin0 => gpin0_freq,
502 // AdcClkSrc::Gpin1 => gpin1_freq,
503 };
504 assert!(adc_in_freq != 0);
505 assert!(conf.div >= 1 && conf.div <= 4);
506 CLOCKS.adc.store(adc_in_freq / conf.div as u32, Ordering::Relaxed);
323 } else { 507 } else {
324 peris.set_adc(false); 508 peris.set_adc(false);
509 CLOCKS.adc.store(0, Ordering::Relaxed);
325 } 510 }
326 511
327 if let Some(conf) = config.rtc_clk { 512 if let Some(conf) = config.rtc_clk {
328 // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz
329 c.clk_rtc_ctrl().modify(|w| {
330 w.set_enable(false);
331 });
332 c.clk_rtc_div().write(|w| { 513 c.clk_rtc_div().write(|w| {
333 w.set_int(conf.div_int); 514 w.set_int(conf.div_int);
334 w.set_frac(conf.div_frac); 515 w.set_frac(conf.div_frac);
@@ -336,17 +517,32 @@ pub(crate) unsafe fn init(config: ClockConfig) {
336 c.clk_rtc_ctrl().write(|w| { 517 c.clk_rtc_ctrl().write(|w| {
337 w.set_phase(conf.phase); 518 w.set_phase(conf.phase);
338 w.set_enable(true); 519 w.set_enable(true);
339 w.set_auxsrc(conf.src); 520 w.set_auxsrc(ClkRtcCtrlAuxsrc(conf.src as _));
340 }); 521 });
522 let rtc_in_freq = match conf.src {
523 RtcClkSrc::PllUsb => pll_usb_freq,
524 RtcClkSrc::PllSys => pll_sys_freq,
525 RtcClkSrc::Rosc => rosc_freq,
526 RtcClkSrc::Xosc => xosc_freq,
527 // RtcClkSrc::Gpin0 => gpin0_freq,
528 // RtcClkSrc::Gpin1 => gpin1_freq,
529 };
530 assert!(rtc_in_freq != 0);
531 assert!(config.sys_clk.div_int <= 0x1000000);
532 CLOCKS.rtc.store(
533 ((rtc_in_freq as u64 * 256) / (conf.div_int as u64 * 256 + conf.div_frac as u64)) as u16,
534 Ordering::Relaxed,
535 );
341 } else { 536 } else {
342 peris.set_rtc(false); 537 peris.set_rtc(false);
538 CLOCKS.rtc.store(0, Ordering::Relaxed);
343 } 539 }
344 540
345 // Peripheral clocks should now all be running 541 // Peripheral clocks should now all be running
346 reset::unreset_wait(peris); 542 reset::unreset_wait(peris);
347} 543}
348 544
349unsafe fn configure_rosc(config: RoscConfig) { 545unsafe fn configure_rosc(config: RoscConfig) -> u32 {
350 let p = pac::ROSC; 546 let p = pac::ROSC;
351 547
352 p.freqa().write(|w| { 548 p.freqa().write(|w| {
@@ -371,195 +567,57 @@ unsafe fn configure_rosc(config: RoscConfig) {
371 567
372 p.ctrl().write(|w| { 568 p.ctrl().write(|w| {
373 w.set_enable(pac::rosc::vals::Enable::ENABLE); 569 w.set_enable(pac::rosc::vals::Enable::ENABLE);
374 w.set_freq_range(config.range); 570 w.set_freq_range(pac::rosc::vals::FreqRange(config.range as u16));
375 }); 571 });
376}
377
378pub fn estimate_rosc_freq() -> u32 {
379 let p = pac::ROSC;
380 572
381 let base = match unsafe { p.ctrl().read().freq_range() } { 573 config.hz
382 pac::rosc::vals::FreqRange::LOW => 84_000_000, 574}
383 pac::rosc::vals::FreqRange::MEDIUM => 104_000_000,
384 pac::rosc::vals::FreqRange::HIGH => 140_000_000,
385 pac::rosc::vals::FreqRange::TOOHIGH => 208_000_000,
386 _ => unreachable!(),
387 };
388 let mut div = unsafe { p.div().read().0 - pac::rosc::vals::Div::PASS.0 as u32 };
389 if div == 0 {
390 div = 32
391 }
392 575
393 base / div 576pub fn rosc_freq() -> u32 {
577 CLOCKS.rosc.load(Ordering::Relaxed)
394} 578}
395 579
396pub fn xosc_freq() -> u32 { 580pub fn xosc_freq() -> u32 {
397 unsafe { XIN_HZ } 581 CLOCKS.xosc.load(Ordering::Relaxed)
398} 582}
399 583
400pub fn gpin0_freq() -> u32 { 584// pub fn gpin0_freq() -> u32 {
401 todo!() 585// CLOCKS.gpin0.load(Ordering::Relaxed)
402} 586// }
403pub fn gpin1_freq() -> u32 { 587// pub fn gpin1_freq() -> u32 {
404 todo!() 588// CLOCKS.gpin1.load(Ordering::Relaxed)
405} 589// }
406 590
407pub fn pll_sys_freq() -> u32 { 591pub fn pll_sys_freq() -> u32 {
408 let p = pac::PLL_SYS; 592 CLOCKS.pll_sys.load(Ordering::Relaxed)
409
410 let input_freq = xosc_freq();
411 let cs = unsafe { p.cs().read() };
412
413 let refdiv = cs.refdiv() as u32;
414 let fbdiv = unsafe { p.fbdiv_int().read().fbdiv_int() } as u32;
415 let (postdiv1, postdiv2) = unsafe {
416 let prim = p.prim().read();
417 (prim.postdiv1() as u32, prim.postdiv2() as u32)
418 };
419
420 (((input_freq / refdiv) * fbdiv) / postdiv1) / postdiv2
421} 593}
422 594
423pub fn pll_usb_freq() -> u32 { 595pub fn pll_usb_freq() -> u32 {
424 let p = pac::PLL_USB; 596 CLOCKS.pll_usb.load(Ordering::Relaxed)
425
426 let input_freq = xosc_freq();
427 let cs = unsafe { p.cs().read() };
428
429 let refdiv = cs.refdiv() as u32;
430 let fbdiv = unsafe { p.fbdiv_int().read().fbdiv_int() } as u32;
431 let (postdiv1, postdiv2) = unsafe {
432 let prim = p.prim().read();
433 (prim.postdiv1() as u32, prim.postdiv2() as u32)
434 };
435
436 (((input_freq / refdiv) * fbdiv) / postdiv1) / postdiv2
437} 597}
438 598
439pub fn clk_sys_freq() -> u32 { 599pub fn clk_sys_freq() -> u32 {
440 let c = pac::CLOCKS; 600 CLOCKS.sys.load(Ordering::Relaxed)
441 let ctrl = unsafe { c.clk_sys_ctrl().read() };
442
443 let base = match ctrl.src() {
444 ClkSysCtrlSrc::CLK_REF => clk_ref_freq(),
445 ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX => match ctrl.auxsrc() {
446 ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
447 ClkSysCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
448 ClkSysCtrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(),
449 ClkSysCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
450 ClkSysCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
451 ClkSysCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
452 _ => unreachable!(),
453 },
454 _ => unreachable!(),
455 };
456
457 let div = unsafe { c.clk_sys_div().read() };
458 let int = if div.int() == 0 { 65536 } else { div.int() };
459 // TODO handle fractional clock div
460 let _frac = div.frac();
461
462 base / int
463} 601}
464 602
465pub fn clk_ref_freq() -> u32 { 603pub fn clk_ref_freq() -> u32 {
466 let c = pac::CLOCKS; 604 CLOCKS.reference.load(Ordering::Relaxed)
467 let ctrl = unsafe { c.clk_ref_ctrl().read() };
468
469 let base = match ctrl.src() {
470 ClkRefCtrlSrc::ROSC_CLKSRC_PH => estimate_rosc_freq(),
471 ClkRefCtrlSrc::XOSC_CLKSRC => xosc_freq(),
472 ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX => match ctrl.auxsrc() {
473 ClkRefCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
474 ClkRefCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
475 ClkRefCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
476 _ => unreachable!(),
477 },
478 _ => unreachable!(),
479 };
480
481 let div = unsafe { c.clk_ref_div().read() };
482 let int = if div.int() == 0 { 4 } else { div.int() as u32 };
483
484 base / int
485} 605}
486 606
487pub fn clk_peri_freq() -> u32 { 607pub fn clk_peri_freq() -> u32 {
488 let c = pac::CLOCKS; 608 CLOCKS.peri.load(Ordering::Relaxed)
489 let src = unsafe { c.clk_peri_ctrl().read().auxsrc() };
490
491 match src {
492 ClkPeriCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
493 ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
494 ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
495 ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(),
496 ClkPeriCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
497 ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
498 ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
499 _ => unreachable!(),
500 }
501} 609}
502 610
503pub fn clk_usb_freq() -> u32 { 611pub fn clk_usb_freq() -> u32 {
504 let c = pac::CLOCKS; 612 CLOCKS.usb.load(Ordering::Relaxed)
505 let ctrl = unsafe { c.clk_usb_ctrl().read() };
506
507 let base = match ctrl.auxsrc() {
508 ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
509 ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
510 ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(),
511 ClkUsbCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
512 ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
513 ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
514 _ => unreachable!(),
515 };
516
517 let div = unsafe { c.clk_ref_div().read() };
518 let int = if div.int() == 0 { 4 } else { div.int() as u32 };
519
520 base / int
521} 613}
522 614
523pub fn clk_adc_freq() -> u32 { 615pub fn clk_adc_freq() -> u32 {
524 let c = pac::CLOCKS; 616 CLOCKS.adc.load(Ordering::Relaxed)
525 let ctrl = unsafe { c.clk_adc_ctrl().read() };
526
527 let base = match ctrl.auxsrc() {
528 ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
529 ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
530 ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(),
531 ClkAdcCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
532 ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
533 ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
534 _ => unreachable!(),
535 };
536
537 let div = unsafe { c.clk_adc_div().read() };
538 let int = if div.int() == 0 { 4 } else { div.int() as u32 };
539
540 base / int
541} 617}
542 618
543pub fn clk_rtc_freq() -> u32 { 619pub fn clk_rtc_freq() -> u16 {
544 let c = pac::CLOCKS; 620 CLOCKS.rtc.load(Ordering::Relaxed)
545 let src = unsafe { c.clk_rtc_ctrl().read().auxsrc() };
546
547 let base = match src {
548 ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
549 ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
550 ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(),
551 ClkRtcCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
552 ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
553 ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
554 _ => unreachable!(),
555 };
556
557 let div = unsafe { c.clk_rtc_div().read() };
558 let int = if div.int() == 0 { 65536 } else { div.int() };
559 // TODO handle fractional clock div
560 let _frac = div.frac();
561
562 base / int
563} 621}
564 622
565unsafe fn start_xosc(crystal_hz: u32) { 623unsafe fn start_xosc(crystal_hz: u32) {
@@ -576,72 +634,56 @@ unsafe fn start_xosc(crystal_hz: u32) {
576 while !pac::XOSC.status().read().stable() {} 634 while !pac::XOSC.status().read().stable() {}
577} 635}
578 636
579unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { 637#[inline(always)]
580 let ref_freq = input_freq / config.refdiv; 638unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
581 639 let ref_freq = input_freq / config.refdiv as u32;
582 let fbdiv = config.vco_freq / ref_freq; 640 assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
583 assert!(fbdiv >= 16 && fbdiv <= 320);
584 assert!(config.post_div1 >= 1 && config.post_div1 <= 7); 641 assert!(config.post_div1 >= 1 && config.post_div1 <= 7);
585 assert!(config.post_div2 >= 1 && config.post_div2 <= 7); 642 assert!(config.post_div2 >= 1 && config.post_div2 <= 7);
586 assert!(config.post_div2 <= config.post_div1); 643 assert!(config.refdiv >= 1 && config.refdiv <= 63);
587 assert!(ref_freq <= (config.vco_freq / 16)); 644 assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000);
588 645 let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32);
589 // do not disrupt PLL that is already correctly configured and operating 646 assert!(vco_freq >= 750_000_000 && vco_freq <= 1800_000_000);
590 let cs = p.cs().read();
591 let prim = p.prim().read();
592 if cs.lock()
593 && cs.refdiv() == config.refdiv as u8
594 && p.fbdiv_int().read().fbdiv_int() == fbdiv as u16
595 && prim.postdiv1() == config.post_div1
596 && prim.postdiv2() == config.post_div2
597 {
598 return;
599 }
600
601 // Reset it
602 let mut peris = reset::Peripherals(0);
603 match p {
604 pac::PLL_SYS => peris.set_pll_sys(true),
605 pac::PLL_USB => peris.set_pll_usb(true),
606 _ => unreachable!(),
607 }
608 reset::reset(peris);
609 reset::unreset_wait(peris);
610 647
611 // Load VCO-related dividers before starting VCO 648 // Load VCO-related dividers before starting VCO
612 p.cs().write(|w| w.set_refdiv(config.refdiv as _)); 649 p.cs().write(|w| w.set_refdiv(config.refdiv as _));
613 p.fbdiv_int().write(|w| w.set_fbdiv_int(fbdiv as _)); 650 p.fbdiv_int().write(|w| w.set_fbdiv_int(config.fbdiv));
614 651
615 // Turn on PLL 652 // Turn on PLL
616 p.pwr().modify(|w| { 653 let pwr = p.pwr().write(|w| {
654 w.set_dsmpd(true); // "nothing is achieved by setting this low"
617 w.set_pd(false); 655 w.set_pd(false);
618 w.set_vcopd(false); 656 w.set_vcopd(false);
619 w.set_postdivpd(true); 657 w.set_postdivpd(true);
658 *w
620 }); 659 });
621 660
622 // Wait for PLL to lock 661 // Wait for PLL to lock
623 while !p.cs().read().lock() {} 662 while !p.cs().read().lock() {}
624 663
625 // Wait for PLL to lock 664 // Set post-dividers
626 p.prim().write(|w| { 665 p.prim().write(|w| {
627 w.set_postdiv1(config.post_div1); 666 w.set_postdiv1(config.post_div1);
628 w.set_postdiv2(config.post_div2); 667 w.set_postdiv2(config.post_div2);
629 }); 668 });
630 669
631 // Turn on post divider 670 // Turn on post divider
632 p.pwr().modify(|w| w.set_postdivpd(false)); 671 p.pwr().write(|w| {
672 *w = pwr;
673 w.set_postdivpd(false);
674 });
675
676 vco_freq / ((config.post_div1 * config.post_div2) as u32)
633} 677}
634 678
635pub trait GpinPin: crate::gpio::Pin { 679pub trait GpinPin: crate::gpio::Pin {
636 fn number(&self) -> usize; 680 const NR: usize;
637} 681}
638 682
639macro_rules! impl_gpinpin { 683macro_rules! impl_gpinpin {
640 ($name:ident, $pin_num:expr, $gpin_num:expr) => { 684 ($name:ident, $pin_num:expr, $gpin_num:expr) => {
641 impl GpinPin for crate::peripherals::$name { 685 impl GpinPin for crate::peripherals::$name {
642 fn number(&self) -> usize { 686 const NR: usize = $gpin_num;
643 $gpin_num
644 }
645 } 687 }
646 }; 688 };
647} 689}
@@ -649,23 +691,31 @@ macro_rules! impl_gpinpin {
649impl_gpinpin!(PIN_20, 20, 0); 691impl_gpinpin!(PIN_20, 20, 0);
650impl_gpinpin!(PIN_22, 22, 1); 692impl_gpinpin!(PIN_22, 22, 1);
651 693
652pub struct Gpin<'d, T: GpinPin> { 694pub struct Gpin<'d, T: Pin> {
653 gpin: PeripheralRef<'d, T>, 695 gpin: PeripheralRef<'d, AnyPin>,
696 _phantom: PhantomData<T>,
654} 697}
655 698
656impl<'d, T: GpinPin> Gpin<'d, T> { 699impl<'d, T: Pin> Gpin<'d, T> {
657 pub fn new(gpin: impl Peripheral<P = T> + 'd) -> Self { 700 pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> {
658 into_ref!(gpin); 701 into_ref!(gpin);
659 702
660 unsafe { 703 unsafe {
661 gpin.io().ctrl().write(|w| w.set_funcsel(0x08)); 704 gpin.io().ctrl().write(|w| w.set_funcsel(0x08));
662 } 705 }
663 706
664 Self { gpin } 707 Gpin {
708 gpin: gpin.map_into(),
709 _phantom: PhantomData,
710 }
665 } 711 }
712
713 // fn map_into(self) -> Gpin<'d, AnyPin> {
714 // unsafe { core::mem::transmute(self) }
715 // }
666} 716}
667 717
668impl<'d, T: GpinPin> Drop for Gpin<'d, T> { 718impl<'d, T: Pin> Drop for Gpin<'d, T> {
669 fn drop(&mut self) { 719 fn drop(&mut self) {
670 unsafe { 720 unsafe {
671 self.gpin 721 self.gpin
@@ -695,6 +745,21 @@ impl_gpoutpin!(PIN_23, 1);
695impl_gpoutpin!(PIN_24, 2); 745impl_gpoutpin!(PIN_24, 2);
696impl_gpoutpin!(PIN_25, 3); 746impl_gpoutpin!(PIN_25, 3);
697 747
748#[repr(u8)]
749pub enum GpoutSrc {
750 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS.0,
751 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0.0,
752 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1.0,
753 PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB.0,
754 Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC.0,
755 Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC.0,
756 Sys = ClkGpoutCtrlAuxsrc::CLK_SYS.0,
757 Usb = ClkGpoutCtrlAuxsrc::CLK_USB.0,
758 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC.0,
759 Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC.0,
760 Ref = ClkGpoutCtrlAuxsrc::CLK_REF.0,
761}
762
698pub struct Gpout<'d, T: GpoutPin> { 763pub struct Gpout<'d, T: GpoutPin> {
699 gpout: PeripheralRef<'d, T>, 764 gpout: PeripheralRef<'d, T>,
700} 765}
@@ -720,11 +785,11 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
720 } 785 }
721 } 786 }
722 787
723 pub fn set_src(&self, src: ClkGpoutCtrlAuxsrc) { 788 pub fn set_src(&self, src: GpoutSrc) {
724 unsafe { 789 unsafe {
725 let c = pac::CLOCKS; 790 let c = pac::CLOCKS;
726 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 791 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
727 w.set_auxsrc(src); 792 w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _));
728 }); 793 });
729 } 794 }
730 } 795 }
@@ -753,25 +818,24 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
753 818
754 let base = match src { 819 let base = match src {
755 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), 820 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
756 ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), 821 // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
757 ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), 822 // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
758 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), 823 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
759 ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(), 824 ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => rosc_freq(),
760 ClkGpoutCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(), 825 ClkGpoutCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),
761 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(), 826 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
762 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(), 827 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(),
763 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(), 828 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(),
764 ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq(), 829 ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _,
765 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(), 830 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(),
766 _ => unreachable!(), 831 _ => unreachable!(),
767 }; 832 };
768 833
769 let div = unsafe { c.clk_gpout_div(self.gpout.number()).read() }; 834 let div = unsafe { c.clk_gpout_div(self.gpout.number()).read() };
770 let int = if div.int() == 0 { 65536 } else { div.int() }; 835 let int = if div.int() == 0 { 65536 } else { div.int() } as u64;
771 // TODO handle fractional clock div 836 let frac = div.frac() as u64;
772 let _frac = div.frac();
773 837
774 base / int 838 ((base as u64 * 256) / (int * 256 + frac)) as u32
775 } 839 }
776} 840}
777 841
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.
diff --git a/examples/rp/src/bin/gpout.rs b/examples/rp/src/bin/gpout.rs
index 236a653ac..64461fc5f 100644
--- a/examples/rp/src/bin/gpout.rs
+++ b/examples/rp/src/bin/gpout.rs
@@ -17,14 +17,14 @@ async fn main(_spawner: Spawner) {
17 gpout3.enable(); 17 gpout3.enable();
18 18
19 loop { 19 loop {
20 gpout3.set_src(clocks::GpoutSrc::CLK_SYS); 20 gpout3.set_src(clocks::GpoutSrc::Sys);
21 info!( 21 info!(
22 "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}", 22 "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}",
23 gpout3.get_freq() 23 gpout3.get_freq()
24 ); 24 );
25 Timer::after(Duration::from_secs(2)).await; 25 Timer::after(Duration::from_secs(2)).await;
26 26
27 gpout3.set_src(clocks::GpoutSrc::CLK_REF); 27 gpout3.set_src(clocks::GpoutSrc::Ref);
28 info!( 28 info!(
29 "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}", 29 "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}",
30 gpout3.get_freq() 30 gpout3.get_freq()