init_at91.c
Go to the documentation of this file.
00001 00039 #include <io/arm.h> 00040 #include <cfg/macros.h> 00041 00042 #include "cfg/cfg_wdt.h" 00043 00044 #define USE_FIXED_PLL 1 00045 00046 #define XTAL_FREQ 18432000UL 00047 00048 #if USE_FIXED_PLL 00049 #if CPU_FREQ != 48054857L 00050 /* Avoid errors on nightly test */ 00051 #if !defined(ARCH_NIGHTTEST) || !(ARCH & ARCH_NIGHTTEST) 00052 #warning Clock registers set for 48.055MHz operation, revise following code if you want a different clock. 00053 #endif 00054 #endif 00055 00056 /* 00057 * With a 18.432MHz cristal, master clock is: 00058 * (((18.432 * (PLL_MUL_VAL + 1)) / PLL_DIV_VAL) / AT91MCK_PRES) = 48.055MHz 00059 */ 00060 #define PLL_MUL_VAL 72 00061 #define PLL_DIV_VAL 14 00062 #define AT91MCK_PRES PMC_PRES_CLK_2 00063 00064 #else /* !USE_FIXED_PLL*/ 00065 00066 #define PLL_IN_MIN 1000000UL 00067 #define PLL_IN_MAX 32000000UL 00068 #define PLL_OUT_MIN 80000000UL 00069 #define PLL_OUT_MAX 160000000UL 00070 00071 #define DIV_HARD_MIN 1 00072 #define DIV_HARD_MAX 255 00073 00074 #define DIV_MIN (DIV_ROUND(XTAL_FREQ, PLL_IN_MAX) \ 00075 < DIV_HARD_MIN ? DIV_HARD_MIN : DIV_ROUND(XTAL_FREQ, PLL_IN_MAX)) 00076 00077 #define DIV_MAX (DIV_ROUND(XTAL_FREQ, PLL_IN_MIN) \ 00078 > DIV_HARD_MAX ? DIV_HARD_MAX : DIV_ROUND(XTAL_FREQ, PLL_IN_MIN)) 00079 00080 #define MUL_MIN 0 00081 #define MUL_MAX 2047 00082 00083 typedef struct PllRegs 00084 { 00085 uint32_t mul; 00086 uint32_t div; 00087 uint32_t pres; 00088 } PllRegs; 00089 00095 static const PllRegs pllCostants(void) 00096 { 00097 uint32_t best_err = CPU_FREQ; 00098 PllRegs res; 00099 00100 for (uint32_t div = DIV_MIN; div <= DIV_MAX; div++) 00101 { 00102 for (uint32_t pres = 0; pres < 8; pres++) 00103 { 00104 uint32_t mul = DIV_ROUND((CPU_FREQ * div) << pres, XTAL_FREQ) - 1; 00105 if (mul <= MUL_MAX) 00106 { 00107 uint32_t pll = (XTAL_FREQ * (mul + 1)) / div; 00108 if (pll >= PLL_OUT_MIN && pll <= PLL_OUT_MAX) 00109 { 00110 uint32_t err = ABS((int32_t)((pll >> pres) - CPU_FREQ)); 00111 if (err == 0) 00112 { 00113 res.div = div; 00114 res.mul = mul; 00115 res.pres = pres; 00116 return res; 00117 } 00118 if (err < best_err) 00119 { 00120 best_err = err; 00121 res.div = div; 00122 res.mul = mul; 00123 res.pres = pres; 00124 } 00125 } 00126 } 00127 } 00128 } 00129 return res; 00130 } 00131 #endif /* !USE_FIXED_PLL*/ 00132 00133 /* 00134 * Override dummy hardware init functions supplied by the ASM startup 00135 * routine. 00136 */ 00137 00138 void __init1(void); 00139 void __init2(void); 00140 00153 void __init1(void) 00154 { 00155 /* 00156 * Compute number of master clock cycles in 1.5us. 00157 * Needed by flash writing functions. 00158 * The maximum FMCN value is 0xFF and 0 can be used only if 00159 * master clock is less than 33kHz. 00160 */ 00161 #define MCN DIV_ROUNDUP(CPU_FREQ, 666667UL) 00162 #define FMCN (CPU_FREQ <= 33333UL ? 0 : (MCN < 0xFF ? MCN : 0xFF)) 00163 00164 #if CPU_FREQ < 30000000UL 00165 /* Use 1 cycles for flash access. */ 00166 MC_FMR = FMCN << MC_FMCN_SHIFT | MC_FWS_1R2W; 00167 #else 00168 /* Use 2 cycles for flash access. */ 00169 MC_FMR = FMCN << MC_FMCN_SHIFT | MC_FWS_2R3W; 00170 #endif 00171 00172 /* Disable all interrupts. Useful for debugging w/o target reset. */ 00173 AIC_EOICR = 0xFFFFFFFF; 00174 AIC_IDCR = 0xFFFFFFFF; 00175 00176 #if CONFIG_WATCHDOG == 0 00177 /* The watchdog is enabled after processor reset. Disable it. */ 00178 WDT_MR = BV(WDT_WDDIS); 00179 #endif 00180 00181 /* 00182 * Enable the main oscillator. Set startup time of 6 * 8 slow 00183 * clock cycles and wait until oscillator is stabilized. 00184 */ 00185 CKGR_MOR = (6 << 8) | BV(CKGR_MOSCEN); 00186 while (!(PMC_SR & BV(PMC_MOSCS))) ; 00187 00188 /* Switch to Slow oscillator clock. */ 00189 PMC_MCKR &= ~PMC_CSS_MASK; 00190 while (!(PMC_SR & BV(PMC_MCKRDY))) ; 00191 00192 /* Switch to prescaler div 1 factor. */ 00193 PMC_MCKR &= ~PMC_PRES_MASK; 00194 while (!(PMC_SR & BV(PMC_MCKRDY))) ; 00195 00196 uint32_t div, pres, mul; 00197 #if USE_FIXED_PLL 00198 div = PLL_DIV_VAL; 00199 mul = PLL_MUL_VAL; 00200 pres = AT91MCK_PRES; 00201 #else 00202 PllRegs pll = pllCostants(); 00203 div = pll.div; 00204 mul = pll.mul; 00205 pres = pll.pres << PMC_PRES_SHIFT; 00206 #endif 00207 00208 /* 00209 * Set PLL: 00210 * PLLfreq = crystal / divider * (multiplier + 1) 00211 * Wait 28 clock cycles until PLL is locked. 00212 */ 00213 CKGR_PLLR = ((mul << CKGR_MUL_SHIFT) 00214 | (28 << CKGR_PLLCOUNT_SHIFT) | div); 00215 while (!(PMC_SR & BV(PMC_LOCK))) ; 00216 00217 /* Set master clock prescaler. */ 00218 PMC_MCKR = pres; 00219 while (!(PMC_SR & BV(PMC_MCKRDY))) ; 00220 00221 /* 00222 * Switch to PLL clock. Trying to set this together with the 00223 * prescaler fails (see datasheets). 00224 */ 00225 PMC_MCKR |= PMC_CSS_PLL_CLK; 00226 while (!(PMC_SR & BV(PMC_MCKRDY))) ; 00227 } 00228 00234 void __init2(void) 00235 { 00236 /* Enable external reset key. */ 00237 RSTC_MR = (RSTC_KEY | BV(RSTC_URSTEN)); 00238 00239 /* Enable clock for PIO(s) */ 00240 PMC_PCER = BV(PIOA_ID); 00241 #if CPU_ARM_SAM7X 00242 PMC_PCER |= BV(PIOB_ID); 00243 #endif 00244 }
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)