From d4947b20c4cd79b224e02b12cffb1bb8b628fb78 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 14 May 2026 11:26:21 +0700 Subject: [PATCH 1/3] add DFLL closed loop support in addition to crystalless configuration options --- cores/arduino/startup.c | 59 ++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/cores/arduino/startup.c b/cores/arduino/startup.c index 676844091..71b167bc4 100644 --- a/cores/arduino/startup.c +++ b/cores/arduino/startup.c @@ -109,42 +109,81 @@ void SystemInit( void ) /* Wait for synchronization */ } - /* DFLL Configuration in Open Loop mode */ - +#ifdef CRYSTALLESS + /* DFLL Configuration in Open Loop mode with USB clock recovery */ + OSCCTRL->DFLLCTRLA.reg = 0; - //GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK3_Val); - + OSCCTRL->DFLLMUL.reg = OSCCTRL_DFLLMUL_CSTEP( 0x1 ) | OSCCTRL_DFLLMUL_FSTEP( 0x1 ) | OSCCTRL_DFLLMUL_MUL( 0 ); - + while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_DFLLMUL ) { /* Wait for synchronization */ } - + OSCCTRL->DFLLCTRLB.reg = 0; while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_DFLLCTRLB ) { /* Wait for synchronization */ } - + OSCCTRL->DFLLCTRLA.reg |= OSCCTRL_DFLLCTRLA_ENABLE; while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_ENABLE ) { /* Wait for synchronization */ } - + OSCCTRL->DFLLVAL.reg = OSCCTRL->DFLLVAL.reg; while( OSCCTRL->DFLLSYNC.bit.DFLLVAL ); - + OSCCTRL->DFLLCTRLB.reg = OSCCTRL_DFLLCTRLB_WAITLOCK | OSCCTRL_DFLLCTRLB_CCDIS | OSCCTRL_DFLLCTRLB_USBCRM ; - + while ( !OSCCTRL->STATUS.bit.DFLLRDY ) { /* Wait for synchronization */ } +#else + /* DFLL Configuration in Closed Loop mode against XOSC32K (via GCLK3) */ + + GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = GCLK_PCHCTRL_CHEN | + GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK3_Val); + + OSCCTRL->DFLLCTRLA.reg = 0; + + // MUL = round(48000000 / 32768) = 1465 -> DFLL targets 48,005,120 Hz + OSCCTRL->DFLLMUL.reg = OSCCTRL_DFLLMUL_CSTEP( 1 ) | + OSCCTRL_DFLLMUL_FSTEP( 1 ) | + OSCCTRL_DFLLMUL_MUL( (48000000UL + 16384UL) / 32768UL ); + + while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_DFLLMUL ) + { + /* Wait for synchronization */ + } + + OSCCTRL->DFLLCTRLB.reg = 0; + while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_DFLLCTRLB ) + { + /* Wait for synchronization */ + } + + OSCCTRL->DFLLCTRLA.reg |= OSCCTRL_DFLLCTRLA_ENABLE; + while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_ENABLE ) + { + /* Wait for synchronization */ + } + + OSCCTRL->DFLLCTRLB.reg = OSCCTRL_DFLLCTRLB_MODE | + OSCCTRL_DFLLCTRLB_WAITLOCK; + + while ( (OSCCTRL->STATUS.reg & (OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC | OSCCTRL_STATUS_DFLLLCKF)) + != (OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC | OSCCTRL_STATUS_DFLLLCKF) ) + { + /* Wait for synchronization, coarse lock, and fine lock */ + } +#endif GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_1M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(48u); From 02d718986ac9d0bb570beff4083c1cc01be3a494 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 5 Nov 2026 23:50:45 +0700 Subject: [PATCH 2/3] Bound the SAMD51 closed-loop DFLL lock wait with an open-loop fallback Also reload DFLLVAL in open loop before closing the loop (errata DS80000748 2.8.3) and read back PCHCTRL.CHEN (DS60001507 14.6.6). --- cores/arduino/startup.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/cores/arduino/startup.c b/cores/arduino/startup.c index 71b167bc4..4ee40c1ab 100644 --- a/cores/arduino/startup.c +++ b/cores/arduino/startup.c @@ -150,6 +150,12 @@ void SystemInit( void ) GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK3_Val); + while ( (GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg & GCLK_PCHCTRL_CHEN) == 0 ) + { + /* Wait for synchronization */ + } + + uint32_t const dfllval_open_loop = OSCCTRL->DFLLVAL.reg; OSCCTRL->DFLLCTRLA.reg = 0; @@ -175,14 +181,32 @@ void SystemInit( void ) /* Wait for synchronization */ } + OSCCTRL->DFLLVAL.reg = OSCCTRL->DFLLVAL.reg; + while( OSCCTRL->DFLLSYNC.bit.DFLLVAL ); + OSCCTRL->DFLLCTRLB.reg = OSCCTRL_DFLLCTRLB_MODE | OSCCTRL_DFLLCTRLB_WAITLOCK; + // Bounded in iterations of the CPU on OSCULP32K: without a running crystal the DFLL never fine-locks, + // so it then falls back to open loop at the DFLLVAL it started from + uint32_t timeout = 2000; while ( (OSCCTRL->STATUS.reg & (OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC | OSCCTRL_STATUS_DFLLLCKF)) - != (OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC | OSCCTRL_STATUS_DFLLLCKF) ) + != (OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC | OSCCTRL_STATUS_DFLLLCKF) && --timeout ) { /* Wait for synchronization, coarse lock, and fine lock */ } + + if ( timeout == 0 ) + { + OSCCTRL->DFLLCTRLB.reg = 0; + while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_DFLLCTRLB ) + { + /* Wait for synchronization */ + } + + OSCCTRL->DFLLVAL.reg = dfllval_open_loop; + while( OSCCTRL->DFLLSYNC.bit.DFLLVAL ); + } #endif GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_1M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(48u); From 36805039ca9815d7af3d68a748417b16dff2b564 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 6 Nov 2026 00:44:59 +0700 Subject: [PATCH 3/3] Narrow the DFLL lock-wait comment to the cases its fallback covers --- cores/arduino/startup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/arduino/startup.c b/cores/arduino/startup.c index 4ee40c1ab..a7c4822fc 100644 --- a/cores/arduino/startup.c +++ b/cores/arduino/startup.c @@ -187,8 +187,8 @@ void SystemInit( void ) OSCCTRL->DFLLCTRLB.reg = OSCCTRL_DFLLCTRLB_MODE | OSCCTRL_DFLLCTRLB_WAITLOCK; - // Bounded in iterations of the CPU on OSCULP32K: without a running crystal the DFLL never fine-locks, - // so it then falls back to open loop at the DFLLVAL it started from + // Bounded in OSCULP32K CPU iterations: the earlier waits need a running crystal, so this only catches a reference + // that stops after setup or a DFLL that cannot fine-lock, falling back to open loop at the DFLLVAL it started from uint32_t timeout = 2000; while ( (OSCCTRL->STATUS.reg & (OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC | OSCCTRL_STATUS_DFLLLCKF)) != (OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC | OSCCTRL_STATUS_DFLLLCKF) && --timeout )