diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2023-05-17 22:20:44 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-05-17 22:20:44 +0000 |
| commit | 4b303949bff82cb328b75e37e9e03038d8d0e778 (patch) | |
| tree | 4e06a78cf075a26aedf7cc3edde8840468d1cd5d | |
| parent | 908ec5faef00345c680a3e6e64b30f107f2cd26f (diff) | |
| parent | fc746a88b50f2d57a573d7a9ec8b8f3fbc0c9b08 (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.rs | 722 | ||||
| -rw-r--r-- | embassy-rp/src/rtc/mod.rs | 7 | ||||
| -rw-r--r-- | examples/rp/src/bin/gpout.rs | 4 |
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 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; | ||
| 3 | |||
| 1 | use embassy_hal_common::{into_ref, PeripheralRef}; | 4 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 2 | use pac::clocks::vals::*; | 5 | use pac::clocks::vals::*; |
| 3 | 6 | ||
| 7 | use crate::gpio::sealed::Pin; | ||
| 8 | use crate::gpio::AnyPin; | ||
| 4 | use crate::{pac, reset, Peripheral}; | 9 | use 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. |
| 7 | static 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 | |
| 9 | pub 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, | 15 | struct 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 | |||
| 30 | static 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)] | ||
| 48 | pub 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] |
| 16 | pub struct ClockConfig { | 59 | pub 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 | ||
| 27 | impl ClockConfig { | 72 | impl 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)] | ||
| 182 | pub 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 | ||
| 114 | pub struct RoscConfig { | 189 | pub 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 | ||
| 120 | pub struct XoscConfig { | 200 | pub 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 | ||
| 127 | pub struct PllConfig { | 206 | pub 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 | ||
| 134 | pub enum ExternalClock { | ||
| 135 | Crystal, | ||
| 136 | Clock, | ||
| 137 | } | ||
| 138 | pub struct RefClkConfig { | 213 | pub 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)] | ||
| 143 | pub enum RefClkSrc { | 220 | pub 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)] | ||
| 149 | pub enum SysClkSrc { | 232 | pub 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 | ||
| 154 | pub struct SysClkConfig { | 244 | pub 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)] | ||
| 253 | pub 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 | |||
| 160 | pub struct UsbClkConfig { | 262 | pub 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)] | ||
| 271 | pub 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 | |||
| 166 | pub struct AdcClkConfig { | 280 | pub 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)] | ||
| 289 | pub 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 | |||
| 172 | pub struct RtcClkConfig { | 298 | pub 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 | ||
| 349 | unsafe fn configure_rosc(config: RoscConfig) { | 545 | unsafe 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 | |||
| 378 | pub 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 | 576 | pub fn rosc_freq() -> u32 { |
| 577 | CLOCKS.rosc.load(Ordering::Relaxed) | ||
| 394 | } | 578 | } |
| 395 | 579 | ||
| 396 | pub fn xosc_freq() -> u32 { | 580 | pub fn xosc_freq() -> u32 { |
| 397 | unsafe { XIN_HZ } | 581 | CLOCKS.xosc.load(Ordering::Relaxed) |
| 398 | } | 582 | } |
| 399 | 583 | ||
| 400 | pub fn gpin0_freq() -> u32 { | 584 | // pub fn gpin0_freq() -> u32 { |
| 401 | todo!() | 585 | // CLOCKS.gpin0.load(Ordering::Relaxed) |
| 402 | } | 586 | // } |
| 403 | pub fn gpin1_freq() -> u32 { | 587 | // pub fn gpin1_freq() -> u32 { |
| 404 | todo!() | 588 | // CLOCKS.gpin1.load(Ordering::Relaxed) |
| 405 | } | 589 | // } |
| 406 | 590 | ||
| 407 | pub fn pll_sys_freq() -> u32 { | 591 | pub 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 | ||
| 423 | pub fn pll_usb_freq() -> u32 { | 595 | pub 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 | ||
| 439 | pub fn clk_sys_freq() -> u32 { | 599 | pub 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 | ||
| 465 | pub fn clk_ref_freq() -> u32 { | 603 | pub 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 | ||
| 487 | pub fn clk_peri_freq() -> u32 { | 607 | pub 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 | ||
| 503 | pub fn clk_usb_freq() -> u32 { | 611 | pub 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 | ||
| 523 | pub fn clk_adc_freq() -> u32 { | 615 | pub 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 | ||
| 543 | pub fn clk_rtc_freq() -> u32 { | 619 | pub 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 | ||
| 565 | unsafe fn start_xosc(crystal_hz: u32) { | 623 | unsafe 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 | ||
| 579 | unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { | 637 | #[inline(always)] |
| 580 | let ref_freq = input_freq / config.refdiv; | 638 | unsafe 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 | ||
| 635 | pub trait GpinPin: crate::gpio::Pin { | 679 | pub trait GpinPin: crate::gpio::Pin { |
| 636 | fn number(&self) -> usize; | 680 | const NR: usize; |
| 637 | } | 681 | } |
| 638 | 682 | ||
| 639 | macro_rules! impl_gpinpin { | 683 | macro_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 { | |||
| 649 | impl_gpinpin!(PIN_20, 20, 0); | 691 | impl_gpinpin!(PIN_20, 20, 0); |
| 650 | impl_gpinpin!(PIN_22, 22, 1); | 692 | impl_gpinpin!(PIN_22, 22, 1); |
| 651 | 693 | ||
| 652 | pub struct Gpin<'d, T: GpinPin> { | 694 | pub struct Gpin<'d, T: Pin> { |
| 653 | gpin: PeripheralRef<'d, T>, | 695 | gpin: PeripheralRef<'d, AnyPin>, |
| 696 | _phantom: PhantomData<T>, | ||
| 654 | } | 697 | } |
| 655 | 698 | ||
| 656 | impl<'d, T: GpinPin> Gpin<'d, T> { | 699 | impl<'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 | ||
| 668 | impl<'d, T: GpinPin> Drop for Gpin<'d, T> { | 718 | impl<'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); | |||
| 695 | impl_gpoutpin!(PIN_24, 2); | 745 | impl_gpoutpin!(PIN_24, 2); |
| 696 | impl_gpoutpin!(PIN_25, 3); | 746 | impl_gpoutpin!(PIN_25, 3); |
| 697 | 747 | ||
| 748 | #[repr(u8)] | ||
| 749 | pub 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 | |||
| 698 | pub struct Gpout<'d, T: GpoutPin> { | 763 | pub 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() |
