SAML21 Configuring DPLL to 16MHz (no ASF)

Go To Last Post
5 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. 

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

Hello all, 

I am trying to configure and use the DPLL96M in SAMDA1, and i test the following code but no clock signal is resulted .

The code do the following: It uses XOSC32K 32kHZ as a source ,on GEN 1 , then to MUX 1 to generate DPLL 48MHZ, then to GEN 2 to see it on an output port.

Could anyone tell me what is missing please.

 /* ----------------------------------------------------------------------------------------------
             * 1) Enable XOSC32K clock 
             */
            SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP( 0x6u ) |
                                                    SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K ;
            SYSCTRL->XOSC32K.bit.ENABLE = 1 ;

            while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY) == 0 )
            {
              /* Wait for oscillator stabilization */
            }

            
            GCLK->CTRL.reg = GCLK_CTRL_SWRST ;

            while ( (GCLK->CTRL.reg & GCLK_CTRL_SWRST) && (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) )
            {
              /* Wait for reset to complete */
            }
            /* ----------------------------------------------------------------------------------------------
             * 2) Put XOSC32K as source of Generic Clock Generator 1
             */
            GCLK->GENDIV.reg = GCLK_GENDIV_ID( 1u ) ; // Generic Clock Generator 1

            while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
            {
              /* Wait for synchronization */
            }
            /* Write Generic Clock Generator 1 configuration */
            GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( 1u ) | // Generic Clock Generator 1
                                              GCLK_GENCTRL_SRC_XOSC32K | // Selected source is External 32KHz Oscillator
                                              GCLK_GENCTRL_OE | // Output clock to a pin for tests
                                              GCLK_GENCTRL_GENEN ;

            while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
            {
              /* Wait for synchronization */
            }

             GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCLK_CLKCTRL_ID_FDPLL_Val ) | // Generic Clock Multiplexer 1
                                               GCLK_CLKCTRL_GEN_GCLK1 | // Generic Clock Generator 1 is source
                                               GCLK_CLKCTRL_CLKEN ;

            while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
            {
              // Wait for synchronization
            }

          // Enable the DPLL96M

            SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDRFRAC(0) | SYSCTRL_DPLLRATIO_LDR(1499);

            SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_DIV(0);
            SYSCTRL->DPLLCTRLB.bit.LBYPASS = 0;
            SYSCTRL->DPLLCTRLB.bit.LTIME = 0;    //select the DPLL lock time-out
            SYSCTRL->DPLLCTRLB.bit.REFCLK = 0;   //select the DPLL clock reference
            SYSCTRL->DPLLCTRLB.bit.WUF = 0;     // select if output is gated during lock time
          //  SYSCTRL->DPLLCTRLB.bit.LPEN = 0;    // Low-Power Enable
            SYSCTRL->DPLLCTRLB.bit.FILTER = 0;

            SYSCTRL->DPLLCTRLA.bit.ONDEMAND = 0;
            SYSCTRL->DPLLCTRLA.bit.RUNSTDBY = 0;
            SYSCTRL->DPLLCTRLA.bit.ENABLE = 1;

            while ((SYSCTRL->DPLLSTATUS.reg & SYSCTRL_DPLLSTATUS_ENABLE)==0 )
            {
              /* Wait for the DPLL is enabled*/

            }
            while ((SYSCTRL->DPLLSTATUS.reg & SYSCTRL_DPLLSTATUS_LOCK )==0 )
            {
              /* Wait for the DPLL is not locked */
            }

            GCLK->GENDIV.reg = GCLK_GENDIV_ID( 2u ) ; // Generic Clock Generator 2

             while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
             {
              //  Wait for synchronization
             }
              //Write Generic Clock Generator 2 configuration
             GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( 2u ) |
                 GCLK_GENCTRL_SRC_FDPLL |
                 GCLK_GENCTRL_OE | // Output clock to a pin for tests
                 GCLK_GENCTRL_GENEN ;

             while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
             {
              //  Wait for synchronization
             }

  /*
             * Now that all system clocks are configured, we can set CPU and APBx BUS clocks.
             * There values are normally the one present after Reset.
             */

            PM->CPUSEL.reg  = PM_CPUSEL_CPUDIV_DIV1 ;
            PM->APBASEL.reg = PM_APBASEL_APBADIV_DIV1_Val ;
            PM->APBBSEL.reg = PM_APBBSEL_APBBDIV_DIV1_Val ;
            PM->APBCSEL.reg = PM_APBCSEL_APBCDIV_DIV1_Val ;

            PM->APBAMASK.reg |= PM_APBAMASK_PM;

 

             PORT->Group[0].DIRSET.reg |=  PORT_PA16;
             PORT->Group[0].PMUX[8].bit.PMUXE = 0x7; //Attach clock to I/O
             PORT->Group[0].PINCFG[16].reg |= PORT_PINCFG_PMUXEN;