Exemplo n.º 1
0
/**
 * \brief Performs the low-level initialization of the chip.
 * This includes EFC and master clock configuration.
 * It also enable a low level on the pin NRST triggers a user reset.
 */
extern WEAK void LowLevelInit( void )
{
    uint32_t dwTimeout;

    /* Set 3 WS for Embedded Flash Access for 84 MHz */
    EFC0->EEFC_FMR = EEFC_FMR_FWS( 3 );
    EFC1->EEFC_FMR = EEFC_FMR_FWS( 3 );

    /* Initialize main oscillator */
    if ( !(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) )  /* Main Oscillator Selection */
    {
        /* The Main Crystal Oscillator is enabled */
        PMC->CKGR_MOR = CKGR_MOR_KEY(0x37)
                      | CKGR_MOR_MOSCXTST(0x8) /* Main Crystal Oscillator Start-up Time: 1.4ms(datasheet) */
                      /* Specifies the number of Slow Clock cycles multiplied by 8 for the Main Crystal Oscillator start-up time */
                      | CKGR_MOR_MOSCRCEN      /* Main On-Chip RC Oscillator Enable */
                      | CKGR_MOR_MOSCXTEN;     /* Main Crystal Oscillator Enable */
                      /* MOSCSEL: The Main On-Chip RC Oscillator is selected */
                      /* MOSCRCF: The Fast RC Oscillator Frequency is at 4 MHz (default) */
                      /* CFDEN:  The Clock Failure Detector is disabled. */
        dwTimeout = 0;
        while ( !(PMC->PMC_SR & PMC_SR_MOSCXTS) && (dwTimeout++ < CLOCK_TIMEOUT) );
    }

    /* Switch to 3-20MHz Xtal oscillator */
    /* The Main Crystal Oscillator is enabled */
    PMC->CKGR_MOR = CKGR_MOR_KEY(0x37)
                  | CKGR_MOR_MOSCXTST(0x8)  /* Main Crystal Oscillator Start-up Time: 1.4ms(datasheet) */
                  /* Specifies the number of Slow Clock cycles multiplied by 8 for the Main Crystal Oscillator start-up time */
                  | CKGR_MOR_MOSCRCEN       /* Main On-Chip RC Oscillator Enable */
                  | CKGR_MOR_MOSCXTEN       /* Main Crystal Oscillator Enable */
                  | CKGR_MOR_MOSCSEL;       /* The Main Crystal Oscillator is selected */
                  /* MOSCRCF: The Fast RC Oscillator Frequency is at 4 MHz (default) */
                  /* CFDEN:  The Clock Failure Detector is disabled. */
    dwTimeout = 0;
    /* Wait Main XTAL Oscillator Status */
    while (!(PMC->PMC_SR & PMC_SR_MOSCXTS) && (dwTimeout++ < CLOCK_TIMEOUT));

    /* configure PLLA to 168 MHz */
    PMC->CKGR_PLLAR = CKGR_PLLAR_STUCKTO1
                    | CKGR_PLLAR_MULA(13)     /* PLLA Multiplier 12 MHz x (13+1) = 168 MHz */
                    | CKGR_PLLAR_PLLACOUNT(2) /* PLLA Counter 200µs(datasheet) */
                    | CKGR_PLLAR_DIVA(1);     /* Divider bypassed */
    dwTimeout = 0;
    /* Wait PLL A Lock Status */
    while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (dwTimeout++ < CLOCK_TIMEOUT));

    PMC->PMC_MCKR = PMC_MCKR_PRES_CLK_2        /* Selected clock divided by 2 => 168/2 = 84 MHz  */
                  | PMC_MCKR_CSS_MAIN_CLK;     /* Main Clock is selected */
    dwTimeout = 0;
    /* Wait Master Clock Status */
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (dwTimeout++ < CLOCK_TIMEOUT));

    PMC->PMC_MCKR = PMC_MCKR_PRES_CLK_2        /* Selected clock divided by 2 => 168/2 = 84 MHz  */
                  | PMC_MCKR_CSS_PLLA_CLK;   /* PLLA Clock is selected */
    dwTimeout = 0;
    /* Wait Master Clock Status */
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (dwTimeout++ < CLOCK_TIMEOUT));

}
/**
 * \brief Setup the microcontroller system.
 *
 * Initialize the System and update the SystemFrequency variable.
 */
