clock_lm3s.c
Go to the documentation of this file.00001 00038 #include <cfg/compiler.h> 00039 #include <cfg/debug.h> 00040 #include <io/lm3s.h> 00041 #include "clock_lm3s.h" 00042 00043 /* The PLL VCO frequency is 400 MHz */ 00044 #define PLL_VCO 400000000UL 00045 00046 /* Extract the system clock divisor from the RCC register */ 00047 #define RCC_TO_DIV(rcc) \ 00048 (((rcc & SYSCTL_RCC_SYSDIV_MASK) >> \ 00049 SYSCTL_RCC_SYSDIV_SHIFT) + 1) 00050 00051 /* 00052 * Very small delay: each loop takes 3 cycles. 00053 */ 00054 void NAKED lm3s_busyWait(unsigned long iterations) 00055 { 00056 register uint32_t __n asm("r0") = iterations; 00057 00058 asm volatile ( 00059 "1: subs r0, #1\n\t" 00060 "bne 1b\n\t" 00061 "bx lr\n\t" 00062 : : "r"(__n) : "memory", "cc"); 00063 } 00064 00065 INLINE unsigned long clock_get_rate(void) 00066 { 00067 reg32_t rcc = HWREG(SYSCTL_RCC); 00068 00069 return rcc & SYSCTL_RCC_USESYSDIV ? 00070 PLL_VCO / 2 / RCC_TO_DIV(rcc) : PLL_VCO; 00071 } 00072 00073 /* 00074 * Try to evaluate the correct SYSDIV value depending on the desired CPU 00075 * frequency. 00076 */ 00077 INLINE int evaluate_sysdiv(unsigned long freq) 00078 { 00079 int i; 00080 00081 /* 00082 * NOTE: with BYPASS=0, SYSDIV < 3 are reserved values (see LM3S1968 00083 * Microcontroller DATASHEET, p.78). 00084 */ 00085 for (i = 3; i < 16; i++) 00086 if (freq >= (PLL_VCO / 2 / (i + 1))) 00087 break; 00088 return i; 00089 } 00090 00091 void clock_init(void) 00092 { 00093 reg32_t rcc, rcc2; 00094 unsigned long clk; 00095 int i; 00096 00097 rcc = HWREG(SYSCTL_RCC); 00098 rcc2 = HWREG(SYSCTL_RCC2); 00099 00100 /* 00101 * Step #1: bypass the PLL and system clock divider by setting the 00102 * BYPASS bit and clearing the USESYS bit in the RCC register. This 00103 * configures the system to run off a “raw” clock source (using the 00104 * main oscillator or internal oscillator) and allows for the new PLL 00105 * configuration to be validated before switching the system clock to 00106 * the PLL. 00107 */ 00108 rcc |= SYSCTL_RCC_BYPASS; 00109 rcc &= ~SYSCTL_RCC_USESYSDIV; 00110 rcc2 |= SYSCTL_RCC2_BYPASS2; 00111 00112 /* Write back RCC/RCC2 registers */ 00113 HWREG(SYSCTL_RCC) = rcc; 00114 HWREG(SYSCTL_RCC) = rcc2; 00115 00116 lm3s_busyWait(16); 00117 00118 /* 00119 * Step #2: select the crystal value (XTAL) and oscillator source 00120 * (OSCSRC), and clear the PWRDN bit in RCC/RCC2. Setting the XTAL 00121 * field automatically pulls valid PLL configuration data for the 00122 * appropriate crystal, and clearing the PWRDN bit powers and enables 00123 * the PLL and its output. 00124 */ 00125 00126 /* Enable the main oscillator first. */ 00127 rcc &= ~(SYSCTL_RCC_IOSCDIS | SYSCTL_RCC_MOSCDIS); 00128 rcc |= SYSCTL_RCC_IOSCDIS; 00129 00130 /* Do not override RCC register fields */ 00131 rcc2 &= ~SYSCTL_RCC2_USERCC2; 00132 00133 rcc &= ~(SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M | SYSCTL_RCC_PWRDN); 00134 rcc |= XTAL_FREQ | SYSCTL_RCC_OSCSRC_MAIN; 00135 00136 /* Clear the PLL lock interrupt. */ 00137 HWREG(SYSCTL_MISC) = SYSCTL_INT_PLL_LOCK; 00138 00139 HWREG(SYSCTL_RCC) = rcc; 00140 HWREG(SYSCTL_RCC) = rcc2; 00141 00142 lm3s_busyWait(16); 00143 00144 /* 00145 * Step #3: select the desired system divider (SYSDIV) in RCC/RCC2 and 00146 * set the USESYS bit in RCC. The SYSDIV field determines the system 00147 * frequency for the microcontroller. 00148 */ 00149 rcc &= ~(SYSCTL_RCC_SYSDIV_M | SYSCTL_RCC_USESYSDIV); 00150 00151 clk = PLL_VCO / 2; 00152 for (i = 3; i < 16; i++) 00153 if (CPU_FREQ >= (clk / (i + 1))) 00154 break; 00155 rcc |= SYSCTL_RCC_USESYSDIV | 00156 (evaluate_sysdiv(CPU_FREQ) << SYSCTL_RCC_SYSDIV_SHIFT); 00157 00158 /* 00159 * Step #4: wait for the PLL to lock by polling the PLLLRIS bit in the 00160 * Raw Interrupt Status (RIS) register. 00161 */ 00162 for (i = 0; i < 32768; i++) 00163 if (HWREG(SYSCTL_RIS) & SYSCTL_INT_PLL_LOCK) 00164 break; 00165 00166 /* 00167 * Step #5: enable use of the PLL by clearing the BYPASS bit in 00168 * RCC/RCC2. 00169 */ 00170 rcc &= ~SYSCTL_RCC_BYPASS; 00171 00172 HWREG(SYSCTL_RCC) = rcc; 00173 00174 lm3s_busyWait(16); 00175 }
