aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/src/clocks.rs241
1 files changed, 147 insertions, 94 deletions
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 5d3444442..def34fc70 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -6,32 +6,25 @@ use crate::{pac, reset};
6static mut XIN_HZ: u32 = 0; 6static mut XIN_HZ: u32 = 0;
7 7
8pub struct ClockConfig { 8pub struct ClockConfig {
9 rosc_config: Option<RoscConfig>, 9 rosc: Option<RoscConfig>,
10 xosc_config: Option<XoscConfig>, 10 xosc: Option<XoscConfig>,
11 ref_clk_config: (RefClkSrc, u8), 11 ref_clk: RefClkConfig,
12 sys_clk_config: (SysClkSrc, u32), 12 sys_clk: SysClkConfig,
13 peri_clk_src: Option<ClkPeriCtrlAuxsrc>, 13 peri_clk_src: Option<ClkPeriCtrlAuxsrc>,
14 usb_clk_config: Option<(ClkUsbCtrlAuxsrc, u8)>, 14 usb_clk: Option<UsbClkConfig>,
15 adc_clk_config: Option<(ClkAdcCtrlAuxsrc, u8)>, 15 adc_clk: Option<AdcClkConfig>,
16 rtc_clk_config: Option<(ClkRtcCtrlAuxsrc, u32)>, 16 rtc_clk: Option<RtcClkConfig>,
17} 17}
18 18
19impl ClockConfig { 19impl ClockConfig {
20 pub fn crystal(crystal_hz: u32) -> Self { 20 pub fn crystal(crystal_hz: u32) -> Self {
21 Self { 21 Self {
22 rosc_config: Some(RoscConfig { 22 rosc: Some(RoscConfig {
23 range: pac::rosc::vals::FreqRange::MEDIUM, 23 range: pac::rosc::vals::FreqRange::MEDIUM,
24 drive_strength_0: 0, 24 drive_strength: [0; 8],
25 drive_strength_1: 0,
26 drive_strength_2: 0,
27 drive_strength_3: 0,
28 drive_strength_4: 0,
29 drive_strength_5: 0,
30 drive_strength_6: 0,
31 drive_strength_7: 0,
32 div: 16, 25 div: 16,
33 }), 26 }),
34 xosc_config: Some(XoscConfig { 27 xosc: Some(XoscConfig {
35 hz: crystal_hz, 28 hz: crystal_hz,
36 clock_type: ExternalClock::Crystal, 29 clock_type: ExternalClock::Crystal,
37 sys_pll: Some(PllConfig { 30 sys_pll: Some(PllConfig {
@@ -47,42 +40,68 @@ impl ClockConfig {
47 post_div2: 2, 40 post_div2: 2,
48 }), 41 }),
49 }), 42 }),
50 ref_clk_config: (RefClkSrc::Xosc, 1), 43 ref_clk: RefClkConfig {
51 sys_clk_config: (SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS), 1), 44 src: RefClkSrc::Xosc,
45 div: 1,
46 },
47 sys_clk: SysClkConfig {
48 src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS),
49 div_int: 1,
50 div_frac: 0,
51 },
52 peri_clk_src: Some(ClkPeriCtrlAuxsrc::CLK_SYS), 52 peri_clk_src: Some(ClkPeriCtrlAuxsrc::CLK_SYS),
53 usb_clk_config: Some((ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB, 1)), 53 usb_clk: Some(UsbClkConfig {
54 adc_clk_config: Some((ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB, 1)), 54 src: ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB,
55 rtc_clk_config: Some((ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB, 1024)), 55 div: 1,
56 }),
57 adc_clk: Some(AdcClkConfig {
58 src: ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB,
59 div: 1,
60 }),
61 rtc_clk: Some(RtcClkConfig {
62 src: ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB,
63 div_int: 1024,
64 div_frac: 0,
65 }),
56 } 66 }
57 } 67 }
58 68
59 pub fn rosc() -> Self { 69 pub fn rosc() -> Self {
60 Self { 70 Self {
61 rosc_config: Some(RoscConfig { 71 rosc: Some(RoscConfig {
62 range: pac::rosc::vals::FreqRange::HIGH, 72 range: pac::rosc::vals::FreqRange::HIGH,
63 drive_strength_0: 0, 73 drive_strength: [0; 8],
64 drive_strength_1: 0,
65 drive_strength_2: 0,
66 drive_strength_3: 0,
67 drive_strength_4: 0,
68 drive_strength_5: 0,
69 drive_strength_6: 0,
70 drive_strength_7: 0,
71 div: 1, 74 div: 1,
72 }), 75 }),
73 xosc_config: None, 76 xosc: None,
74 ref_clk_config: (RefClkSrc::Rosc, 4), 77 ref_clk: RefClkConfig {
75 sys_clk_config: (SysClkSrc::Aux(ClkSysCtrlAuxsrc::ROSC_CLKSRC), 1), 78 src: RefClkSrc::Rosc,
79 div: 1,
80 },
81 sys_clk: SysClkConfig {
82 src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::ROSC_CLKSRC),
83 div_int: 1,
84 div_frac: 0,
85 },
76 peri_clk_src: Some(ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH), 86 peri_clk_src: Some(ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH),
77 usb_clk_config: None, 87 usb_clk: None,
78 adc_clk_config: Some((ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH, 1)), 88 adc_clk: Some(AdcClkConfig {
79 rtc_clk_config: Some((ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH, 1024)), 89 src: ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH,
90 div: 1,
91 }),
92 rtc_clk: Some(RtcClkConfig {
93 src: ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH,
94 div_int: 1024,
95 div_frac: 0,
96 }),
80 } 97 }
81 } 98 }
82} 99}
83pub enum ExternalClock { 100
84 Crystal, 101pub struct RoscConfig {
85 Clock, 102 range: pac::rosc::vals::FreqRange,
103 drive_strength: [u8; 8],
104 div: u16,
86} 105}
87 106
88pub struct XoscConfig { 107pub struct XoscConfig {
@@ -92,19 +111,6 @@ pub struct XoscConfig {
92 usb_pll: Option<PllConfig>, 111 usb_pll: Option<PllConfig>,
93} 112}
94 113
95pub struct RoscConfig {
96 range: pac::rosc::vals::FreqRange,
97 drive_strength_0: u8,
98 drive_strength_1: u8,
99 drive_strength_2: u8,
100 drive_strength_3: u8,
101 drive_strength_4: u8,
102 drive_strength_5: u8,
103 drive_strength_6: u8,
104 drive_strength_7: u8,
105 div: u16,
106}
107
108pub struct PllConfig { 114pub struct PllConfig {
109 pub refdiv: u32, 115 pub refdiv: u32,
110 pub vco_freq: u32, 116 pub vco_freq: u32,
@@ -112,9 +118,13 @@ pub struct PllConfig {
112 pub post_div2: u8, 118 pub post_div2: u8,
113} 119}
114 120
121pub enum ExternalClock {
122 Crystal,
123 Clock,
124}
115pub struct RefClkConfig { 125pub struct RefClkConfig {
116 pub src: RefClkSrc, 126 src: RefClkSrc,
117 pub div: u8, 127 div: u8,
118} 128}
119 129
120pub enum RefClkSrc { 130pub enum RefClkSrc {
@@ -123,16 +133,33 @@ pub enum RefClkSrc {
123 Aux(ClkRefCtrlAuxsrc), 133 Aux(ClkRefCtrlAuxsrc),
124} 134}
125 135
126pub struct SysClkConfig {
127 pub src: SysClkSrc,
128 pub div: u32,
129}
130
131pub enum SysClkSrc { 136pub enum SysClkSrc {
132 Ref, 137 Ref,
133 Aux(ClkSysCtrlAuxsrc), 138 Aux(ClkSysCtrlAuxsrc),
134} 139}
135 140
141pub struct SysClkConfig {
142 src: SysClkSrc,
143 div_int: u32,
144 div_frac: u8,
145}
146
147pub struct UsbClkConfig {
148 src: ClkUsbCtrlAuxsrc,
149 div: u8,
150}
151
152pub struct AdcClkConfig {
153 src: ClkAdcCtrlAuxsrc,
154 div: u8,
155}
156
157pub struct RtcClkConfig {
158 src: ClkRtcCtrlAuxsrc,
159 div_int: u32,
160 div_frac: u8,
161}
162
136/// safety: must be called exactly once at bootup 163/// safety: must be called exactly once at bootup
137pub(crate) unsafe fn init(config: ClockConfig) { 164pub(crate) unsafe fn init(config: ClockConfig) {
138 // Reset everything except: 165 // Reset everything except:
@@ -160,11 +187,11 @@ pub(crate) unsafe fn init(config: ClockConfig) {
160 c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH)); 187 c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH));
161 while c.clk_ref_selected().read() != 1 {} 188 while c.clk_ref_selected().read() != 1 {}
162 189
163 if let Some(config) = config.rosc_config { 190 if let Some(config) = config.rosc {
164 configure_rosc(config); 191 configure_rosc(config);
165 } 192 }
166 193
167 if let Some(config) = config.xosc_config { 194 if let Some(config) = config.xosc {
168 XIN_HZ = config.hz; 195 XIN_HZ = config.hz;
169 196
170 pac::WATCHDOG.tick().write(|w| { 197 pac::WATCHDOG.tick().write(|w| {
@@ -188,21 +215,18 @@ pub(crate) unsafe fn init(config: ClockConfig) {
188 } 215 }
189 } 216 }
190 217
191 let (src, div) = config.ref_clk_config; 218 match config.ref_clk.src {
192 match src {
193 RefClkSrc::Xosc => { 219 RefClkSrc::Xosc => {
194 c.clk_ref_ctrl().write(|w| { 220 c.clk_ref_ctrl().write(|w| {
195 w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC); 221 w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC);
196 }); 222 });
197 while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::XOSC_CLKSRC.0 {} 223 while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::XOSC_CLKSRC.0 {}
198 c.clk_ref_div().write(|w| w.set_int(div));
199 } 224 }
200 RefClkSrc::Rosc => { 225 RefClkSrc::Rosc => {
201 c.clk_ref_ctrl().write(|w| { 226 c.clk_ref_ctrl().write(|w| {
202 w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH); 227 w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH);
203 }); 228 });
204 while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::ROSC_CLKSRC_PH.0 {} 229 while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::ROSC_CLKSRC_PH.0 {}
205 c.clk_ref_div().write(|w| w.set_int(div));
206 } 230 }
207 RefClkSrc::Aux(src) => { 231 RefClkSrc::Aux(src) => {
208 c.clk_ref_ctrl().write(|w| { 232 c.clk_ref_ctrl().write(|w| {
@@ -210,23 +234,23 @@ pub(crate) unsafe fn init(config: ClockConfig) {
210 w.set_src(ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX); 234 w.set_src(ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX);
211 }); 235 });
212 while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX.0 {} 236 while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX.0 {}
213 c.clk_ref_div().write(|w| w.set_int(div));
214 } 237 }
215 } 238 }
239 c.clk_ref_div().write(|w| {
240 w.set_int(config.ref_clk.div);
241 });
216 242
217 pac::WATCHDOG.tick().write(|w| { 243 pac::WATCHDOG.tick().write(|w| {
218 w.set_cycles((clk_ref_freq() / 1_000_000) as u16); 244 w.set_cycles((clk_ref_freq() / 1_000_000) as u16);
219 w.set_enable(true); 245 w.set_enable(true);
220 }); 246 });
221 247
222 let (src, div) = config.sys_clk_config; 248 match config.sys_clk.src {
223 match src {
224 SysClkSrc::Ref => { 249 SysClkSrc::Ref => {
225 c.clk_sys_ctrl().write(|w| { 250 c.clk_sys_ctrl().write(|w| {
226 w.set_src(ClkSysCtrlSrc::CLK_REF); 251 w.set_src(ClkSysCtrlSrc::CLK_REF);
227 }); 252 });
228 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} 253 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {}
229 c.clk_sys_div().write(|w| w.set_int(div));
230 } 254 }
231 SysClkSrc::Aux(src) => { 255 SysClkSrc::Aux(src) => {
232 c.clk_sys_ctrl().write(|w| { 256 c.clk_sys_ctrl().write(|w| {
@@ -234,7 +258,6 @@ pub(crate) unsafe fn init(config: ClockConfig) {
234 }); 258 });
235 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} 259 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {}
236 260
237 c.clk_sys_div().write(|w| w.set_int(div));
238 c.clk_sys_ctrl().write(|w| { 261 c.clk_sys_ctrl().write(|w| {
239 w.set_auxsrc(src); 262 w.set_auxsrc(src);
240 w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); 263 w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX);
@@ -242,6 +265,10 @@ pub(crate) unsafe fn init(config: ClockConfig) {
242 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX.0 {} 265 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX.0 {}
243 } 266 }
244 } 267 }
268 c.clk_sys_div().write(|w| {
269 w.set_int(config.sys_clk.div_int);
270 w.set_frac(config.sys_clk.div_frac);
271 });
245 272
246 let mut peris = reset::ALL_PERIPHERALS; 273 let mut peris = reset::ALL_PERIPHERALS;
247 274
@@ -257,37 +284,40 @@ pub(crate) unsafe fn init(config: ClockConfig) {
257 peris.set_uart1(false); 284 peris.set_uart1(false);
258 } 285 }
259 286
260 if let Some((src, div)) = config.usb_clk_config { 287 if let Some(conf) = config.usb_clk {
261 // CLK USB = PLL USB (48MHz) / 1 = 48MHz 288 // CLK USB = PLL USB (48MHz) / 1 = 48MHz
262 c.clk_usb_div().write(|w| w.set_int(div)); 289 c.clk_usb_div().write(|w| w.set_int(conf.div));
263 c.clk_usb_ctrl().write(|w| { 290 c.clk_usb_ctrl().write(|w| {
264 w.set_enable(true); 291 w.set_enable(true);
265 w.set_auxsrc(src); 292 w.set_auxsrc(conf.src);
266 }); 293 });
267 } else { 294 } else {
268 peris.set_usbctrl(false); 295 peris.set_usbctrl(false);
269 } 296 }
270 297
271 if let Some((src, div)) = config.adc_clk_config { 298 if let Some(conf) = config.adc_clk {
272 // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz 299 // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz
273 c.clk_adc_div().write(|w| w.set_int(div)); 300 c.clk_adc_div().write(|w| w.set_int(conf.div));
274 c.clk_adc_ctrl().write(|w| { 301 c.clk_adc_ctrl().write(|w| {
275 w.set_enable(true); 302 w.set_enable(true);
276 w.set_auxsrc(src); 303 w.set_auxsrc(conf.src);
277 }); 304 });
278 } else { 305 } else {
279 peris.set_adc(false); 306 peris.set_adc(false);
280 } 307 }
281 308
282 if let Some((src, div)) = config.rtc_clk_config { 309 if let Some(conf) = config.rtc_clk {
283 // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz 310 // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz
284 c.clk_rtc_ctrl().modify(|w| { 311 c.clk_rtc_ctrl().modify(|w| {
285 w.set_enable(false); 312 w.set_enable(false);
286 }); 313 });
287 c.clk_rtc_div().write(|w| w.set_int(div)); 314 c.clk_rtc_div().write(|w| {
315 w.set_int(conf.div_int);
316 w.set_frac(conf.div_frac);
317 });
288 c.clk_rtc_ctrl().write(|w| { 318 c.clk_rtc_ctrl().write(|w| {
289 w.set_enable(true); 319 w.set_enable(true);
290 w.set_auxsrc(src); 320 w.set_auxsrc(conf.src);
291 }); 321 });
292 } else { 322 } else {
293 peris.set_rtc(false); 323 peris.set_rtc(false);
@@ -302,18 +332,18 @@ unsafe fn configure_rosc(config: RoscConfig) {
302 332
303 p.freqa().write(|w| { 333 p.freqa().write(|w| {
304 w.set_passwd(pac::rosc::vals::Passwd::PASS); 334 w.set_passwd(pac::rosc::vals::Passwd::PASS);
305 w.set_ds0(config.drive_strength_0); 335 w.set_ds0(config.drive_strength[0]);
306 w.set_ds1(config.drive_strength_1); 336 w.set_ds1(config.drive_strength[1]);
307 w.set_ds2(config.drive_strength_2); 337 w.set_ds2(config.drive_strength[2]);
308 w.set_ds3(config.drive_strength_3); 338 w.set_ds3(config.drive_strength[3]);
309 }); 339 });
310 340
311 p.freqb().write(|w| { 341 p.freqb().write(|w| {
312 w.set_passwd(pac::rosc::vals::Passwd::PASS); 342 w.set_passwd(pac::rosc::vals::Passwd::PASS);
313 w.set_ds4(config.drive_strength_4); 343 w.set_ds4(config.drive_strength[4]);
314 w.set_ds5(config.drive_strength_5); 344 w.set_ds5(config.drive_strength[5]);
315 w.set_ds6(config.drive_strength_6); 345 w.set_ds6(config.drive_strength[6]);
316 w.set_ds7(config.drive_strength_7); 346 w.set_ds7(config.drive_strength[7]);
317 }); 347 });
318 348
319 p.div().write(|w| { 349 p.div().write(|w| {
@@ -637,17 +667,31 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) {
637 p.pwr().modify(|w| w.set_postdivpd(false)); 667 p.pwr().modify(|w| w.set_postdivpd(false));
638} 668}
639 669
640pub struct Gpout0 { 670pub trait GpoutPin {}
641 _pin: crate::peripherals::PIN_21, 671
672impl GpoutPin for crate::peripherals::PIN_21 {}
673impl GpoutPin for crate::peripherals::PIN_23 {}
674impl GpoutPin for crate::peripherals::PIN_24 {}
675impl GpoutPin for crate::peripherals::PIN_25 {}
676
677use embassy_hal_common::{into_ref, PeripheralRef};
678
679use crate::Peripheral;
680
681pub struct Gpout<'d, T: GpoutPin> {
682 _pin: PeripheralRef<'d, T>,
642} 683}
643 684
644impl Gpout0 { 685impl<'d, T: GpoutPin> Gpout<'d, T> {
645 pub fn new(pin: crate::peripherals::PIN_21) -> Self { 686 pub fn new(_pin: impl Peripheral<P = T> + 'd) -> Self {
687 into_ref!(_pin);
688
646 unsafe { 689 unsafe {
647 let p = pac::IO_BANK0.gpio(21).ctrl(); 690 let p = pac::IO_BANK0.gpio(21).ctrl();
648 p.write(|w| w.set_funcsel(pac::io::vals::Gpio21ctrlFuncsel::CLOCKS_GPOUT_0.0)) 691 p.write(|w| w.set_funcsel(pac::io::vals::Gpio21ctrlFuncsel::CLOCKS_GPOUT_0.0));
649 } 692 }
650 Self { _pin: pin } 693
694 Self { _pin }
651 } 695 }
652 696
653 pub fn set_div(&self, int: u32, frac: u8) { 697 pub fn set_div(&self, int: u32, frac: u8) {
@@ -677,6 +721,15 @@ impl Gpout0 {
677 }); 721 });
678 } 722 }
679 } 723 }
724
725 pub fn disable(&self) {
726 unsafe {
727 let c = pac::CLOCKS;
728 c.clk_gpout0_ctrl().modify(|w| {
729 w.set_enable(true);
730 });
731 }
732 }
680} 733}
681 734
682/// Random number generator based on the ROSC RANDOMBIT register. 735/// Random number generator based on the ROSC RANDOMBIT register.