void SystemInit( void )
{
  /* Set 6 FWS for Embedded Flash Access */
  EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE ;

	/* Initialize main oscillator */
	if ( !(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) )
  {
  	PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTST(0x8U) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN ;
  	while ( !(PMC->PMC_SR & PMC_SR_MOSCXTS) ) ;
	}

	/* Switch to 3-20MHz Xtal oscillator */
	PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTST(0x8U) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;
	while ( !(PMC->PMC_SR & PMC_SR_MOSCSELS) ) ;

	PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK ;
	while ( !(PMC->PMC_SR & PMC_SR_MCKRDY) ) ;

	/* Initialize PLLA */
	PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | CKGR_PLLAR_MULA(0x13U) | CKGR_PLLAR_PLLACOUNT(0x3fU) | CKGR_PLLAR_DIVA(0x1U) ;
	while ( !(PMC->PMC_SR & PMC_SR_LOCKA) ) ;

	/* Switch to main clock */
	PMC->PMC_MCKR = ((PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_PLLA_CLK) & ~PMC_MCKR_CSS_Msk) |	PMC_MCKR_CSS_MAIN_CLK ;
	while ( !(PMC->PMC_SR & PMC_SR_MCKRDY) ) ;

	/* Switch to PLLA */
	PMC->PMC_MCKR = PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_PLLA_CLK ;
	while ( !(PMC->PMC_SR & PMC_SR_MCKRDY) ) ;

  SystemCoreClock=__SYSTEM_CLOCK_120MHZ ;
}
Exemplo n.º 3
0
void clock_init(void)
{
	uint32_t timeout;

	/* Disable watchdog */
	WDT_MR = BV(WDT_WDDIS);

	/* Set wait states for flash access, needed for higher CPU clock rates */
	EEFC0_FMR = EEFC_FMR_FWS(3);
#ifdef EEFC1_FMR
	EEFC1_FMR = EEFC_FMR_FWS(3);
#endif

	// Initialize main oscillator
	if (!(CKGR_MOR & BV(CKGR_MOR_MOSCSEL)))
	{
		CKGR_MOR = CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCXTST(0x8)
			| BV(CKGR_MOR_MOSCRCEN) | BV(CKGR_MOR_MOSCXTEN);
		timeout = CLOCK_TIMEOUT;
		while (!(PMC_SR & BV(PMC_SR_MOSCXTS)) && --timeout);
	}

	// Switch to external oscillator
	CKGR_MOR = CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCXTST(0x8)
		| BV(CKGR_MOR_MOSCRCEN) | BV(CKGR_MOR_MOSCXTEN) | BV(CKGR_MOR_MOSCSEL);
	timeout = CLOCK_TIMEOUT;
	while (!(PMC_SR & BV(PMC_SR_MOSCXTS)) && --timeout);

	// Initialize and enable PLL clock
	CKGR_PLLR = evaluate_pll() | BV(CKGR_PLLR_STUCKTO1) | CKGR_PLLR_PLLCOUNT(0x2);
	timeout = CLOCK_TIMEOUT;
	while (!(PMC_SR & BV(PMC_SR_LOCK)) && --timeout);

	PMC_MCKR = PMC_MCKR_CSS_MAIN_CLK;
	timeout = CLOCK_TIMEOUT;
	while (!(PMC_SR & BV(PMC_SR_MCKRDY)) && --timeout);

	PMC_MCKR = PMC_MCKR_CSS_PLL_CLK;
	timeout = CLOCK_TIMEOUT;
	while (!(PMC_SR & BV(PMC_SR_MCKRDY)) && --timeout);

	/* Enable clock on PIO for inputs */
	// TODO: move this in gpio_init() for better power management?
	pmc_periphEnable(PIOA_ID);
	pmc_periphEnable(PIOB_ID);
	pmc_periphEnable(PIOC_ID);
#ifdef PIOF_ID
	pmc_periphEnable(PIOD_ID);
	pmc_periphEnable(PIOE_ID);
	pmc_periphEnable(PIOF_ID);
#endif
}
Exemplo n.º 4
0
Arquivo: cpu.c Projeto: A-Paul/RIOT
/**
 * @brief Initialize the CPU, set IRQ priorities
 */
void cpu_init(void)
{
    /* disable the watchdog timer */
    WDT->WDT_MR |= WDT_MR_WDDIS;
    /* initialize the Cortex-M core */
    cortexm_init();

    /* setup the flash wait states */
    EFC0->EEFC_FMR = EEFC_FMR_FWS(CLOCK_FWS);
    EFC1->EEFC_FMR = EEFC_FMR_FWS(CLOCK_FWS);

    /* unlock write protect register for PMC module */
    PMC->PMC_WPMR = PMC_WPMR_WPKEY(WPKEY);

    /* activate the external crystal */
    PMC->CKGR_MOR = (CKGR_MOR_KEY(MORKEY) |
                     CKGR_MOR_MOSCXTST(XTAL_STARTUP) |
                     CKGR_MOR_MOSCXTEN |
                     CKGR_MOR_MOSCRCEN);
    /* wait for crystal to be stable */
    while (!(PMC->PMC_SR & PMC_SR_MOSCXTS));

    /* select crystal to clock the main clock */
    PMC->CKGR_MOR = (CKGR_MOR_KEY(MORKEY) |
                     CKGR_MOR_MOSCXTST(XTAL_STARTUP) |
                     CKGR_MOR_MOSCXTEN |
                     CKGR_MOR_MOSCRCEN |
                     CKGR_MOR_MOSCSEL);
    /* wait for main oscillator selection to be complete */
    while (!(PMC->PMC_SR & PMC_SR_MOSCSELS));

    /* setup PLLA */
    PMC->CKGR_PLLAR = (CKGR_PLLAR_ONE |
                       CKGR_PLLAR_PLLACOUNT(PLL_CNT) |
                       CKGR_PLLAR_MULA(CLOCK_PLL_MUL) |
                       CKGR_PLLAR_DIVA(CLOCK_PLL_DIV));
    /* wait for PLL to lock */
    while (!(PMC->PMC_SR & PMC_SR_LOCKA));

    /* before switching to PLLA, we need to switch to main clock */
    PMC->PMC_MCKR = PMC_MCKR_CSS_MAIN_CLK;
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY));

    /* use PLLA as main clock source */
    PMC->PMC_MCKR = PMC_MCKR_CSS_PLLA_CLK;
    /* wait for master clock to be ready */
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY));

    /* trigger static peripheral initialization */
    periph_init();
}
Exemplo n.º 5
0
/**
 * \brief Enable internal 4/8/12MHz fast RC as main clock input.
 *
 * \param freqSelect fast RC frequency (FAST_RC_4MHZ, FAST_RC_8MHZ, FAST_RC_12MHZ).
 */
extern void PMC_EnableIntRC4_8_12MHz(uint32_t freqSelect)
{
    uint32_t   read_MOR;

    /* Before switching MAIN OSC on RC OSC : enable it and don't disable
     * at the same time external crystal in case of if MAIN OSC is still using external crystal
     */

    read_MOR = PMC->CKGR_MOR;

    read_MOR &= ~CKGR_MOR_MOSCRCF_Msk;   /* reset MOSCRCF field in MOR register before select RC 12MHz */

    read_MOR |= (CKGR_MOR_KEY(0x37u) |
            freqSelect               |
            CKGR_MOR_MOSCXTEN        |
            CKGR_MOR_MOSCRCEN        |
            CKGR_MOR_MOSCXTST(PmcFastRcCnt));  /* enable external crystal - enable RC OSC */

    PMC->CKGR_MOR = read_MOR;

    while( !(PMC->PMC_SR & PMC_SR_MOSCRCS ) );  /* wait end of RC oscillator stabilization */
    while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );


    read_MOR &= ~CKGR_MOR_MOSCSEL;               /* select internal fast RC */

    PMC->CKGR_MOR = read_MOR;

    while( !(PMC->PMC_SR & PMC_SR_MOSCSELS ) ); /* Wait end of Main Oscillator Selection */
    while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );
}
Exemplo n.º 6
0
Arquivo: pmc.c Projeto: 00alis/Arduino
/**
 * \brief Switch main clock source selection to internal fast RC.
 *
 * \param ul_moscrcf Fast RC oscillator(4/8/12Mhz).
 *
 * \retval 0 Success.
 * \retval 1 Timeout error.
 * \retval 2 Invalid frequency.
 */
