SAML21 Configuring DPLL to 16MHz (no ASF)

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How to configure FDPLL to output 16MHz from 12MHz OSCM source? Changing divider values not helping. Heres my code, I am configuring OSC16 at 4MHz and dividing it by 2 in GCLK GEN1. Using that as an input to DPLL and multiplying it by 7+1. But DPLL keep waiting for lock and CLKRDY bits to set. Same thing when OSC16 is configured at 12MHz and dividing it by 6. Both of these configurations bring GCLKGEN1 to 2MHz. The latter configuration works alright when I am multiplying DPLL INT factor by 23 to run CPU at 48MHZ.  

 

What I want is: 

/*
 * OSC16M (12MHz) --> GCLK_GEN[1] (2MHZ) --> DPLL (16MHz) --> GCLK_GEN[0] (16MHz) --> CPU_CLK (16MHz)
 * */  

This is my code, that used to run at 48 MHz and now I have changed multipliers to run at 16MHz. OSCCTRL_DPLLRATIO_LDR(7) from OSCCTRL_DPLLRATIO_LDR(23).

static void CLOCKS_OSC16M_12MHz_Init(const uint8_t divider)
{
	/* Various bits in the INTFLAG register can be set to one at startup.
	   This will ensure that these bits are cleared */
	//OSCCTRL->INTFLAG.reg = OSCCTRL_INTFLAG_DFLLRDY;
	//SUPC->INTFLAG.reg = SUPC_INTFLAG_BOD33RDY | SUPC_INTFLAG_BOD33DET;

	/* Configure OSC16M and Enable */
	OSCCTRL->OSC16MCTRL.reg =	OSCCTRL_OSC16MCTRL_ONDEMAND | OSCCTRL_OSC16MCTRL_RUNSTDBY
								| OSCCTRL_OSC16MCTRL_FSEL_12| OSCCTRL_OSC16MCTRL_ENABLE;

	/* Wait for OSC16M to be ready */
	while(OSCCTRL->STATUS.bit.OSC16MRDY == 0);

}

static void CLOCKS_DPLL_Init()
{
	/*
	 * DPLL96M is configured to run at 48MHz.
	 * OSC16M (12MHz) --> GCLK_GEN[1] (2MHZ) --> DPLL (48MHz) --> GCLK_GEN[0] (48MHz) --> CPU_CLK (48MHz)
	 * */  

	/* Configuration of the NVM CTRLB register and set the flash wait states */
	NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(2) ;

	set_power_domain(2);

	// ------------------------------------------//
	// Clock Gen 1 Configuration
	// ------------------------------------------//

	/* Configure and Enable Clock Generator 1 */
	/* Clock Source should be running before enabling this generator */
	/* GCLK_GENCTRL_OE is to enable GCLK_IO output */
	GCLK->GENCTRL[1].reg = GCLK_GENCTRL_DIV(6) | GCLK_GENCTRL_IDC | GCLK_GENCTRL_SRC_OSC16M | GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN;

	/* Wait for Generator 1 to be in sync */
	/* Bit is cleared when in sync */
	while(GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL1);

	// Peripheral Channel Control
	// - Set Generator 1 as a source for the channel to be used as a source to DPLL
	// - Enable DPLL peripheral channel
	// - Write Lock
	GCLK->PCHCTRL[1].reg = GCLK_PCHCTRL_GEN_GCLK1 | GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_WRTLOCK;

	while(GCLK->PCHCTRL[1].bit.CHEN != 1);

	// ------------------------------------------//
	// DPLL Configuration
	// ------------------------------------------//

	while(OSCCTRL->DPLLSYNCBUSY.bit.DPLLRATIO == 1);

	OSCCTRL->DPLLRATIO.reg |= OSCCTRL_DPLLRATIO_LDR(7) | OSCCTRL_DPLLRATIO_LDRFRAC(0);

	while(OSCCTRL->DPLLSYNCBUSY.bit.DPLLRATIO == 1);

	OSCCTRL->DPLLCTRLB.reg |= OSCCTRL_DPLLCTRLB_DIV(0) |  OSCCTRL_DPLLCTRLB_LTIME(0) | OSCCTRL_DPLLCTRLB_REFCLK(2) | OSCCTRL_DPLLCTRLB_FILTER(0);

	while(OSCCTRL->DPLLSYNCBUSY.bit.ENABLE == 1);

	OSCCTRL->DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE;

	while(OSCCTRL->DPLLSTATUS.bit.CLKRDY == 0 || OSCCTRL->DPLLSTATUS.bit.LOCK == 0);

	// ------------------------------------------//
	// Clock Gen 0 Configuration
	// ------------------------------------------//

	/* Configure GCLK0 (CPU clock) to run from the DPLL96M */
	/* GCLK_GENCTRL_OE is to enable GCLK_IO output */
	GCLK->GENCTRL[0].reg = GCLK_GENCTRL_DIV(1) | GCLK_GENCTRL_IDC | GCLK_GENCTRL_SRC_DPLL96M | GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN;

	while(GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL0);

	// ------------------------------------------//
	// Clock Gen 3 Configuration
	// ------------------------------------------//

	/* Configure GCLK3 to run from the OSC16M */
	/* GCLK_GENCTRL_OE is to enable GCLK_IO output */
	//GCLK->GENCTRL[3].reg = GCLK_GENCTRL_DIV(1) | GCLK_GENCTRL_IDC | GCLK_GENCTRL_SRC_OSC16M /*| GCLK_GENCTRL_OE*/ | GCLK_GENCTRL_GENEN;

	//while(GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL3);

}

What am I missing here? 

 

Thanks in advance. 

Last Edited: Mon. Jun 17, 2019 - 06:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

FDPLL min and max range are 48MHz and 96MHz according to the User manual. 

 

Thanks, Lajon for pointing it out here :  https://community.atmel.com/forum/using-internal-oscillator-not-asf#comment-2711906

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Input to the PLL needs to be about 32kHz (edit: up to 2MHz for the PLL?) Divide by big number, generate 64MHz by multiplying by bigger number, then divide by 4.
https://github.com/WestfW/SAMD10-experiments/blob/master/D10-LED_TOGGLE0/src/UserSource/led_toggle.c#L16

Last Edited: Tue. Jun 18, 2019 - 07:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the reply westfw.

 

Heres my parameter I changed after you replied. 

 

OSCCTRL->OSC16MCTRL.reg = OSCCTRL_OSC16MCTRL_FSEL_4

 

GCLK->GENCTRL[1].reg = GCLK_GENCTRL_DIV(125)

 

OSCCTRL->DPLLRATIO.reg |= OSCCTRL_DPLLRATIO_LDR(1500);

 

and it keeps waiting for CLKRDY and LOCK bit to set.

 

I have another question posted after this one, it has the same issue as well. there I am trying to configure clock as  OSC16M (4MHz) --> GCLK_GEN[1] (2MHZ) --> DPLL (48MHz) --> GCLK_GEN[0] (48MHz) --> CPU_CLK (48MHz).

Post:  https://community.atmel.com/forum/saml21-dpll-doesnt-lock-when-using-oscm16m-4mhz-locks-when-oscm16m-12mhz

 

haven't seen your GitHub code yet. my next task.