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 }