void pmc_switch_mainck_to_fastrc(uint32_t ul_moscrcf)
{
	uint32_t ul_needXTEN = 0;

	/* Enable Fast RC oscillator but DO NOT switch to RC now */
	if (PMC->CKGR_MOR & CKGR_MOR_MOSCXTEN) {
		PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk) |
				PMC_CKGR_MOR_KEY_VALUE | CKGR_MOR_MOSCRCEN |
				ul_moscrcf;
	} else {
		ul_needXTEN = 1;
		PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk) |
				PMC_CKGR_MOR_KEY_VALUE | CKGR_MOR_MOSCRCEN |
				CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCXTST(PMC_XTAL_STARTUP_TIME) |
				ul_moscrcf;
	}

	/* Wait the Fast RC to stabilize */
	while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));

	/* Switch to Fast RC */
	PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) | PMC_CKGR_MOR_KEY_VALUE;

	// BUG FIX : clock_example3_SAM3S_SERIES does not switch sclk->mainck with XT disabled.
	if (ul_needXTEN) {
		PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) |
				PMC_CKGR_MOR_KEY_VALUE;
	}
}
Exemplo n.º 7
0
/**
 * \brief Switch main clock source selection to internal fast RC.
 *
 * \param ul_moscrcf Fast RC oscillator(4/8/12Mhz).
 *
 * \retval 0 Success.
 * \retval 1 Timeout error.
 * \retval 2 Invalid frequency.
 */
void pmc_switch_mainck_to_fastrc(uint32_t ul_moscrcf)
{
    uint32_t ul_needXTEN = 0;

    /* Enable Fast RC oscillator but DO NOT switch to RC now */
    if (PMC->CKGR_MOR & CKGR_MOR_MOSCXTEN) {
        PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk) |
                        PMC_CKGR_MOR_KEY_VALUE | CKGR_MOR_MOSCRCEN |
                        ul_moscrcf;
    } else {
        ul_needXTEN = 1;
        PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk) |
                        PMC_CKGR_MOR_KEY_VALUE | CKGR_MOR_MOSCRCEN |
                        CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCXTST(PMC_XTAL_STARTUP_TIME) |
                        ul_moscrcf;
    }

    /* Wait the Fast RC to stabilize */
    while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));

    /* Switch to Fast RC */
    PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) | PMC_CKGR_MOR_KEY_VALUE;

    /* Disable xtal oscillator */
    if (ul_needXTEN) {
        PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) |
                        PMC_CKGR_MOR_KEY_VALUE;
    }
}
Exemplo n.º 8
0
/**
 * \brief Enable external oscillator as main clock input.
 */
void PMC_EnableExtOsc(void)
{
	uint32_t   read_MOR;

	/* Before switching MAIN OSC on external crystal : enable it and don't disable
	 * at the same time RC OSC in case of if MAIN OSC is still using RC OSC
	 */

	read_MOR = PMC->CKGR_MOR;
	read_MOR &= ~CKGR_MOR_MOSCRCF_Msk;  
	/* reset MOSCRCF field in MOR register before select RC 12MHz */
	read_MOR  |= (CKGR_MOR_KEY_PASSWD 
				| CKGR_MOR_MOSCRCF_12_MHz
				| CKGR_MOR_MOSCXTEN     
				| CKGR_MOR_MOSCRCEN     
				| CKGR_MOR_MOSCXTST(DEFAUTL_MAIN_OSC_COUNT)); 
			/* enable external crystal - enable RC OSC */

	PMC->CKGR_MOR = read_MOR;

	while( !(PMC->PMC_SR & PMC_SR_MOSCRCS ) );
	/* wait end of RC oscillator stabilization */
	while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );

	read_MOR |= CKGR_MOR_MOSCSEL;
	/* select external crystal */

	PMC->CKGR_MOR = read_MOR;

	while( !(PMC->PMC_SR & PMC_SR_MOSCSELS ) ); 
	/* Wait end of Main Oscillator Selection */
	while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );
}
Exemplo n.º 9
0
/**
 * \brief Select external OSC.
 */
extern void PMC_SelectExtBypassOsc(void)
{ 
    PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) |
                    CKGR_MOR_MOSCRCEN | 
                    CKGR_MOR_MOSCXTST(0xFF) |
                    CKGR_MOR_MOSCXTBY;
    PMC->CKGR_MOR |= CKGR_MOR_MOSCSEL;
    /* wait MAIN clock status change for external OSC 12 MHz selection*/
    while(!(PMC->PMC_SR & PMC_SR_MOSCSELS));
}
Exemplo n.º 10
0
/**
 * \brief Enable main XTAL oscillator.
 *
 * \param ul_xtal_startup_time Xtal start-up time, in number of slow clocks.
 */
