@@ -74,7 +74,9 @@ the CPU frequency can't exceed it's frequency.
7474/* Main clock > 48 MHz -> use DPLL, otherwise use DFLL */
7575# define USE_DPLL (CLOCK_CORECLOCK > SAM0_DFLL_FREQ_HZ)
7676# define USE_DFLL 1
77+ #ifndef USE_XOSC
7778# define USE_XOSC 0
79+ #endif
7880
7981# ifndef GCLK_TIMER_HZ
8082# define GCLK_TIMER_HZ MHZ(8)
@@ -115,9 +117,18 @@ static void xosc32k_init(void)
115117 while (!(OSC32KCTRL -> STATUS .reg & OSC32KCTRL_STATUS_XOSC32KRDY )) {}
116118}
117119
120+ #ifndef XOSC0_EXT_OSC
121+ # define XOSC0_EXT_OSC (0)
122+ #endif
123+
124+ #ifndef XOSC1_EXT_OSC
125+ # define XOSC1_EXT_OSC (0)
126+ #endif
127+
118128static void xosc_init (uint8_t idx )
119129{
120130 uint32_t freq ;
131+ bool xtal ;
121132
122133 if (!USE_XOSC ||
123134 (idx == 0 && XOSC0_FREQUENCY == 0 ) ||
@@ -130,9 +141,17 @@ static void xosc_init(uint8_t idx)
130141
131142 if (idx == 0 ) {
132143 freq = XOSC0_FREQUENCY ;
144+ xtal = !XOSC0_EXT_OSC ;
133145 }
134146 else if (idx == 1 ) {
135147 freq = XOSC1_FREQUENCY ;
148+ xtal = !XOSC1_EXT_OSC ;
149+ }
150+
151+ if (xtal ) {
152+ OSCCTRL -> XOSCCTRL [idx ].reg = OSCCTRL_XOSCCTRL_ENABLE ;
153+ while (!(OSCCTRL -> STATUS .vec .XOSCRDY & (idx + 1 ))) {}
154+ return ;
136155 }
137156
138157 uint32_t reg = OSCCTRL_XOSCCTRL_XTALEN
@@ -204,6 +223,10 @@ static void fdpll_init_nolock(uint8_t idx, uint32_t f_cpu, uint8_t flags)
204223 OSCCTRL -> Dpll [idx ].DPLLCTRLA .reg = 0 ;
205224 while (OSCCTRL -> Dpll [idx ].DPLLSYNCBUSY .reg ) {}
206225
226+ /* holds LDR 13 bit integer and 5 bit fractional part:
227+ * - integer part: ldr13_5 >> 5
228+ * - fractional part: ldr13_5 & 0x1f */
229+ uint32_t ldr13_5 ;
207230 uint32_t ctrlb = 0 ;
208231
209232 /* HW revision before F (A and D) might false unlock -> LBYPASS and WUF */
@@ -217,12 +240,25 @@ static void fdpll_init_nolock(uint8_t idx, uint32_t f_cpu, uint8_t flags)
217240 * (critical for some application not so much for other)*/
218241 if (EXTERNAL_OSC32_SOURCE ) {
219242 /* Source the DPLL from 32kHz XOSC32 ( equivalent to ((f_cpu << 5) / 32768) ) */
220- const uint32_t LDR = (f_cpu >> 10 );
221- OSCCTRL -> Dpll [idx ].DPLLRATIO .reg = OSCCTRL_DPLLRATIO_LDRFRAC (LDR & 0x1F )
222- | OSCCTRL_DPLLRATIO_LDR ((LDR >> 5 ) - 1 );
223-
243+ ldr13_5 = (f_cpu >> 10 );
224244 ctrlb |= OSCCTRL_DPLLCTRLB_REFCLK_XOSC32 ;
225- OSCCTRL -> Dpll [idx ].DPLLCTRLB .reg = ctrlb ;
245+ }
246+ else if (XOSC1_FREQUENCY ) {
247+ /* Source the DPLL from XOSC1 equivalent to ((f_cpu << 5) / 32768) ) */
248+ /* fCLK_DPLLn = fCKR × (LDR + 1 + LDRFRAC/32)*/
249+ /* fDIV = fXOSC / 2 * ( DIV + 1) */
250+ /* divide to 1 MHz then multiply to fcpu */
251+ const uint32_t div = (XOSC1_FREQUENCY / MHZ (1 ) / 2 ) - 1 ;
252+ ldr13_5 = (f_cpu / MHZ (1 )) << 5 ;
253+ ctrlb |= OSCCTRL_DPLLCTRLB_DIV (DIV ) | OSCCTRL_DPLLCTRLB_REFCLK_XOSC1 ;
254+ }
255+ else if (XOSC0_FREQUENCY ) {
256+ /* Source the DPLL from XOSC0 /* divide to 1 MHz then multiply to fcpu */
257+ /* fCLK_DPLLn = fCKR × (LDR + 1 + LDRFRAC/32)*/
258+ /* fDIV = fXOSC / 2 * ( DIV + 1) */
259+ const uint32_t div = (XOSC0_FREQUENCY / MHZ (1 ) / 2 ) - 1 ;
260+ ldr13_5 = (f_cpu / MHZ (1 )) << 5 ;
261+ ctrlb |= OSCCTRL_DPLLCTRLB_DIV (div ) | OSCCTRL_DPLLCTRLB_REFCLK_XOSC0 ;
226262 }
227263 else {
228264 /* TODO find a better fallback source (eg 48MCLK routed though gclk divided down to 1MHz)
@@ -232,11 +268,13 @@ static void fdpll_init_nolock(uint8_t idx, uint32_t f_cpu, uint8_t flags)
232268 while (!(GCLK -> PCHCTRL [OSCCTRL_GCLK_ID_FDPLL0 + idx ].reg & GCLK_PCHCTRL_CHEN )) {}
233269 /* Source the DPLL from 32kHz GCLK1 ( equivalent to ((f_cpu << 5) / 32768) )
234270 * avoid the routing through gclk when XOSC32 is the source */
235- const uint32_t LDR = (f_cpu >> 10 );
236- OSCCTRL -> Dpll [idx ].DPLLRATIO .reg = OSCCTRL_DPLLRATIO_LDRFRAC (LDR & 0x1F )
237- | OSCCTRL_DPLLRATIO_LDR ((LDR >> 5 ) - 1 );
271+ ldr13_5 = (f_cpu >> 10 );
238272 ctrlb |= OSCCTRL_DPLLCTRLB_REFCLK_GCLK ;
239273 }
274+
275+ OSCCTRL -> Dpll [idx ].DPLLRATIO .reg = OSCCTRL_DPLLRATIO_LDRFRAC (ldr13_5 & 0x1F )
276+ | OSCCTRL_DPLLRATIO_LDR ((ldr13_5 >> 5 ) - 1 );
277+
240278 OSCCTRL -> Dpll [idx ].DPLLCTRLB .reg = ctrlb ;
241279 OSCCTRL -> Dpll [idx ].DPLLCTRLA .reg = OSCCTRL_DPLLCTRLA_ENABLE | flags ;
242280
0 commit comments