void clk_out_init(void) { /* Enable the FB_CLKOUT function on PTC3 (alt5 function) */ PORTA_PCR15 = ( PORT_PCR_MUX(0x3)); /* Select the CLKOUT in the SMI_SOPT2 mux to be bus clk*/ SIM_SOPT2 |= SIM_SOPT2_CLKOUTSEL(2); }
void vfnMcuConfig (void) { #if defined(CLKOUT) SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK; //Enable clock on PTC3 PORTC_PCR3 = PORT_PCR_MUX(0x05); //PTC3 as CLKOUT SIM_SOPT2 &= ~SIM_SOPT2_CLKOUTSEL_MASK; //Clear CLKOUTSEL register SIM_SOPT2 |= SIM_SOPT2_CLKOUTSEL(0x02); //Select BUSCLK as CLKOUT output #endif /* Actual PLL frequency is 48MHz --> 96MHz needed for USB to work due freq divider by 2 */ /* Set dividers for new PLL frequency */ SIM_CLKDIV1 = ( 0 | SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV4(1) ); /* Return MCG to PBE */ MCG_C6 |= MCG_C6_PLLS_MASK; MCG_C2 &= ~MCG_C2_LP_MASK; MCG_C1 &= ~MCG_C1_IREFS_MASK; MCG_C1 |= MCG_C1_CLKS(2); /* Move MCG to FBE */ MCG_C6 &= ~MCG_C6_PLLS_MASK; MCG_C5 &= ~MCG_C5_PLLCLKEN0_MASK; /* Configure PLL to run @96MHz */ MCG_C6 &= ~MCG_C6_VDIV0_MASK; MCG_C5 &= ~MCG_C5_PRDIV0_MASK; MCG_C6 |= (USB_PLL_VDIV - 24); MCG_C5 |= (USB_PLL_PRDIV - 1); MCG_C5 |= MCG_C5_PLLCLKEN0_MASK; //Enable PLL while(!(MCG_S & MCG_S_LOCK0_MASK)); //Wait for PLL to lock /* Go to PBE */ MCG_C6 |= MCG_C6_PLLS_MASK; /* Go to PEE */ MCG_C1 &= ~MCG_C1_CLKS_MASK; /* MCG is now configured */ /* Reconfigure UART0 with new frequency */ #if TERM_PORT_NUM==0 uart0_init (UART0_BASE_PTR, 48000, TERMINAL_BAUD); #elif TERM_PORT_NUM==1 uart_init (UART1_BASE_PTR, 24000, TERMINAL_BAUD); #else uart_init (UART2_BASE_PTR, 24000, TERMINAL_BAUD); #endif }
void UARTinit() { SIM_SCGC4 |= SIM_SCGC4_UART0_MASK; /* PORTA_PCR1: ISF=0,MUX=2 */ PORTA_PCR1 |= (PORT_PCR_MUX(2)); /* PORTA_PCR2: ISF=0,MUX=2 */ PORTA_PCR2 |= (PORT_PCR_MUX(2)); /* Disable TX & RX while we configure settings */ UART0_C2 &= ~(UART0_C2_TE_MASK); //disable transmitter UART0_C2 &= ~(UART0_C2_RE_MASK); //disable receiver /* UART0_C1: LOOPS=0,DOZEEN=0,RSRC=0,M=0,WAKE=0,ILT=0,PE=0,PT=0 */ UART0_C1 = 0x00U; /* Set the C1 register */ /* UART0_C3: R8T9=0,R9T8=0,TXDIR=0,TXINV=0,ORIE=0,NEIE=0,FEIE=0,PEIE=0 */ UART0_C3 = 0x00U; /* Set the C3 register */ /* UART0_S2: LBKDIF=0,RXEDGIF=0,MSBF=0,RXINV=0,RWUID=0,BRK13=0,LBKDE=0,RAF=0 */ UART0_S2 = 0x00U; /* Set the S2 register */ SIM_SOPT2 |= SIM_SOPT2_UART0SRC(1); //set clock source to be from PLL/FLL SIM_SOPT2 |= SIM_SOPT2_CLKOUTSEL(0b100); unsigned SBR = 546;//137; //Set the baud rate register, SBR = 137 UART0_BDH |= (~UART0_BDH_SBR_MASK) | SBR >> 8; UART0_BDL |= (~UART0_BDL_SBR_MASK) | SBR; char OSR = 3; //set the oversampling ratio to option #3 = 4x UART0_C4 &= (~UART0_C4_OSR_MASK) | OSR; /* * Target Baud rate = 38400 9600 * * Baud rate = baud clock / ((OSR+1) * SBR) * baud clock = FLL/PLL = 20.97152MHz 32kHZ * OSR = 3 * SBR = 137 //546 * Resulting Baud rate = 20.97152MHz / ((3 + 1) * 546) = 9600 */ UART0_C5 |= UART0_C5_BOTHEDGE_MASK; //enable sampling on both edges of the clock UART0_C2 |= UART0_C2_TE_MASK; //enable transmitter UART0_C2 |= UART0_C2_RE_MASK; //enable receiver }
void ResetHandler(void) { uint32_t *src = &_etext; uint32_t *dest = &_sdata; WDOG_UNLOCK = WDOG_UNLOCK_SEQ1; WDOG_UNLOCK = WDOG_UNLOCK_SEQ2; WDOG_STCTRLH = WDOG_STCTRLH_ALLOWUPDATE; startup_early_hook(); // enable clocks to always-used peripherals SIM_SCGC5 = 0x00043F82; // clocks active to all GPIO SIM_SCGC6 = SIM_SCGC6_RTC | SIM_SCGC6_FTM0 | SIM_SCGC6_FTM1 | SIM_SCGC6_ADC0 | SIM_SCGC6_FTFL; // if the RTC oscillator isn't enabled, get it started early if (!(RTC_CR & RTC_CR_OSCE)) { RTC_SR = 0; RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; } // TODO: do this while the PLL is waiting to lock.... while (dest < &_edata) *dest++ = *src++; dest = &_sbss; while (dest < &_ebss) *dest++ = 0; SCB_VTOR = 0; // use vector table in flash // start in FEI mode // enable capacitors for crystal OSC0_CR = OSC_SC8P | OSC_SC2P; // enable osc, 8-32 MHz range, low power mode MCG_C2 = MCG_C2_RANGE0(2) | MCG_C2_EREFS; // switch to crystal as clock source, FLL input = 16 MHz / 512 MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(4); // wait for crystal oscillator to begin while ((MCG_S & MCG_S_OSCINIT0) == 0) ; // wait for FLL to use oscillator while ((MCG_S & MCG_S_IREFST) != 0) ; // wait for MCGOUT to use oscillator while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) ; // now we're in FBE mode // config PLL input for 16 MHz Crystal / 4 = 4 MHz MCG_C5 = MCG_C5_PRDIV0(3); // config PLL for 96 MHz output MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(0); // wait for PLL to start using xtal as its input while (!(MCG_S & MCG_S_PLLST)) ; // wait for PLL to lock while (!(MCG_S & MCG_S_LOCK0)) ; // now we're in PBE mode #if F_CPU == 96000000 // config divisors: 96 MHz core, 48 MHz bus, 24 MHz flash SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3); #elif F_CPU == 48000000 // config divisors: 48 MHz core, 48 MHz bus, 24 MHz flash SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3); #elif F_CPU == 24000000 // config divisors: 24 MHz core, 24 MHz bus, 24 MHz flash SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(3); #else #error "Error, F_CPU must be 96000000, 48000000, or 24000000" #endif // switch to PLL as clock source, FLL input = 16 MHz / 512 MCG_C1 = MCG_C1_CLKS(0) | MCG_C1_FRDIV(4); // wait for PLL clock to be used while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ; // now we're in PEE mode // configure USB for 48 MHz clock SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); // USB = 96 MHz PLL / 2 // USB uses PLL clock, trace is CPU clock, CLKOUT=OSCERCLK0 SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); // initialize the SysTick counter SYST_RVR = (F_CPU / 1000) - 1; SYST_CSR = SYST_CSR_CLKSOURCE | SYST_CSR_TICKINT | SYST_CSR_ENABLE; //init_pins(); __enable_irq(); _init_Teensyduino_internal_(); if (RTC_SR & RTC_SR_TIF) rtc_set(TIME_T); __libc_init_array(); /* for (ptr = &__init_array_start; ptr < &__init_array_end; ptr++) { (*ptr)(); } */ startup_late_hook(); main(); while (1) ; }
void __startup(void) { // The CPU has a watchdog feature which is on by default, // so we have to configure it to not have nasty reset-surprises // later on. startup_watchdog_hook(); // If the system was in VLLS mode, some peripherials and // the I/O pins are in latched mode. We need to restore // config and can then acknowledge the isolation to get back // to normal. For now, we'll just ack TODO: properly do this if (PMC_REGSC & PMC_REGSC_ACKISO_MASK) PMC_REGSC |= PMC_REGSC_ACKISO_MASK; // There is a write-once-after-reset register that allows to // set which power states are available. Let's set it here. SMC_PMPROT = ENABLED_POWER_MODES; // For the sake of simplicity, enable all GPIO port clocks SIM_SCGC5 |= ( SIM_SCGC5_PORTA_MASK | SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK | SIM_SCGC5_PORTE_MASK); // ---------------------------------------------------------------------------------- // Setup clocks // ---------------------------------------------------------------------------------- // See section 5 in the Freescale K20 manual for how clock distribution works // The limits are outlined in section 5.5: // Core and System clocks: max 72 MHz // Bus/peripherial clock: max 50 MHz (integer divide of core) // Flash clock: max 25 MHz // // The teensy 3.x has a 16 MHz external oscillator // So we'll enable the external clock for the OSC module. Since // we're in high-frequency mode, also enable capacitors OSC_CR = OSC_CR_SC8P_MASK | OSC_CR_SC2P_MASK; // TODO This does not actually seem enable the ext crystal // Set MCG to very high frequency crystal and request oscillator. We have // to do this first so that the divisor will be correct (512 and not 16) MCG_C2 = MCG_C2_RANGE0(2) | MCG_C2_EREFS0_MASK; // Select the external reference clock for MCGOUTCLK // The divider for the FLL has to be chosen that we get something in 31.25 to 39.0625 kHz // 16MHz / 512 = 31.25 kHz -> set FRDIV to 4 MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(4); // Wait for OSC to become ready while ((MCG_S & MCG_S_OSCINIT0_MASK) == 0) ; // Wait for the FLL to synchronize to external reference while ((MCG_S & MCG_S_IREFST_MASK) != 0) ; // Wait for the clock mode to synchronize to external while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) ; // The clock is now in FBE mode #if F_CPU <= 16000000 // For 16 MHz and below, the crystal is fast enough // -> enable BLPE mode which will disable both FLL and PLL MCG_C2 = MCG_C2_RANGE0(2) | MCG_C2_EREFS_MASK | MCG_C2_LP_MASK; #else // We need PLL to go above 16 MHz #if F_CPU == 96000000 MCG_C5 = MCG_C5_PRDIV0(3); // 16MHz / 4 = 4MHz (this needs to be 2-4MHz) MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV0(0); // Enable PLL*24 = 96 MHz #elif F_CPU == 72000000 MCG_C5 = MCG_C5_PRDIV0(5); // 16 MHz / 6 = 2.66 MHz (this needs to be 2-4MHz) MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV0(3); // Enable PLL*27 = 71.82 MHz #elif F_CPU == 48000000 MCG_C5 = MCG_C5_PRDIV0(7); // 16 MHz / 8 = 2 MHz (this needs to be 2-4MHz) MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV0(0); // Enable PLL*24 = 48 MHz #elif F_CPU == 24000000 // For 24 MHz, we'll use a 48 MHz PLL and divide in the SIM MCG_C5 = MCG_C5_PRDIV0(7); // 16 MHz / 8 = 2 MHz (this needs to be 2-4MHz) MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV0(0); // Enable PLL*24 = 48 MHz #else #error "Unknown F_CPU value" #endif // Now that we setup and enabled the PLL, wait for it to become active while (!(MCG_S & MCG_S_PLLST_MASK)) ; // and locked while (!(MCG_S & MCG_S_LOCK0_MASK)) ; #endif // Next up: Setup clock dividers for MCU, peripherials, flash and USB // This is done by the SIM (System Integration Module) // There are two registers: // SIM_CLKDIV1: // OUTDIV1: Core/system clock divider // OUTDIV2: Peripherial/Bus clock // OUTDIV4: Flash clock // SIM_CLKDIV2: // USBDIV: Divisor // USBFRAC: Fraction // Output is input_clock*(USBFRAC+1)/(USBDIV+1) // // USB needs a 48MHz clock, so the divider should be setup accordingly. Also, // for the USB FS OTG controller to work, the system clock needs to be >= 20 MHz #if F_CPU == 96000000 // 96 MHz core, 48 MHz bus, 24 MHz flash (OVERCLOCKED!) SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3); SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); // 96 * 1/2 = 48 #elif F_CPU == 72000000 // 72 MHz core, 36 MHz bus, 24 MHz flash SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(2); SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(2) | SIM_CLKDIV2_USBFRAC_MASK; // 72 * 2/3 = 48 #elif F_CPU == 48000000 // 48 MHz core, 48 MHz bus, 24 MHz flash, USB = 96 / 2 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV4(1); SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(0); // 48 * 1/1 = 48 #elif F_CPU == 24000000 // PLL is 48 MHz // 24 MHz core, 24 MHz bus, 24 MHz flash SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(1); SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(0); // 48 * 1/1 = 48 // -- For the modes <= 16 MHz, we have the MCG clock on 16 MHz, without FLL/PLL // Also, USB is not possible #elif F_CPU == 16000000 // 16 MHz core, 16 MHz bus, 16 MHz flash SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV4(0); #elif F_CPU == 8000000 // 8 MHz core, 8 MHz bus, 8 MHz flash SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(1); #else #error "Unsupported F_CPU value" #endif // The dividers are set, so we can transition over to PLL for > 16 MHz #if F_CPU > 16000000 // Switch clock source to PLL, keep FLL divider at 512 MCG_C1 = MCG_C1_CLKS(0) | MCG_C1_FRDIV(4); // Wait for the clock to sync while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ; // Use PLL for USB and Bus/peripherals, core for trace and put OSCERCLK0 on CLKOUT pin SIM_SOPT2 = SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK | SIM_SOPT2_TRACECLKSEL_MASK | SIM_SOPT2_CLKOUTSEL(6); #endif // ---------------------------------------------------------------------------------- // Relocate data from flash to RAM as necessary // ---------------------------------------------------------------------------------- // // At the minimum, the .data and .bss sections have to be setup in RAM. Also, since // they are aligned to 4 bytes, we can use uint32s for copying (which is faster than // byte by byte) uint32_t * src = &_etext; uint32_t * dest = &_sdata; while (dest < &_edata) *dest++ = *src++; // Also zero out .bss dest = &_sbss; while (dest < &_ebss) *dest++ = 0; // TODO: Relocate interrupt vector to RAM for speed? // Init systick? #if ENABLE_SYSTICK_HANDLER systick_init(); #endif // Enable interrupts before entering main? #if ENABLE_INTERRUPTS_ON_STARTUP interrupt_enable(); #endif // After everthing is done, call main main(); // This should be unreachable code as long as main() does not return. // To avoid running the instruction pointer into places it shouldn't go, // loop forever // TODO: Going into sleep would maybe be a better solution while (1); }
void ResetHandler(void) { /* * Enable watchdog timer. Allow settings to be changed later, in case the * application firmware wants to adjust its settings or disable it. * * Originally I tried using the 1 kHz low-power oscillator here, but that seemed to * run into an issue where refreshes weren't taking effect. It seems similar to * this problem on the Freescale forums, which didn't really have a satisfactory * solution: * * https://community.freescale.com/thread/309519 * * As a workaround, I'm using the "alternate" system clock. */ { const uint32_t watchdog_timeout = F_BUS / 100; // 10ms WDOG_UNLOCK = WDOG_UNLOCK_SEQ1; WDOG_UNLOCK = WDOG_UNLOCK_SEQ2; asm volatile ("nop"); asm volatile ("nop"); WDOG_STCTRLH = WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN | WDOG_STCTRLH_STOPEN | WDOG_STCTRLH_CLKSRC; WDOG_PRESC = 0; WDOG_TOVALH = watchdog_timeout >> 16; WDOG_TOVALL = watchdog_timeout; } // enable clocks to always-used peripherals SIM_SCGC5 = 0x00043F82; // clocks active to all GPIO SIM_SCGC6 = SIM_SCGC6_RTC | SIM_SCGC6_FTM0 | SIM_SCGC6_FTM1 | SIM_SCGC6_ADC0 | SIM_SCGC6_FTFL; // release I/O pins hold, if we woke up from VLLS mode if (PMC_REGSC & PMC_REGSC_ACKISO) PMC_REGSC |= PMC_REGSC_ACKISO; // start in FEI mode // enable capacitors for crystal OSC0_CR = OSC_SC8P | OSC_SC2P; // enable osc, 8-32 MHz range, low power mode MCG_C2 = MCG_C2_RANGE0(2) | MCG_C2_EREFS; // switch to crystal as clock source, FLL input = 16 MHz / 512 MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(4); // wait for crystal oscillator to begin while ((MCG_S & MCG_S_OSCINIT0) == 0) ; // wait for FLL to use oscillator while ((MCG_S & MCG_S_IREFST) != 0) ; // wait for MCGOUT to use oscillator while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) ; // now we're in FBE mode // config PLL input for 16 MHz Crystal / 4 = 4 MHz MCG_C5 = MCG_C5_PRDIV0(3); // config PLL for 96 MHz output MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(0); // Copy things while we're waiting on the PLL { // Relocate data and text to RAM uint32_t *src = &_eflash; uint32_t *dest = &_sdtext; while (dest < &_edtext) *dest++ = *src++; // Clear BSS dest = &_sbss; while (dest < &_ebss) *dest++ = 0; // Copy IVT to RAM src = (uint32_t*) &gVectors[0]; dest = &ramVectors[0]; while (dest <= &ramVectors[63]) *dest++ = *src++; // Switch to ram IVT SCB_VTOR = (uint32_t) &ramVectors[0]; } // wait for PLL to start using xtal as its input while (!(MCG_S & MCG_S_PLLST)) ; // wait for PLL to lock while (!(MCG_S & MCG_S_LOCK0)) ; // now we're in PBE mode // config divisors: 48 MHz core, 48 MHz bus, 24 MHz flash SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3); // switch to PLL as clock source, FLL input = 16 MHz / 512 MCG_C1 = MCG_C1_CLKS(0) | MCG_C1_FRDIV(4); // wait for PLL clock to be used while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ; // now we're in PEE mode // configure USB for 48 MHz clock SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); // USB = 96 MHz PLL / 2 // USB uses PLL clock, trace is CPU clock, CLKOUT=OSCERCLK0 SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); __enable_irq(); main(); }