예제 #1
0
파일: clock.c 프로젝트: N7QWT/klipper
void
SystemInit(void)
{
    // Setup flash to work with 48Mhz clock
    NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_RWS_HALF;

    // Enable external 32Khz crystal
    uint32_t val = (SYSCTRL_XOSC32K_STARTUP(6)
                    | SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K);
    SYSCTRL->XOSC32K.reg = val;
    SYSCTRL->XOSC32K.reg = val | SYSCTRL_XOSC32K_ENABLE;
    while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY))
        ;

    // Reset GCLK
    GCLK->CTRL.reg = GCLK_CTRL_SWRST;
    while (GCLK->CTRL.reg & GCLK_CTRL_SWRST)
        ;

    // Route 32Khz clock to DFLL48M
    GCLK->GENDIV.reg = GCLK_GENDIV_ID(CLK_32K);
    GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(CLK_32K)
                         | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_GENEN);
    GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_ID(MCLK_DFLL48M)
                         | GCLK_CLKCTRL_GEN(CLK_32K) | GCLK_CLKCTRL_CLKEN);

    // Configure DFLL48M clock
    SYSCTRL->DFLLCTRL.reg = 0;
    uint32_t mul = DIV_ROUND_CLOSEST(CONFIG_CLOCK_FREQ, CLK_32K_FREQ);
    SYSCTRL->DFLLMUL.reg = (SYSCTRL_DFLLMUL_CSTEP(31)
                            | SYSCTRL_DFLLMUL_FSTEP(511)
                            | SYSCTRL_DFLLMUL_MUL(mul));
    SYSCTRL->DFLLCTRL.reg = (SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_WAITLOCK
                             | SYSCTRL_DFLLCTRL_QLDIS
                             | SYSCTRL_DFLLCTRL_ENABLE);
    uint32_t ready = (SYSCTRL_PCLKSR_DFLLRDY | SYSCTRL_PCLKSR_DFLLLCKC
                      | SYSCTRL_PCLKSR_DFLLLCKF);
    while ((SYSCTRL->PCLKSR.reg & ready) != ready)
        ;

    // Switch main clock to DFLL48M clock
    GCLK->GENDIV.reg = GCLK_GENDIV_ID(CLK_MAIN);
    GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(CLK_MAIN)
                         | GCLK_GENCTRL_SRC_DFLL48M
                         | GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN);
}
예제 #2
0
void main_clock_init (void)
{
	/* enable the xosc32k and set the start up time */
	SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP(6) | SYSCTRL_XOSC32K_EN32K |
												 SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_ENABLE;
	
	while (!SYSCTRL->PCLKSR.bit.XOSC32KRDY){}
	
	/* enable the generic clock GEN1 and configure the XOSC32K as clock source for it */
	GCLK->GENCTRL.reg = GCLK_GENCTRL_ID_GCLK1 | GCLK_GENCTRL_SRC_XOSC32K | 
											GCLK_GENCTRL_GENEN | GCLK_GENCTRL_IDC;
	
	while (GCLK->STATUS.bit.SYNCBUSY){}
	
	/* Enable the DFLL and set the operation mode as closed loop */
  SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE | SYSCTRL_DFLLCTRL_MODE;
  
  while(!SYSCTRL->PCLKSR.bit.DFLLRDY){}
		
  /* Load the Multiply factor, Coarse Step and fine Step for DFLL */
  SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(0x1F/4) | SYSCTRL_DFLLMUL_FSTEP(0xFF/4) |  
												 SYSCTRL_DFLLMUL_MUL(1465);
		
  /* Enable the Generic Clock GEN 1 as DFLL48 as Reference */ 
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_ID(0);
  /* wait for fine lock */
  while(!SYSCTRL->PCLKSR.bit.DFLLLCKF){}
		
  /* Set the NVM Read Wait States to 1, Since the operating frequency 48 MHz */
  NVMCTRL->CTRLB.bit.RWS = 1;
		
  /*  Enable the Generic Clock 0 and Configure the DFLL as Clock Source for it*/
  GCLK->GENCTRL.reg = GCLK_GENCTRL_ID_GCLK0 | GCLK_GENCTRL_SRC_DFLL48M |  GCLK_GENCTRL_GENEN | 
											GCLK_GENCTRL_IDC;
  
  while(GCLK->STATUS.bit.SYNCBUSY){}		
}
void SystemInit( void )
{
  /* Set 1 Flash Wait State for 48MHz, cf tables 20.9 and 35.27 in SAMD21 Datasheet */
  NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val ;

  /* Turn on the digital interface clock */
  PM->APBAMASK.reg |= PM_APBAMASK_GCLK ;

  /* ----------------------------------------------------------------------------------------------
   * 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator)
   */
  SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP( 0x6u ) | /* cf table 15.10 of product datasheet in chapter 15.8.6 */
                         SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K ;
  SYSCTRL->XOSC32K.bit.ENABLE = 1 ; /* separate call, as described in chapter 15.6.3 */

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

  /* Software reset the module to ensure it is re-initialized correctly */
  /* Note: Due to synchronization, there is a delay from writing CTRL.SWRST until the reset is complete.
   * CTRL.SWRST and STATUS.SYNCBUSY will both be cleared when the reset is complete, as described in chapter 13.8.1
   */
  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( GENERIC_CLOCK_GENERATOR_XOSC32K ) ; // 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( GENERIC_CLOCK_GENERATOR_XOSC32K ) | // 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 */
  }

  /* ----------------------------------------------------------------------------------------------
   * 3) Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference)
   */
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GENERIC_CLOCK_MULTIPLEXER_DFLL48M ) | // Generic Clock Multiplexer 0
                      GCLK_CLKCTRL_GEN_GCLK1 | // Generic Clock Generator 1 is source
                      GCLK_CLKCTRL_CLKEN ;

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

  /* ----------------------------------------------------------------------------------------------
   * 4) Enable DFLL48M clock
   */

  /* DFLL Configuration in Closed Loop mode, cf product datasheet chapter 15.6.7.1 - Closed-Loop Operation */

  /* Remove the OnDemand mode, Bug http://avr32.icgroup.norway.atmel.com/bugzilla/show_bug.cgi?id=9905 */
  SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0 ;

  while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
  {
    /* Wait for synchronization */
  }

  SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP( 31 ) | // Coarse step is 31, half of the max value
                         SYSCTRL_DFLLMUL_FSTEP( 511 ) | // Fine step is 511, half of the max value
                         SYSCTRL_DFLLMUL_MUL( (__CLOCK_48MHz/__CLOCK_32KHz) ) ; // External 32KHz is the reference

  while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
  {
    /* Wait for synchronization */
  }

  /* Write full configuration to DFLL control register */
  SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE | /* Enable the closed loop mode */
                           SYSCTRL_DFLLCTRL_WAITLOCK |
                           SYSCTRL_DFLLCTRL_QLDIS ; /* Disable Quick lock */

  while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
  {
    /* Wait for synchronization */
  }

  /* Enable the DFLL */
  SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE ;

  while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) == 0 ||
          (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF) == 0 )
  {
    /* Wait for locks flags */
  }

  while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
  {
    /* Wait for synchronization */
  }

  /* ----------------------------------------------------------------------------------------------
   * 5) Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz.
   */
  GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_MAIN ) ; // Generic Clock Generator 0

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

  /* Write Generic Clock Generator 0 configuration */
  GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_MAIN ) | // Generic Clock Generator 0
                      GCLK_GENCTRL_SRC_DFLL48M | // Selected source is DFLL 48MHz
