/** * \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 ; }
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 }
/** * @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(); }
/** * \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) ); }
/** * \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; } }
/** * \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; } }
/** * \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) ); }
/** * \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)); }
/** * \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)); }
//----------------------------------------------------------------------------- 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"); }
/** * \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)); } }
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. */ }
/** * \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; } }
/** * \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)); }
/** * \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(); }
#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),
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. }
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... }