Skip to content

Commit 7e21344

Browse files
committed
fix FrequencyIn for crystalless boards and simplify clock logic
1 parent 92bb909 commit 7e21344

File tree

1 file changed

+34
-15
lines changed

1 file changed

+34
-15
lines changed

ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ static frequencyio_frequencyin_obj_t *active_frequencyins[TC_INST_NUM];
5757
volatile uint8_t reference_tc;
5858
#ifdef SAM_D5X_E5X
5959
static uint8_t dpll_gclk;
60+
61+
#if !BOARD_HAS_CRYSTAL
62+
static uint8_t osculp32k_gclk;
63+
#endif
64+
6065
#endif
6166

6267
void frequencyin_reset(void) {
@@ -67,6 +72,11 @@ void frequencyin_reset(void) {
6772
reference_tc = 0xff;
6873
#ifdef SAM_D5X_E5X
6974
dpll_gclk = 0xff;
75+
76+
#if !BOARD_HAS_CRYSTAL
77+
osculp32k_gclk = 0xff;
78+
#endif
79+
7080
#endif
7181
}
7282

@@ -208,34 +218,38 @@ static bool frequencyin_samd51_start_dpll(void) {
208218
return true;
209219
}
210220

211-
uint8_t free_gclk = find_free_gclk(1);
212-
if (free_gclk == 0xff) {
213-
dpll_gclk = 0xff;
221+
dpll_gclk = find_free_gclk(1);
222+
if (dpll_gclk == 0xff) {
214223
return false;
215224
}
216225

217-
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL1].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(free_gclk);
218226
// TC4-7 can only have a max of 100MHz source
219227
// DPLL1 frequency equation with [X]OSC32K as source: 98.304MHz = 32768(2999 + 1 + 0/32)
220228
// Will also enable the Lock Bypass due to low-frequency sources causing DPLL unlocks
221229
// as outlined in the Errata (1.12.1)
222230
OSCCTRL->Dpll[1].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0) | OSCCTRL_DPLLRATIO_LDR(2999);
231+
223232
#if BOARD_HAS_CRYSTAL
224-
// we can use XOSC32K directly as the source
225-
OSC32KCTRL->XOSC32K.bit.EN32K = 1;
226-
OSCCTRL->Dpll[1].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK(1) | OSCCTRL_DPLLCTRLB_LBYPASS;
233+
// we can use XOSC32K directly as the source. It has already been initialized in clocks.c
234+
OSCCTRL->Dpll[1].DPLLCTRLB.reg =
235+
OSCCTRL_DPLLCTRLB_REFCLK(OSCCTRL_DPLLCTRLB_REFCLK_XOSC32_Val) | OSCCTRL_DPLLCTRLB_LBYPASS;
227236
#else
228-
// can't use OSCULP32K directly; need to setup a GCLK as a reference,
229-
// which must be done in samd/clocks.c to avoid waiting for sync
230-
return;
231-
//OSC32KCTRL->OSCULP32K.bit.EN32K = 1;
232-
//OSCCTRL->Dpll[1].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK(0);
237+
// We can't use OSCULP32K directly. Set up a GCLK controlled by it
238+
// Then use that GCLK as the reference oscillator for the DPLL.
239+
osculp32k_gclk = find_free_gclk(1);
240+
if (osculp32k_gclk == 0xff) {
241+
return false;
242+
}
243+
enable_clock_generator(osculp32k_gclk, GCLK_GENCTRL_SRC_OSCULP32K_Val, 1);
244+
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL1].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(OSCCTRL_GCLK_ID_FDPLL1);
245+
OSCCTRL->Dpll[1].DPLLCTRLB.reg =
246+
OSCCTRL_DPLLCTRLB_REFCLK(OSCCTRL_DPLLCTRLB_REFCLK_GCLK_Val) | OSCCTRL_DPLLCTRLB_LBYPASS;
233247
#endif
234-
OSCCTRL->Dpll[1].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE;
235248

249+
OSCCTRL->Dpll[1].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE;
236250
while (!(OSCCTRL->Dpll[1].DPLLSTATUS.bit.LOCK || OSCCTRL->Dpll[1].DPLLSTATUS.bit.CLKRDY)) {}
237-
enable_clock_generator(free_gclk, GCLK_GENCTRL_SRC_DPLL1_Val, 1);
238-
dpll_gclk = free_gclk;
251+
252+
enable_clock_generator(dpll_gclk, GCLK_GENCTRL_SRC_DPLL1_Val, 1);
239253
return true;
240254
}
241255

@@ -249,6 +263,11 @@ static void frequencyin_samd51_stop_dpll(void) {
249263
dpll_gclk = 0xff;
250264
}
251265

266+
if (osculp32k_gclk != 0xff) {
267+
disable_clock_generator(osculp32k_gclk);
268+
osculp32k_gclk = 0xff;
269+
}
270+
252271
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL1].reg = 0;
253272
OSCCTRL->Dpll[1].DPLLCTRLA.reg = 0;
254273
OSCCTRL->Dpll[1].DPLLRATIO.reg = 0;

0 commit comments

Comments
 (0)