//                      GCLK_GENCTRL_OE | // Output clock to a pin for tests
                      GCLK_GENCTRL_IDC | // Set 50/50 duty cycle
                      GCLK_GENCTRL_GENEN ;

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

  /* ----------------------------------------------------------------------------------------------
   * 6) Modify PRESCaler value of OSC8M to have 8MHz
   */
  SYSCTRL->OSC8M.bit.PRESC = SYSCTRL_OSC8M_PRESC_0_Val ;
  SYSCTRL->OSC8M.bit.ONDEMAND = 0 ;

  /* ----------------------------------------------------------------------------------------------
   * 7) Put OSC8M as source for Generic Clock Generator 3
   */
  GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_OSC8M ) ; // Generic Clock Generator 3

  /* Write Generic Clock Generator 3 configuration */
  GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_OSC8M ) | // Generic Clock Generator 3
                      GCLK_GENCTRL_SRC_OSC8M | // Selected source is RC OSC 8MHz (already enabled at reset)
//                      GCLK_GENCTRL_OE | // Output clock to a pin for tests
                      GCLK_GENCTRL_GENEN ;

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

  /* ----------------------------------------------------------------------------------------------
   * 8) Put OSC8M as source for Generic Clock Generator 2, with freq/8
   */
  GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_OSC1M ) | 8 << 8; // Generic Clock Generator 4

  /* Write Generic Clock Generator 3 configuration */
  GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_OSC1M ) | // Generic Clock Generator 4
                      GCLK_GENCTRL_SRC_OSC8M | // Selected source is RC OSC 8MHz (already enabled at reset)