void pmc_osc_enable_main_xtal(uint32_t ul_xtal_startup_time)
{
	uint32_t mor = PMC->CKGR_MOR;
	mor &= ~(CKGR_MOR_MOSCXTBY|CKGR_MOR_MOSCXTEN);
	mor |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTEN |
			CKGR_MOR_MOSCXTST(ul_xtal_startup_time);
	PMC->CKGR_MOR = mor;
	/* Wait the main Xtal to stabilize */
	while (!(PMC->PMC_SR & PMC_SR_MOSCXTS));
}
Exemplo n.º 11
0
//-----------------------------------------------------------------------------
static void sys_init(void)
{
  // Disable watchdog
  WDT->WDT_MR = WDT_MR_WDDIS;

  // Set flash wait states to maximum for 150 MHz operation
  EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE;

  // Enable 32 kHz Xtal
  SUPC->SUPC_CR |= SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL;

  // Enable 12 MHz Xtal
  PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTST(8) |
      CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN;
  while (!(PMC->PMC_SR & PMC_SR_MOSCXTS));
    
  PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTST(8) |
      CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;
  while (!(PMC->PMC_SR & PMC_SR_MOSCSELS));

  // Setup PLL (12 MHz * 25 = 300 MHz)
  PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | CKGR_PLLAR_MULA(25-1) |
      CKGR_PLLAR_PLLACOUNT(0x3f) | CKGR_PLLAR_DIVA(1);
  while (!(PMC->PMC_SR & PMC_SR_LOCKA));

  // Switch main clock to PLL (two step process)
  PMC->PMC_MCKR = PMC_MCKR_CSS_MAIN_CLK | PMC_MCKR_MDIV_PCK_DIV2;
  while (!(PMC->PMC_SR & PMC_SR_MCKRDY));

  PMC->PMC_MCKR = PMC_MCKR_CSS_PLLA_CLK | PMC_MCKR_MDIV_PCK_DIV2;
  while (!(PMC->PMC_SR & PMC_SR_MCKRDY));

  // Enable PIOA, PIOB, PIOC, PIOD and PIOE
  PMC->PMC_PCER0 = PMC_PCER0_PID10 | PMC_PCER0_PID11 | PMC_PCER0_PID12 |
      PMC_PCER0_PID16 | PMC_PCER0_PID17;

  // Disable altenate functions on some pins
  MATRIX->CCFG_SYSIO |= CCFG_SYSIO_SYSIO4;

  // Enable interrupts
  asm volatile ("cpsie i");
}
Exemplo n.º 12
0
/**
 * \brief Select external OSC.
 */
void PMC_SelectExtBypassOsc(void)
{   
	volatile uint32_t timeout;
	if((PMC->CKGR_MOR & CKGR_MOR_MOSCXTBY) != CKGR_MOR_MOSCXTBY){
		PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD |
			CKGR_MOR_MOSCRCEN | 
			CKGR_MOR_MOSCXTST(0xFF) |
			CKGR_MOR_MOSCXTBY;
		PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL;
		/* wait MAIN clock status change for external OSC 12 MHz selection*/
		while(!(PMC->PMC_SR & PMC_SR_MOSCSELS));
		// Check if an external clock is provided
		for(timeout = 0; timeout<0xffff;timeout++);
		while(!(PMC->CKGR_MCFR & CKGR_MCFR_MAINFRDY));
	}
}
Exemplo n.º 13
0
static void
mcu_xtal_mainck_start (void)
{
    PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTBY) |
        CKGR_MOR_KEY (0x37) | CKGR_MOR_MOSCXTEN |
        CKGR_MOR_MOSCXTST (MCU_MAINCK_COUNT);
    
    /* Wait for the xtal oscillator to stabilize.  */
    while (! (PMC->PMC_SR & PMC_SR_MOSCXTS))
        continue;
    
    PMC->CKGR_MOR |= CKGR_MOR_KEY (0x37) | CKGR_MOR_MOSCSEL;

    /* Could check if xtal oscillator fails to start; say if xtal
       not connected.  */
}
Exemplo n.º 14
0
/**
 * \brief Switch main clock source selection to external Xtal/Bypass.
 * The function may switch MCK to SCLK if MCK source is MAINCK to avoid any
 * system crash.
 *
 * \note If used in Xtal mode, the Xtal is automatically enabled.
 *
 * \param ul_bypass 0 for Xtal, 1 for bypass.
 *
 * \retval 0 Success.
 * \retval 1 Timeout error.
 */
void pmc_switch_mainck_to_xtal(uint32_t ul_bypass)
{
    /* Enable Main Xtal oscillator */
    if (ul_bypass) {
        PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) |
                        PMC_CKGR_MOR_KEY_VALUE | CKGR_MOR_MOSCXTBY |
                        CKGR_MOR_MOSCSEL;
    } else {
        PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTBY) |
                        PMC_CKGR_MOR_KEY_VALUE | CKGR_MOR_MOSCXTEN |
                        CKGR_MOR_MOSCXTST(PMC_XTAL_STARTUP_TIME);
        /* Wait the Xtal to stabilize */
        while (!(PMC->PMC_SR & PMC_SR_MOSCXTS));

        PMC->CKGR_MOR |= PMC_CKGR_MOR_KEY_VALUE | CKGR_MOR_MOSCSEL;
    }
}
Exemplo n.º 15
0
/**
 * \brief Switch main clock source selection to external Xtal/Bypass.
 *
 * \note The function may switch MCK to SCLK if MCK source is MAINCK to avoid
 *       any system crash.
 *
 * \note If used in Xtal mode, the Xtal is automatically enabled.
 *
 * \param ul_bypass 0 for Xtal, 1 for bypass.
 *
 * \retval 0 Success.
 * \retval 1 Timeout error.
 */
void pmc_switch_mainck_to_xtal(uint32_t ul_bypass,
		uint32_t ul_xtal_startup_time)
{
	/* Enable Main Xtal oscillator */
	if (ul_bypass) {
		PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) |
				CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTBY |
				CKGR_MOR_MOSCSEL;
	} else {
		PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTBY) |
				CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTEN |
				CKGR_MOR_MOSCXTST(ul_xtal_startup_time);
		/* Wait the Xtal to stabilize */
		while (!(PMC->PMC_SR & PMC_SR_MOSCXTS));

		PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL;
	}
}
/**
 * \brief Setup the microcontroller system.
 *
 * Initialize the System and update the SystemFrequency variable.
 */
