atsamd_hal/peripherals/clock/d5x/
v1.rs

1//! # Clocking API v1
2//!
3//! Configuring the system clock sources. You will typically need to create an
4//! instance of `GenericClockController` before you can set up most of the
5//! peripherals on the atsamd51 device. The other types in this module are used
6//! to enforce at compile time that the peripherals have been correctly
7//! configured.
8#![allow(clippy::from_over_into)]
9
10use atsamd_hal_macros::hal_macro_helper;
11
12use fugit::RateExtU32;
13
14use crate::clock::v2::pclk::{Pclk, PclkSourceId, ids::*};
15use crate::pac::gclk::genctrl::Srcselect::*;
16use crate::pac::gclk::pchctrl::Genselect::*;
17use crate::pac::{self, Gclk, Mclk, Nvmctrl, Osc32kctrl, Oscctrl};
18use crate::sercom::*;
19use crate::time::Hertz;
20
21pub type ClockGenId = pac::gclk::pchctrl::Genselect;
22pub type ClockSource = pac::gclk::genctrl::Srcselect;
23
24#[allow(non_camel_case_types)]
25pub enum ClockId {
26    DFLL48 = 0,
27    FDPLL0,
28    FDPLL1,
29    SLOW_32K,
30    EIC,
31    FREQM_MSR,
32    FREQM_REF,
33    SERCOM0_CORE,
34    SERCOM1_CORE,
35    TC0_TC1,
36    USB,
37    EVSYS0,
38    EVSYS1,
39    EVSYS2,
40    EVSYS3,
41    EVSYS4,
42    EVSYS5,
43    EVSYS6,
44    EVSYS7,
45    EVSYS8,
46    EVSYS9,
47    EVSYS10,
48    EVSYS11,
49    SERCOM2_CORE,
50    SERCOM3_CORE,
51    TCC0_TCC1,
52    TC2_TC3,
53    CAN0,
54    CAN1,
55    TCC2_TCC3,
56    TC4_TC5,
57    PDEC,
58    AC,
59    CCL,
60    SERCOM4_CORE,
61    SERCOM5_CORE,
62    SERCOM6_CORE,
63    SERCOM7_CORE,
64    TCC4,
65    TC6_TC7,
66    ADC0,
67    ADC1,
68    DAC,
69    I2S0,
70    I2S1,
71    SDHC0,
72    SDHC1,
73    CM4_TRACE,
74}
75
76impl From<ClockId> for u8 {
77    fn from(clock: ClockId) -> u8 {
78        clock as u8
79    }
80}
81
82/// Represents a configured clock generator.
83///
84/// Can be converted into the effective clock frequency.
85/// Its primary purpose is to be passed in to methods
86/// such as `GenericClockController::tcc2_tc3` to configure
87/// the clock for a peripheral.
88//#[derive(Clone, Copy)]
89pub struct GClock {
90    gclk: ClockGenId,
91    freq: Hertz,
92}
93
94impl Into<Hertz> for GClock {
95    fn into(self) -> Hertz {
96        self.freq
97    }
98}
99
100struct State {
101    gclk: Gclk,
102}
103
104impl State {
105    fn reset_gclk(&mut self) {
106        self.gclk.ctrla().write(|w| w.swrst().set_bit());
107        while self.gclk.ctrla().read().swrst().bit_is_set()
108            || self.gclk.syncbusy().read().bits() != 0
109        {}
110    }
111
112    fn wait_for_sync(&mut self) {
113        while self.gclk.syncbusy().read().bits() != 0 {}
114    }
115
116    fn set_gclk_divider_and_source(
117        &mut self,
118        gclk: ClockGenId,
119        divider: u16,
120        src: ClockSource,
121        improve_duty_cycle: bool,
122    ) {
123        // validate the divisor factor based on gclk ID (see 14.8.3)
124        let mut divisor_invalid = false;
125        if gclk == Gclk1 {
126            if divider as u32 >= 2_u32.pow(16) {
127                divisor_invalid = true;
128            }
129        } else if divider >= 2_u16.pow(8) {
130            divisor_invalid = true;
131        }
132        if divisor_invalid {
133            panic!("invalid divisor {} for Gclk {}", divider, gclk as u8);
134        }
135
136        self.gclk
137            .genctrl(u8::from(gclk) as usize)
138            .write(|w| unsafe {
139                w.src().variant(src);
140                w.div().bits(divider);
141                // divide directly by divider, rather than 2^(n+1)
142                w.divsel().clear_bit();
143                w.idc().bit(improve_duty_cycle);
144                w.genen().set_bit();
145                w.oe().set_bit()
146            });
147
148        self.wait_for_sync();
149    }
150
151    fn enable_clock_generator(&mut self, clock: ClockId, generator: ClockGenId) {
152        self.gclk
153            .pchctrl(u8::from(clock) as usize)
154            .write(|w| unsafe {
155                w.r#gen().bits(generator.into());
156                w.chen().set_bit()
157            });
158        self.wait_for_sync();
159    }
160
161    fn configure_standby(&mut self, gclk: ClockGenId, enable: bool) {
162        self.gclk
163            .genctrl(u8::from(gclk) as usize)
164            .modify(|_, w| w.runstdby().bit(enable));
165        self.wait_for_sync();
166    }
167}
168
169/// `GenericClockController` encapsulates the Gclk hardware.
170///
171/// It provides a type safe way to configure the system clocks.
172/// Initializing the `GenericClockController` instance configures
173/// the system to run at 120MHz by taking the DFLL48
174/// and feeding it into the DPLL0 hardware which multiplies the
175/// signal by 2.5x.
176pub struct GenericClockController {
177    state: State,
178    gclks: [Hertz; 12],
179    used_clocks: u64,
180}
181
182impl GenericClockController {
183    /// Reset the clock controller, configure the system to run
184    /// at 120Mhz and reset various clock dividers.
185    pub fn with_internal_32kosc(
186        gclk: Gclk,
187        mclk: &mut Mclk,
188        osc32kctrl: &mut Osc32kctrl,
189        oscctrl: &mut Oscctrl,
190        nvmctrl: &mut Nvmctrl,
191    ) -> Self {
192        Self::new(gclk, mclk, osc32kctrl, oscctrl, nvmctrl, false)
193    }
194
195    /// Reset the clock controller, configure the system to run
196    /// at 120Mhz and reset various clock dividers.
197    pub fn with_external_32kosc(
198        gclk: Gclk,
199        mclk: &mut Mclk,
200        osc32kctrl: &mut Osc32kctrl,
201        oscctrl: &mut Oscctrl,
202        nvmctrl: &mut Nvmctrl,
203    ) -> Self {
204        Self::new(gclk, mclk, osc32kctrl, oscctrl, nvmctrl, true)
205    }
206
207    fn new(
208        gclk: Gclk,
209        mclk: &mut Mclk,
210        osc32kctrl: &mut Osc32kctrl,
211        oscctrl: &mut Oscctrl,
212        nvmctrl: &mut Nvmctrl,
213        use_external_crystal: bool,
214    ) -> Self {
215        let mut state = State { gclk };
216
217        set_flash_to_half_auto_wait_state(nvmctrl);
218        enable_gclk_apb(mclk);
219
220        if use_external_crystal {
221            enable_external_32kosc(osc32kctrl);
222            state.reset_gclk();
223            state.set_gclk_divider_and_source(Gclk1, 1, Xosc32k, false);
224        } else {
225            enable_internal_32kosc(osc32kctrl);
226            state.reset_gclk();
227            state.set_gclk_divider_and_source(Gclk1, 1, Osculp32k, false);
228        }
229
230        while state.gclk.syncbusy().read().genctrl().is_gclk0() {}
231
232        #[cfg(feature = "usb")]
233        configure_usb_correction(oscctrl);
234
235        // GCLK5 set to 2MHz
236        unsafe {
237            state.gclk.genctrl(5).write(|w| {
238                w.src().dfll();
239                w.genen().set_bit();
240                w.div().bits(24)
241            });
242        }
243
244        while state.gclk.syncbusy().read().genctrl().is_gclk5() {}
245
246        configure_and_enable_dpll0(oscctrl, &mut state.gclk);
247        wait_for_dpllrdy(oscctrl);
248
249        unsafe {
250            // GCLK0 set to DPLL0 (120MHz)
251            state.gclk.genctrl(0).write(|w| {
252                w.src().dpll0();
253                w.div().bits(1);
254                w.oe().set_bit();
255                w.genen().set_bit()
256            });
257        }
258
259        while state.gclk.syncbusy().read().genctrl().is_gclk0() {}
260
261        mclk.cpudiv().write(|w| w.div().div1());
262
263        Self {
264            state,
265            gclks: [
266                OSC120M_FREQ,
267                OSC32K_FREQ,
268                0.Hz(),
269                0.Hz(),
270                0.Hz(),
271                2.MHz(),
272                0.Hz(),
273                0.Hz(),
274                0.Hz(),
275                0.Hz(),
276                0.Hz(),
277                0.Hz(),
278            ],
279            used_clocks: 1u64 << u8::from(ClockId::FDPLL0),
280        }
281    }
282
283    /// Returns a `GClock` for gclk0, the 120MHz oscillator.
284    pub fn gclk0(&mut self) -> GClock {
285        GClock {
286            gclk: Gclk0,
287            freq: self.gclks[0],
288        }
289    }
290
291    /// Returns a `GClock` for gclk1, the 32KHz oscillator.
292    pub fn gclk1(&mut self) -> GClock {
293        GClock {
294            gclk: Gclk1,
295            freq: self.gclks[1],
296        }
297    }
298
299    /// Returns the `GClock` for the specified clock generator.
300    /// If that clock generator has not yet been configured,
301    /// returns None.
302    pub fn get_gclk(&mut self, gclk: ClockGenId) -> Option<GClock> {
303        let idx = u8::from(gclk) as usize;
304        if self.gclks[idx].to_Hz() == 0 {
305            None
306        } else {
307            Some(GClock {
308                gclk,
309                freq: self.gclks[idx],
310            })
311        }
312    }
313
314    /// Configures a clock generator with the specified divider and
315    /// source.
316    /// `divider` is a linear divider to be applied to the clock
317    /// source.  While the hardware also supports an exponential divider,
318    /// this function doesn't expose that functionality at this time.
319    /// `improve_duty_cycle` is a boolean that, when set to true, enables
320    /// a 50/50 duty cycle for odd divider values.
321    /// Returns a `GClock` for the configured clock generator.
322    /// Returns `None` if the clock generator has already been configured.
323    pub fn configure_gclk_divider_and_source(
324        &mut self,
325        gclk: ClockGenId,
326        divider: u16,
327        src: ClockSource,
328        improve_duty_cycle: bool,
329    ) -> Option<GClock> {
330        let idx = u8::from(gclk) as usize;
331        if self.gclks[idx].to_Hz() != 0 {
332            return None;
333        }
334        self.state
335            .set_gclk_divider_and_source(gclk, divider, src, improve_duty_cycle);
336        let freq: Hertz = match src {
337            Xosc32k | Osculp32k => OSC32K_FREQ,
338            Gclkgen1 => self.gclks[1],
339            Dfll => OSC48M_FREQ,
340            Dpll0 => OSC120M_FREQ,
341            Xosc0 | Xosc1 | Gclkin | Dpll1 => unimplemented!(),
342        };
343        self.gclks[idx] = freq / divider as u32;
344        Some(GClock { gclk, freq })
345    }
346
347    /// Enables or disables the given GClk from operation in standby.
348    pub fn configure_standby(&mut self, gclk: ClockGenId, enable: bool) {
349        self.state.configure_standby(gclk, enable)
350    }
351}
352
353macro_rules! clock_generator {
354    (
355        $(
356            $(#[$attr:meta])*
357            ($id:ident, $Type:ident, $clock:ident, $PclkId:ident),
358        )+
359    ) => {
360
361$(
362
363/// A typed token that indicates that the clock for the peripheral(s)
364/// with the matching name has been configured.
365///
366/// The effective clock frequency is available via the `freq` method,
367/// or by converting the object into a `Hertz` instance.
368/// The peripheral initialization code will typically require passing
369/// in this object to prove at compile time that the clock has been
370/// correctly initialized.
371$(#[$attr])*
372#[derive(Debug)]
373pub struct $Type {
374    freq: Hertz,
375}
376
377$(#[$attr])*
378impl $Type {
379    /// Returns the frequency of the configured clock
380    pub fn freq(&self) -> Hertz {
381        self.freq
382    }
383}
384$(#[$attr])*
385impl Into<Hertz> for $Type {
386    fn into(self) -> Hertz {
387        self.freq
388    }
389}
390
391/// V2 to V1 compatibility layer that allows to convert V2 [`Pclk`] constructs
392/// into corresponding V1 `*Clock` types. Thus, user can manage V1 clocking
393/// compatible peripherals while using V2 clocking API
394$(#[$attr])*
395impl<I: PclkSourceId> core::convert::From<Pclk<$PclkId, I>> for $Type {
396    fn from(pclk: Pclk<$PclkId, I>) -> Self {
397        $Type {
398            freq: pclk.freq()
399        }
400    }
401}
402
403
404)+
405
406impl GenericClockController {
407    $(
408    /// Configure the clock for peripheral(s) that match the name
409    /// of this function to use the specific clock generator.
410    /// The `GClock` parameter may be one of default clocks
411    /// return from `gclk0()`, `gclk1()` or a clock configured
412    /// by the host application using the `configure_gclk_divider_and_source`
413    /// method.
414    /// Returns a typed token that proves that the clock has been configured;
415    /// the peripheral initialization code will typically require that this
416    /// clock token be passed in to ensure that the clock has been initialized
417    /// appropriately.
418    /// Returns `None` is the specified generic clock has already been
419    /// configured.
420    $(#[$attr])*
421    pub fn $id(&mut self, generator: &GClock) -> Option<$Type> {
422        let bits: u64 = 1 << u8::from(ClockId::$clock) as u64;
423        if (self.used_clocks & bits) != 0 {
424            return None;
425        }
426        self.used_clocks |= bits;
427
428        self.state.enable_clock_generator(ClockId::$clock, generator.gclk);
429        let freq = self.gclks[u8::from(generator.gclk) as usize];
430        Some($Type{freq})
431    }
432    )+
433}
434    }
435}
436
437#[hal_macro_helper]
438clock_generator!(
439    (tc0_tc1, Tc0Tc1Clock, TC0_TC1, Tc0Tc1),
440    (tcc0_tcc1, Tcc0Tcc1Clock, TCC0_TCC1, Tcc0Tcc1),
441    (tc2_tc3, Tc2Tc3Clock, TC2_TC3, Tc2Tc3),
442    (tcc2_tcc3, Tcc2Tcc3Clock, TCC2_TCC3, Tcc2Tcc3),
443    #[hal_cfg(all("tc4", "tc5"))]
444    (tc4_tc5, Tc4Tc5Clock, TC4_TC5, Tc4Tc5),
445    #[hal_cfg("tcc4")]
446    (tcc4, Tcc4Clock, TCC4, Tcc4),
447    #[hal_cfg(all("tc6", "tc7"))]
448    (tc6_tc7, Tc6Tc7Clock, TC6_TC7, Tc6Tc7),
449    (sercom0_core, Sercom0CoreClock, SERCOM0_CORE, Sercom0),
450    (sercom1_core, Sercom1CoreClock, SERCOM1_CORE, Sercom1),
451    (sercom2_core, Sercom2CoreClock, SERCOM2_CORE, Sercom2),
452    (sercom3_core, Sercom3CoreClock, SERCOM3_CORE, Sercom3),
453    (sercom4_core, Sercom4CoreClock, SERCOM4_CORE, Sercom4),
454    (sercom5_core, Sercom5CoreClock, SERCOM5_CORE, Sercom5),
455    #[hal_cfg("sercom6")]
456    (sercom6_core, Sercom6CoreClock, SERCOM6_CORE, Sercom6),
457    #[hal_cfg("sercom7")]
458    (sercom7_core, Sercom7CoreClock, SERCOM7_CORE, Sercom7),
459    (usb, UsbClock, USB, Usb),
460    (adc0, Adc0Clock, ADC0, Adc0),
461    (adc1, Adc1Clock, ADC1, Adc1),
462    (eic, EicClock, EIC, Eic),
463    (freq_m_msr, FreqmMsrClock, FREQM_MSR, FreqMMeasure),
464    (freq_m_ref, FreqmRefClock, FREQM_REF, FreqMReference),
465    (evsys0, Evsys0Clock, EVSYS0, EvSys0),
466    (evsys1, Evsys1Clock, EVSYS1, EvSys1),
467    (evsys2, Evsys2Clock, EVSYS2, EvSys2),
468    (evsys3, Evsys3Clock, EVSYS3, EvSys3),
469    (evsys4, Evsys4Clock, EVSYS4, EvSys4),
470    (evsys5, Evsys5Clock, EVSYS5, EvSys5),
471    (evsys6, Evsys6Clock, EVSYS6, EvSys6),
472    (evsys7, Evsys7Clock, EVSYS7, EvSys7),
473    (evsys8, Evsys8Clock, EVSYS8, EvSys8),
474    (evsys9, Evsys9Clock, EVSYS9, EvSys9),
475    (evsys10, Evsys10Clock, EVSYS10, EvSys10),
476    (evsys11, Evsys11Clock, EVSYS11, EvSys11),
477    #[hal_cfg("can0")]
478    (can0, Can0Clock, CAN0, Can0),
479    #[hal_cfg("can1")]
480    (can1, Can1Clock, CAN1, Can1),
481    (pdec, PdecClock, PDEC, PDec),
482    (ac, AcClock, AC, Ac),
483    (ccl, CclClock, CCL, Ccl),
484    (dac, DacClock, DAC, Dac),
485    #[hal_cfg("i2s")]
486    (i2s0, I2S0Clock, I2S0, I2S0),
487    #[hal_cfg("i2s")]
488    (i2s1, I2S1Clock, I2S1, I2S1),
489    (sdhc0, Sdhc0Clock, SDHC0, Sdhc0),
490    #[hal_cfg("sdhc1")]
491    (sdhc1, Sdhc1Clock, SDHC1, Sdhc1),
492    (cm4_trace, Cm4TraceClock, CM4_TRACE, CM4Trace),
493);
494
495/// The frequency of the 48Mhz source.
496pub const OSC48M_FREQ: Hertz = Hertz::Hz(48_000_000);
497/// The frequency of the 32Khz source.
498pub const OSC32K_FREQ: Hertz = Hertz::Hz(32_768);
499/// The frequency of the 120Mhz source.
500pub const OSC120M_FREQ: Hertz = Hertz::Hz(120_000_000);
501
502fn set_flash_to_half_auto_wait_state(nvmctrl: &mut Nvmctrl) {
503    // Zero indicates zero wait states, one indicates one wait state, etc.,
504    // up to 15 wait states.
505    nvmctrl
506        .ctrla()
507        .modify(|_, w| unsafe { w.rws().bits(0b0111) });
508}
509
510fn enable_gclk_apb(mclk: &mut Mclk) {
511    mclk.apbamask().modify(|_, w| w.gclk_().set_bit());
512}
513
514/// Turn on the internal 32hkz oscillator
515fn enable_internal_32kosc(osc32kctrl: &mut Osc32kctrl) {
516    osc32kctrl.osculp32k().modify(|_, w| {
517        w.en32k().set_bit();
518        w.en1k().set_bit()
519    });
520    osc32kctrl.rtcctrl().write(|w| w.rtcsel().ulp1k());
521}
522
523/// Turn on the external 32hkz oscillator
524fn enable_external_32kosc(osc32kctrl: &mut Osc32kctrl) {
525    osc32kctrl.xosc32k().modify(|_, w| {
526        w.ondemand().clear_bit();
527        // Enable 32khz output
528        w.en32k().set_bit();
529        w.en1k().set_bit();
530        // Crystal connected to xin32/xout32
531        w.xtalen().set_bit();
532        w.enable().set_bit();
533        w.cgm().xt();
534        w.runstdby().set_bit()
535    });
536
537    osc32kctrl.rtcctrl().write(|w| w.rtcsel().xosc1k());
538
539    // Wait for the oscillator to stabilize
540    while osc32kctrl.status().read().xosc32krdy().bit_is_clear() {}
541}
542
543fn wait_for_dpllrdy(oscctrl: &mut Oscctrl) {
544    while oscctrl.dpll(0).dpllstatus().read().lock().bit_is_clear()
545        || oscctrl.dpll(0).dpllstatus().read().clkrdy().bit_is_clear()
546    {}
547}
548
549/// Configure the dpll0 to run at 120MHz
550fn configure_and_enable_dpll0(oscctrl: &mut Oscctrl, gclk: &mut Gclk) {
551    gclk.pchctrl(ClockId::FDPLL0 as usize).write(|w| {
552        w.chen().set_bit();
553        w.r#gen().gclk5()
554    });
555    unsafe {
556        oscctrl.dpll(0).dpllratio().write(|w| {
557            w.ldr().bits(59);
558            w.ldrfrac().bits(0)
559        });
560    }
561    oscctrl.dpll(0).dpllctrlb().write(|w| w.refclk().gclk());
562    oscctrl.dpll(0).dpllctrla().write(|w| {
563        w.enable().set_bit();
564        w.ondemand().clear_bit()
565    });
566}
567
568#[cfg(feature = "usb")]
569/// Configure the dfll48m to calibrate against the 1Khz USB SOF reference.
570fn configure_usb_correction(oscctrl: &mut Oscctrl) {
571    oscctrl.dfllmul().write(|w| unsafe {
572        w.cstep().bits(0x1)
573        .fstep().bits(0x1)
574        // scaling factor for 1Khz SOF signal.
575        .mul().bits((48_000_000u32 / 1000) as u16)
576    });
577    while oscctrl.dfllsync().read().dfllmul().bit_is_set() {}
578
579    oscctrl.dfllctrlb().write(|w| {
580        // closed loop mode
581        w.mode().set_bit()
582        // chill cycle disable
583        .ccdis().set_bit()
584        // usb correction
585        .usbcrm().set_bit()
586    });
587    while oscctrl.dfllsync().read().dfllctrlb().bit_is_set() {}
588}