//                      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 ;

  SystemCoreClock=__CLOCK_48MHz ;

	return;
}
예제 #4
0
void _sysctrl_init_referenced_generators(void)
{
	void *hw = (void *)SYSCTRL;

#if CONF_DFLL_CONFIG == 1

#    if CONF_DFLL_USBCRM != 1 && CONF_DFLL_MODE != CONF_DFLL_OPEN_LOOP_MODE
			hri_gclk_write_CLKCTRL_reg(GCLK, GCLK_CLKCTRL_ID(0) |
			GCLK_CLKCTRL_GEN(CONF_DFLL_GCLK) |
			( 1 << GCLK_CLKCTRL_CLKEN_Pos ));
#    endif

		hri_sysctrl_write_DFLLCTRL_reg(hw, SYSCTRL_DFLLCTRL_ENABLE);
		while(!hri_sysctrl_get_PCLKSR_DFLLRDY_bit(hw)) {;
		}

		hri_sysctrl_write_DFLLMUL_reg(hw, SYSCTRL_DFLLMUL_CSTEP(
				CONF_DFLL_CSTEP) |
			SYSCTRL_DFLLMUL_FSTEP(CONF_DFLL_FSTEP) |
			SYSCTRL_DFLLMUL_MUL(CONF_DFLL_MUL));
		hri_sysctrl_write_DFLLVAL_reg(hw, CONF_DFLLVAL);

		hri_sysctrl_dfllctrl_reg_t tmp =

			( CONF_DFLL_WAITLOCK << SYSCTRL_DFLLCTRL_WAITLOCK_Pos ) |
			( CONF_DFLL_BPLCKC << SYSCTRL_DFLLCTRL_BPLCKC_Pos ) |
			( CONF_DFLL_QLDIS << SYSCTRL_DFLLCTRL_QLDIS_Pos ) |
			( CONF_DFLL_CCDIS << SYSCTRL_DFLLCTRL_CCDIS_Pos ) |
			( CONF_DFLL_RUNSTDBY << SYSCTRL_DFLLCTRL_RUNSTDBY_Pos ) |
			( CONF_DFLL_USBCRM << SYSCTRL_DFLLCTRL_USBCRM_Pos ) |
			( CONF_DFLL_LLAW << SYSCTRL_DFLLCTRL_LLAW_Pos ) |
			( CONF_DFLL_STABLE << SYSCTRL_DFLLCTRL_STABLE_Pos ) |
			( CONF_DFLL_MODE << SYSCTRL_DFLLCTRL_MODE_Pos ) |
			( CONF_DFLL_ENABLE << SYSCTRL_DFLLCTRL_ENABLE_Pos );

		hri_sysctrl_write_DFLLCTRL_reg(hw, tmp);
#endif

#if CONF_DPLL_CONFIG == 1
#    if CONF_DPLL_REFCLK == SYSCTRL_DPLLCTRLB_REFCLK_GCLK_Val
			hri_gclk_write_CLKCTRL_reg(GCLK, GCLK_CLKCTRL_ID(1) |
			GCLK_CLKCTRL_GEN(CONF_DPLL_GCLK) | ( 1 << GCLK_CLKCTRL_CLKEN_Pos ));
#    endif

		hri_sysctrl_write_DPLLCTRLA_reg(hw,
			( CONF_DPLL_RUNSTDBY << SYSCTRL_DPLLCTRLA_RUNSTDBY_Pos ) |
			( CONF_DPLL_ENABLE << SYSCTRL_DPLLCTRLA_ENABLE_Pos ));
		hri_sysctrl_write_DPLLRATIO_reg(hw,
			SYSCTRL_DPLLRATIO_LDRFRAC(CONF_DPLL_LDRFRAC) |
			SYSCTRL_DPLLRATIO_LDR(CONF_DPLL_LDR));
		hri_sysctrl_write_DPLLCTRLB_reg(hw, SYSCTRL_DPLLCTRLB_DIV(
				CONF_DPLL_DIV) |
			( CONF_DPLL_LBYPASS << SYSCTRL_DPLLCTRLB_LBYPASS_Pos ) |
			SYSCTRL_DPLLCTRLB_LTIME(CONF_DPLL_LTIME) |
			SYSCTRL_DPLLCTRLB_REFCLK(CONF_DPLL_REFCLK) |
			( CONF_DPLL_WUF << SYSCTRL_DPLLCTRLB_WUF_Pos ) |
			( CONF_DPLL_LPEN << SYSCTRL_DPLLCTRLB_LPEN_Pos ) |
			SYSCTRL_DPLLCTRLB_FILTER(CONF_DPLL_FILTER));
#endif

#if CONF_DFLL_CONFIG == 1
#    if CONF_DFLL_ENABLE == 1

			if (hri_sysctrl_get_DFLLCTRL_MODE_bit(hw)) {
#        if CONF_DFLL_USBCRM == 0
					hri_sysctrl_pclksr_reg_t status_mask =
				SYSCTRL_PCLKSR_DFLLRDY |
				SYSCTRL_PCLKSR_DFLLLCKF | SYSCTRL_PCLKSR_DFLLLCKC;
#        else
						hri_sysctrl_pclksr_reg_t status_mask =
				SYSCTRL_PCLKSR_DFLLRDY;
#        endif

					while(hri_sysctrl_get_PCLKSR_reg(hw,
					status_mask) != status_mask) {;
					}
			} else {
				while(!hri_sysctrl_get_PCLKSR_DFLLRDY_bit(hw)) {;
				}
			}

#    endif
#    if CONF_DFLL_ONDEMAND == 1
					hri_sysctrl_set_DFLLCTRL_ONDEMAND_bit(hw);
#    endif
#endif

#if CONF_DPLL_CONFIG == 1
#    if CONF_DPLL_ENABLE == 1
				while (!( hri_sysctrl_get_DPLLSTATUS_ENABLE_bit(hw) ||
				hri_sysctrl_get_DPLLSTATUS_LOCK_bit(hw) ||
				hri_sysctrl_get_DPLLSTATUS_CLKRDY_bit(hw))) {;
				}
#    endif
#    if CONF_DPLL_ONDEMAND == 1
				hri_sysctrl_set_DPLLCTRLA_ONDEMAND_bit(hw);
#    endif
#endif

#if CONF_DFLL_CONFIG == 1
			while(hri_gclk_get_STATUS_SYNCBUSY_bit(GCLK)) {;
			}
#endif

#if CONF_OSC32K_CONFIG == 0 || CONF_OSC32K_ENABLE == 0
		    /* Disable after all possible configurations needs sync written. */
			hri_sysctrl_clear_OSC32K_ENABLE_bit(hw);
#endif

		(void)hw;
}