Go Down

Topic: Does the Zero use the 32KHz crystal to enhance the internal DFLL? (Read 3584 times) previous topic - next topic

scswift

It is my understanding that when the SAMD21 powers up, it's using a 1MHz internal clock.  It is then up to the bootloader, not the fuse settings, to configure the internal clocks.

I have found references to the clock settings in the bootloader here:
Code: [Select]

 * Clock system
 * --------------------
 * CPU clock source (GCLK_GEN_0) - 8MHz internal oscillator (OSC8M)
 * SERCOM5 core GCLK source (GCLK_ID_SERCOM5_CORE) - GCLK_GEN_0 (i.e., OSC8M)
 * GCLK Generator 1 source (GCLK_GEN_1) - 48MHz DFLL in Clock Recovery mode (DFLL48M)
 * USB GCLK source (GCLK_ID_USB) - GCLK_GEN_1 (i.e., DFLL in CRM mode)

void system_init()
{
/* Configure flash wait states */
NVMCTRL->CTRLB.bit.RWS = FLASH_WAIT_STATES;

/* Set OSC8M prescalar to divide by 1 */
SYSCTRL->OSC8M.bit.PRESC = 0;

/* Configure OSC8M as source for GCLK_GEN0 */
GCLK_GENCTRL_Type genctrl={0};
uint32_t temp_genctrl;
GCLK->GENCTRL.bit.ID = 0; /* GENERATOR_ID - GCLK_GEN_0 */
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
temp_genctrl = GCLK->GENCTRL.reg;
genctrl.bit.SRC = GCLK_GENCTRL_SRC_OSC8M_Val;
genctrl.bit.GENEN = true;
genctrl.bit.RUNSTDBY = false;
GCLK->GENCTRL.reg = (genctrl.reg | temp_genctrl);
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);

#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY  ||  SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES
SYSCTRL_DFLLCTRL_Type dfllctrl_conf = {0};
SYSCTRL_DFLLVAL_Type dfllval_conf = {0};
uint32_t coarse =( *((uint32_t *)(NVMCTRL_OTP4)
                    + (NVM_SW_CALIB_DFLL48M_COARSE_VAL / 32))
                    >> (NVM_SW_CALIB_DFLL48M_COARSE_VAL % 32))
                    & ((1 << 6) - 1);
if (coarse == 0x3f) {
coarse = 0x1f;
}
uint32_t fine =( *((uint32_t *)(NVMCTRL_OTP4)
                  + (NVM_SW_CALIB_DFLL48M_FINE_VAL / 32))
                  >> (NVM_SW_CALIB_DFLL48M_FINE_VAL % 32))
                  & ((1 << 10) - 1);
if (fine == 0x3ff) {
fine = 0x1ff;
}
dfllval_conf.bit.COARSE  = coarse;
dfllval_conf.bit.FINE    = fine;
dfllctrl_conf.bit.USBCRM = true;
dfllctrl_conf.bit.BPLCKC = false;
dfllctrl_conf.bit.QLDIS  = false;
dfllctrl_conf.bit.CCDIS  = true;
dfllctrl_conf.bit.ENABLE = true;

SYSCTRL->DFLLCTRL.bit.ONDEMAND = false;
while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY));
SYSCTRL->DFLLMUL.reg = 48000;
SYSCTRL->DFLLVAL.reg = dfllval_conf.reg;
SYSCTRL->DFLLCTRL.reg = dfllctrl_conf.reg;

GCLK_CLKCTRL_Type clkctrl={0};
uint16_t temp;
GCLK->CLKCTRL.bit.ID = 0; /* GCLK_ID - DFLL48M Reference */
temp = GCLK->CLKCTRL.reg;
clkctrl.bit.CLKEN = true;
clkctrl.bit.WRTLOCK = false;
clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK0_Val;
GCLK->CLKCTRL.reg = (clkctrl.reg | temp);

/* Configure DFLL48M as source for GCLK_GEN1 */
GCLK->GENCTRL.bit.ID = 1; /* GENERATOR_ID - GCLK_GEN_1 */
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
temp_genctrl = GCLK->GENCTRL.reg;
genctrl.bit.SRC = GCLK_GENCTRL_SRC_DFLL48M_Val;
genctrl.bit.GENEN = true;
genctrl.bit.RUNSTDBY = false;
GCLK->GENCTRL.reg = (genctrl.reg | temp_genctrl);
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
#endif
}


This seems to indicate that USB is used when available to enhance the clock using "clock recovery mode" as outlined in section 16.6 on page 157 in the datasheet:
http://www.atmel.com/images/atmel-42181-sam-d21_datasheet.pdf

I had assumed that the 32KHz crystal was there to be used with closed-loop mode on the DFLL, but unless I'm missing something that doesn't appear to be the case, and the crystal isn't used for anything at all. 

Of course it would still come in handy when you need a more accurate clock and don't have USB available, or you want to keep time more accurately than the internal oscillator for the RTC allows, but it would be nice to know if the crystal is being used and how to set the board up to use it when the USB clock isn't available if you want more accurate time keeping.  The datasheet is confusing, but it seems like enabling it may only involve writing a one to Start the closed loop mode by writing a one to the DFLL Mode Selection bit (DFLLCTRL.MODE) in the DFLL Control
register, assuming all the other stuff mentioned on page 155 is configured by the bootloader.

cmaglie

hi @scswift

the startup sequence of the bootloader is slightly different from the one used in the sketch:

https://github.com/arduino/ArduinoCore-samd/blob/master/cores/arduino/startup.c#L139

everything done in the bootloader is re-do once the sketch starts.
To answer your question:

I had assumed that the 32KHz crystal was there to be used with closed-loop mode on the DFLL, but unless I'm missing something that doesn't appear to be the case, and the crystal isn't used for anything at all.  
If you look the initialization source code linked above you'll see that the DFLL48 run in closed loop mode, and the 32.768Khz source is available as clock source.

For everyone else reading this topic and trying to figure out things: the SAMD21 has many clock sources/generators and we can connect them together in very different ways using the Generic Clock controller (GCLK). For more info see chapter 13 and 14 of the datasheet, in particular Figure 13-1 is really helpful here.



some relevant facts:
- the main CPU clock is taken from the Generic Clock Generator 0 output.
- the DFLL48M reference is the Generic Clock Multiplexer 0 input.

after a reset the system is configured as follow:
- Generic Clock Generator 0 input is connected to OSC8M
- OSC8M is running with a prescaler of 8 => 1Mhz

The actual startup sequence is:

1) Enable XOSC32K clock (External on-board 32.768Hz oscillator)
1b) Do a software-reset on GCLK so it starts from a know configuration: Generic Clock Generator 0 input is connected to OSC8M now the CPU runs at 1Mhz.
2) Select XOSC32K as input of Generic Clock Generator 1
3) Select output of Generic Clock Generator 1 as input of Generic Clock Multiplexer 0 (AKA DFLL48M reference)
4) Enable DFLL48M in closed loop mode
5) Select DFLL48M output as input of Generic Clock Generator 0. Now we are running at 48MHz.
6) Set OSC8M prescaler to 1 to obtain 8Mhz
7) Set OSC8M as input for Generic Clock Generator 3

C.

Go Up