From: batt Date: Wed, 31 Mar 2010 10:56:08 +0000 (+0000) Subject: AT91SAM7 Add hw initialization C routines. X-Git-Tag: 2.5.0~565 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=5e046ad751e05b325e5337bd26b22e340ac8ad67;p=bertos.git AT91SAM7 Add hw initialization C routines. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@3343 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/bertos/cpu/arm/hw/init_at91.c b/bertos/cpu/arm/hw/init_at91.c new file mode 100644 index 00000000..9c3eeb20 --- /dev/null +++ b/bertos/cpu/arm/hw/init_at91.c @@ -0,0 +1,226 @@ +/** + * \file + * + * + * + * \author Francesco Sacchi + * + * \brief AT91SAM7S256 CRT. + */ + +#include +#include + +#define USE_FIXED_PLL 1 + +#define XTAL_FREQ 18420000UL + +#if USE_FIXED_PLL + #if CPU_FREQ != 48023000L + /* Avoid errors on nightly test */ + #if !defined(ARCH_NIGHTTEST) || !(ARCH & ARCH_NIGHTTEST) + #warning Clock registers set for 48.023MHz operation, revise following code if you want a different clock. + #endif + #endif + + /* + * With a 18.420MHz cristal, master clock is: + * (((18.420 * PLL_MUL_VAL + 1) / PLL_DIV_VAL) / AT91MCK_PRES) = 48.023MHz + */ + #define PLL_MUL_VAL 72 /**< Real multiplier value is PLL_MUL_VAL + 1! */ + #define PLL_DIV_VAL 14 + #define AT91MCK_PRES PMC_PRES_CLK_2 + +#else /* !USE_FIXED_PLL*/ + + #define PLL_IN_MIN 1000000UL + #define PLL_IN_MAX 32000000UL + #define PLL_OUT_MIN 80000000UL + #define PLL_OUT_MAX 160000000UL + + #define DIV_HARD_MIN 1 + #define DIV_HARD_MAX 255 + + #define DIV_MIN (DIV_ROUND(XTAL_FREQ, PLL_IN_MAX) \ + < DIV_HARD_MIN ? DIV_HARD_MIN : DIV_ROUND(XTAL_FREQ, PLL_IN_MAX)) + + #define DIV_MAX (DIV_ROUND(XTAL_FREQ, PLL_IN_MIN) \ + > DIV_HARD_MAX ? DIV_HARD_MAX : DIV_ROUND(XTAL_FREQ, PLL_IN_MIN)) + + #define MUL_MIN 0 + #define MUL_MAX 2047 + + typedef struct PllRegs + { + uint32_t mul; + uint32_t div; + uint32_t pres; + } PllRegs; + + /** + * Code used to automatically compute the PLL registers. + * Since the processor uses the internal 32kHz oscillator + * this function takes a lot of time to be executed (~3s!). + */ + static const PllRegs pllCostants(void) + { + uint32_t best_err = CPU_FREQ; + PllRegs res; + + for (uint32_t div = DIV_MIN; div <= DIV_MAX; div++) + { + for (uint32_t pres = 0; pres < 8; pres++) + { + uint32_t mul = DIV_ROUND((CPU_FREQ * div) << pres, XTAL_FREQ) - 1; + if (mul <= MUL_MAX) + { + uint32_t pll = (XTAL_FREQ * (mul + 1)) / div; + if (pll >= PLL_OUT_MIN && pll <= PLL_OUT_MAX) + { + uint32_t err = ABS((int32_t)((pll >> pres) - CPU_FREQ)); + if (err == 0) + { + res.div = div; + res.mul = mul; + res.pres = pres; + return res; + } + if (err < best_err) + { + best_err = err; + res.div = div; + res.mul = mul; + res.pres = pres; + } + } + } + } + } + return res; + } +#endif /* !USE_FIXED_PLL*/ + +/* + * Override dummy hardware init functions supplied by the ASM startup + * routine. + */ + +void __init1(void); +void __init2(void); + +/** + * Early hardware initialization routine1. + * This will be called by the ASM CRT routine just + * *before* clearing .bss and loading .data sections. + * Usually only basic tasks are performed here (i.e. setting the PLL). + * For more generic tasks, __init2() should be used. + * + * \note Please keep in mind that since .bss and .data are not yet set, care + * must be taken. No static data can be used inside this funcition. + * Also some libc functions or floating point operations could potentially + * use initialized static data, be aware! + */ +void __init1(void) +{ + /* Use 2 cycles for flash access. */ + MC_FMR = MC_FWS_2R3W; + + /* Disable all interrupts. Useful for debugging w/o target reset. */ + AIC_EOICR = 0xFFFFFFFF; + AIC_IDCR = 0xFFFFFFFF; + + /* The watchdog is enabled after processor reset. Disable it. */ + WDT_MR = BV(WDT_WDDIS); + + /* + * Enable the main oscillator. Set startup time of 6 * 8 slow + * clock cycles and wait until oscillator is stabilized. + */ + CKGR_MOR = (6 << 8) | BV(CKGR_MOSCEN); + while (!(PMC_SR & BV(PMC_MOSCS))) ; + + /* Switch to Slow oscillator clock. */ + PMC_MCKR &= ~PMC_CSS_MASK; + while (!(PMC_SR & BV(PMC_MCKRDY))) ; + + /* Switch to prescaler div 1 factor. */ + PMC_MCKR &= ~PMC_PRES_MASK; + while (!(PMC_SR & BV(PMC_MCKRDY))) ; + + uint32_t div, pres, mul; + #if USE_FIXED_PLL + div = PLL_DIV_VAL; + mul = PLL_MUL_VAL; + pres = AT91MCK_PRES; + #else + PllRegs pll = pllCostants(); + div = pll.div; + mul = pll.mul; + pres = pll.pres << PMC_PRES_SHIFT; + #endif + + /* + * Set PLL: + * PLLfreq = crystal / divider * (multiplier + 1) + * Wait 28 clock cycles until PLL is locked. + */ + CKGR_PLLR = ((mul << CKGR_MUL_SHIFT) + | (28 << CKGR_PLLCOUNT_SHIFT) | div); + while (!(PMC_SR & BV(PMC_LOCK))) ; + + /* Set master clock prescaler. */ + PMC_MCKR = pres; + while (!(PMC_SR & BV(PMC_MCKRDY))) ; + + /* + * Switch to PLL clock. Trying to set this together with the + * prescaler fails (see datasheets). + */ + PMC_MCKR |= PMC_CSS_PLL_CLK; + while (!(PMC_SR & BV(PMC_MCKRDY))) ; +} + +/** + * Early hardware initialization routine2. + * This will be called by the ASM CRT routine just + * *after* clearing .bss and loading .data sections and before calling main(). + */ +void __init2(void) +{ + /* Enable external reset key. */ + RSTC_MR = (RSTC_KEY | BV(RSTC_URSTEN)); + + /* Enable clock for PIO(s) */ + PMC_PCER = BV(PIOA_ID); + #if CPU_ARM_SAM7X + PMC_PCER |= BV(PIOB_ID); + #endif +}