void SystemInit( void )
{
{
  /* Set 6 FWS for Embedded Flash Access according to 120MHz configuration */
  EFC0->EEFC_FMR = EEFC_FMR_FWS(5)|EEFC_FMR_CLOE;
#if defined(EFC1) // Only valid for products with two flash banks
  EFC1->EEFC_FMR = EEFC_FMR_FWS(5)|EEFC_FMR_CLOE;
#endif // EFC1

  /*
   * We are coming from a Hard Reset or Backup mode.
   * The core is clocked by Internal Fast RC @ 4MHz.
   * We intend to use the device @120MHz from external Oscillator.
   * Steps are (cf datasheet chapter '29.14 Programming Sequence'):
   * 1- Activation of external oscillator
   * 2- Switch the MAINCK to the main crystal oscillator
   * 3- Wait for the MOSCSELS to be set
   * 4- Check the main clock frequency
   * 5- Set PLLx and Divider
   * 6- Select the master clock and processor clock
   * 7- Select the programmable clocks (optional)
   */

  /* Step 1 - Activation of external oscillator
   * As we are clocking the core from internal Fast RC, we keep the bit CKGR_MOR_MOSCRCEN.
   * Main Crystal Oscillator Start-up Time (CKGR_MOR_MOSCXTST) is set to maximum value.
   * Then, we wait the startup time to be finished by checking PMC_SR_MOSCXTS in PMC_SR.
   */
  PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTST(0xfful) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN;
  for ( ; (PMC->PMC_SR & PMC_SR_MOSCXTS) != PMC_SR_MOSCXTS ; );

  /* Step 2 - Switch the MAINCK to the main crystal oscillator
   * We add the CKGR_MOR_MOSCSEL bit.
   * Then we wait for the selection to be done by checking PMC_SR_MOSCSELS in PMC_SR.
   */
  PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTST(0xfful) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;
  /* Step 3 - Wait for the MOSCSELS to be set */
  for ( ; (PMC->PMC_SR & PMC_SR_MOSCSELS) != PMC_SR_MOSCSELS ; );

  /* Step 4 - Check the main clock frequency */
  /* As written in the DS, we could check the MAINF value here (0x18a2) */

  /* Step 5 - Set PLLx and Divider
   * The external oscillator is 12MHz. As we intend to clock the system @120MHz,
   * we need to multiply the oscillator frequency by 10.
   * This can be done by setting MULx to value 9 and DIV to 1.
   * We set the maximum PLL Lock time to maximum in CKGR_PLLAR_PLLACOUNT.
   */
  //PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | (CKGR_PLLAR_MULA(0x1dul) | CKGR_PLLAR_DIVA(3ul) | CKGR_PLLAR_PLLACOUNT(0x1ul));
  PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | (CKGR_PLLAR_MULA(0x9ul) | CKGR_PLLAR_DIVA(1ul) | CKGR_PLLAR_PLLACOUNT(0x3ful));
  for ( ; (PMC->PMC_SR & PMC_SR_LOCKA) != PMC_SR_LOCKA ; );

  /* Step 6 - Select the master clock and processor clock
   * Source for MasterClock will be PLLA output (PMC_MCKR_CSS_PLLA_CLK), without frequency division.
   */
  PMC->PMC_MCKR = PMC_MCKR_PRES_CLK_1 | PMC_MCKR_CSS_PLLA_CLK;
  for ( ; (PMC->PMC_SR & PMC_SR_MCKRDY) != PMC_SR_MCKRDY ; );

  /*
   * Step 7 - Select the programmable clocks
   * *
   * Output MCK on PCK1/pin PA17
   * Used to validate Master Clock settings
   */
//  PMC->PMC_SCER = PMC_SCER_PCK1 ;

  SystemCoreClock=__SYSTEM_CLOCK_120MHZ;
}

}
/**
 * \brief Performs the low-level initialization of the chip.
 * This includes EFC and master clock configuration.
 * It also enable a low level on the pin NRST triggers a user reset.
 */
extern WEAK void LowLevelInit( void )
{
    uint32_t dwTimeout ;

    /* Set 2 WS for Embedded Flash Access */
	EFC0->EEFC_FMR = EEFC_FMR_FWS( 4 ) ;
	EFC1->EEFC_FMR = EEFC_FMR_FWS( 4 ) ;

    /* Initialize main oscillator */
    if ( !(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) )  /* Main Oscillator Selection */
    {
        // 48MHz
        PMC->CKGR_MOR = CKGR_MOR_KEY(0x37)
                      | CKGR_MOR_MOSCXTST(0x8) /* Main Crystal Oscillator Start-up Time: 1.4ms(datasheet) */
                      | CKGR_MOR_MOSCRCEN      /* Main On-Chip RC Oscillator Enable */
                      | CKGR_MOR_MOSCXTEN;     /* Main Crystal Oscillator Enable */
                                               /* The Main On-Chip RC Oscillator is selected */
        dwTimeout = 0 ;
        while ( !(PMC->PMC_SR & PMC_SR_MOSCXTS) && (dwTimeout++ < CLOCK_TIMEOUT) ) ;
    }

    /* Switch to 3-20MHz Xtal oscillator */
    PMC->CKGR_MOR = CKGR_MOR_KEY(0x37)
                  | CKGR_MOR_MOSCXTST(0x8)  /* Main Crystal Oscillator Start-up Time: 1.4ms(datasheet) */
                  | CKGR_MOR_MOSCRCEN       /* Main On-Chip RC Oscillator Enable */
                  | CKGR_MOR_MOSCXTEN       /* Main Crystal Oscillator Enable */
                  | CKGR_MOR_MOSCSEL;       /* The Main Crystal Oscillator is selected */
    dwTimeout = 0;
    /* Wait Main Oscillator Selection Status */
    while (!(PMC->PMC_SR & PMC_SR_MOSCSELS) && (dwTimeout++ < CLOCK_TIMEOUT));

    PMC->PMC_MCKR = (PMC->PMC_MCKR & ~ (0x7UL <<  0)/*AT91C_PMC_CSS*/)
                   | PMC_MCKR_CSS_MAIN_CLK;     /* Main Clock is selected */
    dwTimeout = 0;
    /* Wait Master Clock Status */
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (dwTimeout++ < CLOCK_TIMEOUT));

    /* Initialize PLLA */
    PMC->CKGR_PLLAR = CKGR_PLLAR_STUCKTO1
                    | CKGR_PLLAR_MULA(13)      /* PLLA Multiplier */
                    | CKGR_PLLAR_PLLACOUNT(2) /* PLLA Counter 200µs(datasheet) */
                    | CKGR_PLLAR_DIVA(1);     /* Divider */
    dwTimeout = 0;
    /* Wait PLL A Lock Status */
    while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (dwTimeout++ < CLOCK_TIMEOUT));

    /* Initialize UTMI for USB usage, can be disabled if not using USB for the sake of saving power*/
    PMC->CKGR_UCKR |= CKGR_UCKR_UPLLCOUNT(3) /* UTMI PLL Start-up Time */
                    | CKGR_UCKR_UPLLEN;      /* UTMI PLL Enable */
    dwTimeout = 0;
    /* Wait UTMI PLL Lock Status */
    while (!(PMC->PMC_SR & PMC_SR_LOCKU) && (dwTimeout++ < CLOCK_TIMEOUT));

    /* Switch to PLLA*/
    PMC->PMC_MCKR = ((PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_PLLA_CLK) & ~(0x7UL <<  0)/*AT91C_PMC_CSS*/)
                    | PMC_MCKR_CSS_MAIN_CLK;  /* Main Clock is selected */
    dwTimeout = 0;
    /* Wait Master Clock Status */
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (dwTimeout++ < CLOCK_TIMEOUT));

    PMC->PMC_MCKR = PMC_MCKR_PRES_CLK_2       /* Selected clock divided by 2 */
                  | PMC_MCKR_CSS_PLLA_CLK;    /* PLLA Clock is selected */
    dwTimeout = 0;
    /* Wait Master Clock Status */
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (dwTimeout++ < CLOCK_TIMEOUT));
}
Exemplo n.º 18
0
/**
 * \brief Performs the low-level initialization of the chip.
 * This includes EFC and master clock configuration.
 * It also enable a low level on the pin NRST triggers a user reset.
 */
