Skip to content

Commit b3ee32a

Browse files
committed
cpu/samd5: valid XOSC32 statup time avoid gclk roundtrip for CPU FDPLL
1 parent cfaa76b commit b3ee32a

File tree

1 file changed

+30
-16
lines changed

1 file changed

+30
-16
lines changed

cpu/samd5x/cpu.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@
5959
# endif
6060

6161
# if (CLOCK_CORECLOCK > SAM0_XOSC_FREQ_HZ)
62-
# error When using an external oscillator for the main clock, the CPU frequency can't exceed it's frequency.
62+
# error When using an external oscillator for the main clock,\
63+
the CPU frequency can't exceed it's frequency.
6364
# endif
6465

6566
# define USE_DPLL 0
@@ -102,12 +103,16 @@ static void xosc32k_init(void)
102103
return;
103104
}
104105

106+
/* Startup should be a valid value 0 - 6 (~63 ms to ~8000 ms) see manual 7 is reserved
107+
* table 29-2 : time_for_startup_val[] = {63ms, 125ms, 500ms, 1sec, 2sec, 4sec, 8sec}
108+
* this delay will happen only when the system is powered on or the XOSC32
109+
* is re-enabled after being disabled for e.g.: standby*/
105110
OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_ENABLE
106111
| OSC32KCTRL_XOSC32K_EN1K
107112
| OSC32KCTRL_XOSC32K_EN32K
108113
| OSC32KCTRL_XOSC32K_RUNSTDBY
109114
| OSC32KCTRL_XOSC32K_XTALEN
110-
| OSC32KCTRL_XOSC32K_STARTUP(7);
115+
| OSC32KCTRL_XOSC32K_STARTUP(3); /* 3 ^= ~1sec see above or manual*/
111116

112117
while (!(OSC32KCTRL->STATUS.reg & OSC32KCTRL_STATUS_XOSC32KRDY)) {}
113118
}
@@ -197,24 +202,33 @@ static void fdpll_init_nolock(uint8_t idx, uint32_t f_cpu, uint8_t flags)
197202
return;
198203
}
199204

200-
/* Source the DPLL from 32kHz GCLK1 ( equivalent to ((f_cpu << 5) / 32768) ) */
201-
const uint32_t LDR = (f_cpu >> 10);
202-
203205
/* disable the DPLL before changing the configuration */
204206
OSCCTRL->Dpll[idx].DPLLCTRLA.reg &= ~OSCCTRL_DPLLCTRLA_ENABLE;
205207
while (OSCCTRL->Dpll[idx].DPLLSYNCBUSY.reg) {}
206208

207-
/* set DPLL clock source */
208-
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0 + idx].reg = GCLK_PCHCTRL_GEN(1) | GCLK_PCHCTRL_CHEN;
209-
while (!(GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0 + idx].reg & GCLK_PCHCTRL_CHEN)) {}
210-
211-
OSCCTRL->Dpll[idx].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(LDR & 0x1F)
212-
| OSCCTRL_DPLLRATIO_LDR((LDR >> 5) - 1);
213-
214-
/* Without LBYPASS, startup takes very long, see errata section 2.13. */
215-
OSCCTRL->Dpll[idx].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK_GCLK
216-
| OSCCTRL_DPLLCTRLB_WUF
217-
| OSCCTRL_DPLLCTRLB_LBYPASS;
209+
/* Without LBYPASS, startup takes very long, see errata section 2.13.
210+
* according to the documentation several milliseconds
211+
* (critical for some application not so much for other)*/
212+
if (EXTERNAL_OSC32_SOURCE) {
213+
/* Source the DPLL from 32kHz XOSC32 ( equivalent to ((f_cpu << 5) / 32768) ) */
214+
const uint32_t LDR = (f_cpu >> 10);
215+
OSCCTRL->Dpll[idx].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(LDR & 0x1F)
216+
| OSCCTRL_DPLLRATIO_LDR((LDR >> 5) - 1);
217+
OSCCTRL->Dpll[idx].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK_XOSC32;
218+
}
219+
else {
220+
/* TODO find a better fallback source (eg 48MCLK routed though gclk divided down to 1MHz)
221+
* until then the frequency might not be defined if source is low power internal 32kHz*/
222+
/* set DPLL clock source */
223+
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0 + idx].reg = GCLK_PCHCTRL_GEN(1) | GCLK_PCHCTRL_CHEN;
224+
while (!(GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0 + idx].reg & GCLK_PCHCTRL_CHEN)) {}
225+
/* Source the DPLL from 32kHz GCLK1 ( equivalent to ((f_cpu << 5) / 32768) )
226+
* avoid the routing through gclk when XOSC32 is the source */
227+
const uint32_t LDR = (f_cpu >> 10);
228+
OSCCTRL->Dpll[idx].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(LDR & 0x1F)
229+
| OSCCTRL_DPLLRATIO_LDR((LDR >> 5) - 1);
230+
OSCCTRL->Dpll[idx].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK_GCLK;
231+
}
218232

219233
OSCCTRL->Dpll[idx].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE | flags;
220234

0 commit comments

Comments
 (0)