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