extern WEAK void LowLevelInit( void )
{
    uint8_t i;
    uint32_t _dwTimeout = 0;
    volatile uint32_t read = 0;
    
    if ((uint32_t)LowLevelInit < EBI_CS0_ADDR) /* Code not in external mem */
    {
        /* Switch to PLL + prescaler */
        read = PMC->PMC_MCKR;
        read &= ~(PMC_MCKR_CSS_Msk);
        read |= PMC_MCKR_CSS_MAIN_CLK;
        PMC->PMC_MCKR = read;
        while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
        
        PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCXTST(64) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;
        _dwTimeout = 0;
        while (!(PMC->PMC_SR & PMC_SR_MOSCXTS) && (_dwTimeout++ < CLOCK_TIMEOUT));
        
        PMC->CKGR_PLLAR = 0;

        /* Initialize PLLA */
        PMC->CKGR_PLLAR = CKGR_PLLAR_STUCKTO1
                        | CKGR_PLLAR_MULA(199) 
                        | CKGR_PLLAR_OUTA(0)
                        | CKGR_PLLAR_PLLACOUNT(63)
                        | CKGR_PLLAR_DIVA(3);
        _dwTimeout = 0;
        while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (_dwTimeout++ < CLOCK_TIMEOUT));
        
        /* Wait for the master clock if it was already initialized */
        for ( _dwTimeout =  0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (_dwTimeout++ < CLOCK_TIMEOUT) ; );

        /* Switch to fast clock
        **********************/
        /* Switch to main oscillator + prescaler */
        read = PMC->PMC_MCKR;
        read &= ~(PMC_MCKR_MDIV_Msk);
        read |= (PMC_MCKR_MDIV_PCK_DIV3 | PMC_MCKR_PLLADIV2_DIV2);
        PMC->PMC_MCKR = read;
       
        /* Wait for the master clock if it was already initialized */
        for ( _dwTimeout =  0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (_dwTimeout++ < CLOCK_TIMEOUT) ; );
      
        /* Switch to main oscillator + prescaler */
        read = PMC->PMC_MCKR;
        read &= ~(PMC_MCKR_PRES_Msk);
        read |= PMC_MCKR_PRES_CLOCK;
        PMC->PMC_MCKR = read;

        /* Wait for the master clock if it was already initialized */
        for ( _dwTimeout =  0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (_dwTimeout++ < CLOCK_TIMEOUT) ; );

        /* Switch to PLL + prescaler */
        read = PMC->PMC_MCKR;
        read &= ~(PMC_MCKR_CSS_Msk);
        read |= PMC_MCKR_CSS_PLLA_CLK;
        PMC->PMC_MCKR = read;

        /* Wait for the master clock if it was already initialized */
        for ( _dwTimeout =  0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (_dwTimeout++ < CLOCK_TIMEOUT) ; );
    } 

    /* Initialize AIC */
    AIC->AIC_IDCR = 0xFFFFFFFF;
    AIC->AIC_SVR[0] = (unsigned int) defaultFiqHandler;

    for (i = 1; i < 31; i++) {
        AIC->AIC_SVR[i] = (unsigned int) defaultIrqHandler;
    }
    AIC->AIC_SPU = (unsigned int) defaultSpuriousHandler;

    /* Unstack nested interrupts */
    for (i = 0; i < 8 ; i++) {

        AIC->AIC_EOICR = 0;
    }

    /* Remap */
    BOARD_RemapRam();
    BOARD_ConfigureDdram();
}
Exemplo n.º 19
0
#define MHz(x) (x * 1000000)
extern "C" const PMC_DRIVER_INFO pmc_driver =
{
	{
		DRIVER_INFO_STUB,
		(DRV_ISR)PMC_ISR,
		(DRV_DCR)PMC_DCR,
		(DRV_DSR)PMC_DSR,
		PMC_IRQn,
		DRV_PRIORITY_KERNEL,
		ID_PMC
	},
	PMC,
	CKGR_MOR_CFDEN | CKGR_MOR_MOSCSEL | CKGR_MOR_KEY(0x37) |
	CKGR_MOR_MOSCXTST(255) |
	CKGR_MOR_MOSCXTEN,				//CFG_CKGR_MOR

//	CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCRCF_4MHZ | CKGR_MOR_KEY(0x37) |
//		CKGR_MOR_CFDEN,				//CFG_CKGR_MOR


	//PCK = 12000000 * (7+1) / 2  = 48 MHz
	//PCK = 12000000 * (7+1) / 1  = 96 MHz
	CKGR_PLLAR_STUCKTO1 | CKGR_PLLAR_MULA(7) | CKGR_PLLAR_PLLACOUNT(0x3f)
		| CKGR_PLLAR_DIVA(2),


	//PCK = 12000000 * (15+1) / 3 = 64 MHz
//	CKGR_PLLAR_STUCKTO1 | CKGR_PLLAR_MULA(15) | CKGR_PLLAR_PLLACOUNT(0x3f)
//		| CKGR_PLLAR_DIVA(3),
Exemplo n.º 20
0
static void SetupCpuClock ( void )
{
    // WARNING: This routine is called very early after a reset, so things
    // like the .data and .bss segments have probably not been initialised yet.

    // NOTE about JTAG debugging:
    //   You may have trouble connecting with a JTAG debugger before the clock
    //   has been setup. After a hardware reset, the core runs at 4 MHz by default.
    //   This routine switches to a 12 MHz clock (or 6 MHz after a soft reset), and
    //   then to the final 84 MHz. Even if your debugger can slow the JTAG clock down,
    //   I am not sure that the JTAG connection will always survive the clock changes.


    // Set the FWS (Flash Wait State in the Flash Mode Register) for both flash banks:
    // - FAM: Flash Access Mode: 0: 128-bit access in read Mode only, enhances access speed at the cost of power consumption.
    // - FRDY: Ready Interrupt Enable: 0: Flash Ready does not generate an interrupt.
    // - FWS: Flash Wait State: 4 + 1 = 5 wait states. See also constant CHIP_FREQ_FWS_3.
    //   The core will run at 84 MHz, and the CPU's VDDCORE pins are tied on the Arduino Due
    //   to signal VDDOUT -> VDDPLL. VDDIN has 3.3V, but I could not find any information on
    //   how to program the embedded Power Regulator.
    //   According to the data sheet, section "Embedded Flash Characteristics", if we run
    //   the CPU core at 84 MHz with VDDCORE set to 1.80 V, then we need 5 wait states,
    //   which matches our setting. However, should VDDCORE be 1.62 V, we are out of spec.
    EFC0->EEFC_FMR = EEFC_FMR_FWS(4);
    EFC1->EEFC_FMR = EEFC_FMR_FWS(4);


    const uint32_t SYS_BOARD_OSCOUNT = CKGR_MOR_MOSCXTST( 0x8 );   // Start-up time in Slow Clock cycles (multiplied by 8).
    const uint32_t SYS_CKGR_MOR_KEY_VALUE = CKGR_MOR_KEY( 0x37 );  // Key to unlock MOR register.

    // If the crystal oscillator has not already been selected into the Main Clock,
    // assume that it has not been enabled and stabilised yet, so do it here.

    if ( !( PMC->CKGR_MOR & CKGR_MOR_MOSCSEL ) )
    {
        PMC->CKGR_MOR = SYS_CKGR_MOR_KEY_VALUE |
                        SYS_BOARD_OSCOUNT |
                        CKGR_MOR_MOSCRCEN |  // Main On-Chip RC Oscillator Enable. This is probably the on-chip fast RC oscillator.
                                             // After a hardware reset we are running on it, so it probably must be kept enabled
                                             // until we are finished configuring the clocks.
                        CKGR_MOR_MOSCXTEN;   // Main Crystal Oscillator Enable.

        //  Wail until the PMC Status Register reports that the main XTAL oscillator is stabilised.
        while ( !(PMC->PMC_SR & PMC_SR_MOSCXTS) )
        {
        }
    }

    // Switch the Main Clock to the crystal oscillator. By default after a hardware reset, the on-chip fast RC oscillator runs at 4 MHz,
    // and the crystal oscillator on the Arduino Due runs at 12 MHz. So we are running the CPU faster here,
    // assuming we came here after a hardware reset.
    PMC->CKGR_MOR = SYS_CKGR_MOR_KEY_VALUE |
                    SYS_BOARD_OSCOUNT |
                    CKGR_MOR_MOSCRCEN |
                    CKGR_MOR_MOSCXTEN |
                    CKGR_MOR_MOSCSEL;

    // Wail until the PMC Status Register reports that the switch is complete.
    while (!(PMC->PMC_SR & PMC_SR_MOSCSELS))
    {
    }

    // Switch the Master Clock to the Main Clock, leaving other clock settings unchanged.
    // If we were on the PLL clock, remember that we cannot change the clock source and
    // the prescaler factor at the same time, so the resulting speed may be 12 MHz / 2 = 6 MHz for a short time.
    const uint32_t prevPmcMckr = PMC->PMC_MCKR;
    // - After a hard reset, prevPmcMckr is 1, which means that the Main Clock is selected, as expected.
    // - After a GDB 'load' command (which does a kind of soft reset), the value is 18 (0b10010),
    //   meaning that the PLLA clock divided by 2 was selected (which is what this routine does at the end).
    PMC->PMC_MCKR = (prevPmcMckr & ~uint32_t(PMC_MCKR_CSS_Msk) ) | PMC_MCKR_CSS_MAIN_CLK;

    // Wail until the PMC Status Register reports that the Master Clock is ready.
    while ( !(PMC->PMC_SR & PMC_SR_MCKRDY) )
    {
    }

    // Generate a fast clock with the PLL by setting the PLLA Register in the PMC Clock Generator.
    PMC->CKGR_PLLAR = CKGR_PLLAR_ONE |  // Always 1.
                      CKGR_PLLAR_MULA(0xdUL) |  // Multiplier is 0xd + 1 = 0xe (14). The crystal oscillator freq. is 12 MHz,
                                                // so the resulting frequency is 12 MHz x 14 = 168 MHz (84 MHz x 2).
                      CKGR_PLLAR_PLLACOUNT(0x3fUL) |   // Some delay used during the switching.
                      CKGR_PLLAR_DIVA(0x1UL);   // 1 = The divider is bypassed.

    // Wail until the PMC Status Register reports that the PLL is locked.
    while ( !(PMC->PMC_SR & PMC_SR_LOCKA) )
    {
    }


    // We cannot switch directly to the PLL / 2 clock, we must set the prescaler factor first.
    const uint32_t PLL_FACTOR = PMC_MCKR_PRES_CLK_2;  // 168 MHz / prescaler of 2 = our target core frequency of 84 MHz.

    PMC->PMC_MCKR = PLL_FACTOR | PMC_MCKR_CSS_MAIN_CLK;

    // Wail until the PMC Status Register reports that the Master Clock is ready.
    while ( !(PMC->PMC_SR & PMC_SR_MCKRDY) )
    {
    }


    // Switch the Master Clock to the PLLA / 2 clock.
    PMC->PMC_MCKR = PLL_FACTOR | PMC_MCKR_CSS_PLLA_CLK;

    // Wail until the PMC Status Register reports that the Master Clock is ready.
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY))
    {
    }


    // You can check the Main Clock frequency by reading the CKGR_MCFR register like this:
    //   const uint16_t measuredMainClockFreqIn16SlowClockCycles = PMC->CKGR_MCFR & CKGR_MCFR_MAINF_Msk;
    // On the Arduino Due, the crystal oscillator freq. is 12 MHz, and the Slow Clock runs at 32 KHz,
    // that would be 375 Main Clock ticks for every Slow Clock tick.
    // In 16 Slow Clock ticks, we have 6000 Main Clock ticks then. On my board, the value read
    // is 6601, which is around 10 % off.
}
Exemplo n.º 21
0
void reset_vector(void)
{
  g_stack[0] = 0; // need to put a reference in here to the stack array
                  // to make sure the linker brings it in. I'm sure there
                  // is a more elegant way to do this, but this seems to work
  EFC->EEFC_FMR = EEFC_FMR_FWS(5); // slow down flash for our blazing speed
  WDT->WDT_MR = WDT_MR_WDDIS; // disable watchdog for now
  // TODO: a block of code which can be ifdef'd in and out to source the
  // slow clock from a 32 kHz crystal rather than the (relatively) inaccurate
  // internal RC oscillator
  PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) |
                  PMC_MCKR_CSS_MAIN_CLK;
  PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD |
                  CKGR_MOR_MOSCXTST(0x10) | // startup time: slowclock*8*this
                  CKGR_MOR_MOSCRCEN | // keep main on-chip RC oscillator on !
                  CKGR_MOR_MOSCXTEN; // crystal oscillator enable (not select)
  while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { } // spin until stable
  while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { } // spin until selected
  PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD |     // "password" hard-wired in logic
                  CKGR_MOR_MOSCXTST(0x10) | // startup time: slowclock*8*this
                  CKGR_MOR_MOSCRCEN | // keep main on-chip RC oscillator on !
                  CKGR_MOR_MOSCXTEN; // main crystal oscillator enable
  while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { } // busy wait
  // switch to main crystal oscillator
  PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD     |
                  CKGR_MOR_MOSCXTST(0x10) |
                  CKGR_MOR_MOSCRCEN       | // keep on-chip RC oscillator on !
                  CKGR_MOR_MOSCXTEN       |
                  CKGR_MOR_MOSCSEL;
  while (!(PMC->PMC_SR & PMC_SR_MOSCSELS) ||
         !(PMC->PMC_SR & PMC_SR_MCKRDY)       ) { } // spin until stable
  PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) |
                  PMC_MCKR_CSS_MAIN_CLK;
  while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { } // spin until selected
  // now, let's measure the frequency of the main crystal oscillator
  PMC->CKGR_MCFR = CKGR_MCFR_CCSS   | // measure the crystal oscillator
                   CKGR_MCFR_RCMEAS ; // start a new measurement
  // PLLA must output between 150 MHz and 500 MHz
  // board has 12 MHz crystal; let's multiply by 24 for 288 MHz PLL freq
  #define MUL 23
  PMC->CKGR_PLLAR = CKGR_PLLAR_ONE         | // per datasheet, must set 1<<29
                    CKGR_PLLAR_MULA(MUL)   | // pll = crystal * (mul+1)/div
                    CKGR_PLLAR_DIVA(1)     |
                    CKGR_PLLAR_PLLACOUNT(0x3f);
  while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { } // spin until lock
  // don't use a divider... use the PLL output as CPU clock and divide CPU
  // clock by 2 to get 144 MHz for the master clock
  PMC->PMC_MCKR =  PMC_MCKR_CSS_MAIN_CLK | // | 
                   PMC_MCKR_MDIV_PCK_DIV2;
  while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { } // spin until ready
  // finally, dividers are all set up, so let's switch CPU to the PLLA output
  PMC->PMC_MCKR =  PMC_MCKR_CSS_PLLA_CLK | 
                   PMC_MCKR_MDIV_PCK_DIV2;
  while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { } // spin until selected
  // now we're running the CPU at 288 MHz and the system at 144 MHz

  uint32_t *pSrc, *pDest;
  // set up data segment
  pSrc = &_etext;
  pDest = &_srelocate;
  if (pSrc != pDest)
    for (; pDest < &_erelocate; )
      *pDest++ = *pSrc++;
  // set up bss segment
  for (pDest = &_szero; pDest < &_ezero; )
    *pDest++ = 0;
  // set vector table base address (if needed)
  pSrc = (uint32_t *)&_sfixed;
  SCB->VTOR = ( (uint32_t)pSrc & SCB_VTOR_TBLOFF_Msk ); // 7 LSB's are 0
  if (((uint32_t)pSrc >= IRAM_ADDR) && ((uint32_t)pSrc < IRAM_ADDR+IRAM_SIZE))
    SCB->VTOR |= 1 << 29; // TBLBASE bit 
  enable_fpu();
  __libc_init_array();
  static char metal_stdout_buf[1024];
  setvbuf(stdout, metal_stdout_buf, _IOLBF, sizeof(metal_stdout_buf));
  systime_init();
  led_init();
  console_init();
  main();
  while (1) { } // hopefully we never get here...
}