* \author Andrea Righi <arighi@develer.com>
*/
+#include "clock_lm3s.h"
+
#include <cfg/compiler.h>
#include <cfg/debug.h>
-#include "io/lm3s.h"
-#include "clock_lm3s.h"
+
+#include <io/lm3s.h>
+
/* The PLL VCO frequency is 400 MHz */
#define PLL_VCO 400000000UL
/*
* Very small delay: each loop takes 3 cycles.
*/
-INLINE void __delay(unsigned long iterations)
+void NAKED lm3s_busyWait(unsigned long iterations)
{
+ register uint32_t __n asm("r0") = iterations;
+
asm volatile (
- "1: subs %0, #1\n\t"
- " bne 1b\n\t"
- : "=r"(iterations) : : "memory", "cc");
+ "1: subs r0, #1\n\t"
+ "bne 1b\n\t"
+ "bx lr\n\t"
+ : : "r"(__n) : "memory", "cc");
}
-unsigned long clock_get_rate(void)
+INLINE unsigned long clock_get_rate(void)
{
reg32_t rcc = HWREG(SYSCTL_RCC);
return rcc & SYSCTL_RCC_USESYSDIV ?
- PLL_VCO / RCC_TO_DIV(rcc) : PLL_VCO;
+ PLL_VCO / 2 / RCC_TO_DIV(rcc) : PLL_VCO;
}
-void clock_set_rate(void)
+/*
+ * Try to evaluate the correct SYSDIV value depending on the desired CPU
+ * frequency.
+ */
+INLINE int evaluate_sysdiv(unsigned long freq)
+{
+ int i;
+
+ /*
+ * NOTE: with BYPASS=0, SYSDIV < 3 are reserved values (see LM3S1968
+ * Microcontroller DATASHEET, p.78).
+ */
+ for (i = 3; i < 16; i++)
+ if (freq >= (PLL_VCO / 2 / (i + 1)))
+ break;
+ return i;
+}
+
+void clock_init(void)
{
reg32_t rcc, rcc2;
unsigned long clk;
int i;
+ /*
+ * PLL may not function properly at default LDO setting.
+ *
+ * Description:
+ *
+ * In designs that enable and use the PLL module, unstable device
+ * behavior may occur with the LDO set at its default of 2.5 volts or
+ * below (minimum of 2.25 volts). Designs that do not use the PLL
+ * module are not affected.
+ *
+ * Workaround: Prior to enabling the PLL module, it is recommended that
+ * the default LDO voltage setting of 2.5 V be adjusted to 2.75 V using
+ * the LDO Power Control (LDOPCTL) register.
+ *
+ * Silicon Revision Affected: A1, A2
+ *
+ * See also: Stellaris LM3S1968 A2 Errata documentation.
+ */
+ if (REVISION_IS_A1 | REVISION_IS_A2)
+ HWREG(SYSCTL_LDOPCTL) = SYSCTL_LDOPCTL_2_75V;
+
rcc = HWREG(SYSCTL_RCC);
rcc2 = HWREG(SYSCTL_RCC2);
HWREG(SYSCTL_RCC) = rcc;
HWREG(SYSCTL_RCC) = rcc2;
+ lm3s_busyWait(16);
+
/*
* Step #2: select the crystal value (XTAL) and oscillator source
* (OSCSRC), and clear the PWRDN bit in RCC/RCC2. Setting the XTAL
HWREG(SYSCTL_RCC) = rcc;
HWREG(SYSCTL_RCC) = rcc2;
- __delay(16);
+ lm3s_busyWait(16);
/*
* Step #3: select the desired system divider (SYSDIV) in RCC/RCC2 and
*/
rcc &= ~(SYSCTL_RCC_SYSDIV_M | SYSCTL_RCC_USESYSDIV);
- /*
- * Try to evaluate the correct SYSDIV value depending on the desired
- * CPU frequency.
- *
- * NOTE: with BYPASS=0, SYSDIV < 3 are reserved values (see LM3S1968
- * Microcontroller DATASHEET, p.78).
- */
clk = PLL_VCO / 2;
for (i = 3; i < 16; i++)
if (CPU_FREQ >= (clk / (i + 1)))
break;
- if (i)
- rcc |= SYSCTL_RCC_USESYSDIV | (i << SYSCTL_RCC_SYSDIV_SHIFT);
+ rcc |= SYSCTL_RCC_USESYSDIV |
+ (evaluate_sysdiv(CPU_FREQ) << SYSCTL_RCC_SYSDIV_SHIFT);
/*
* Step #4: wait for the PLL to lock by polling the PLLLRIS bit in the
HWREG(SYSCTL_RCC) = rcc;
- __delay(16);
+ lm3s_busyWait(16);
}