X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Fcortex-m3%2Fdrv%2Fclock_sam3.c;h=ae70d52999ae20b35574f792aac35c0e7a7fd2ba;hb=93308de29d9092161217cfff1b1375b482937214;hp=967e3798b6613429ef293e4675b8ed78286f9601;hpb=3c57e466444d95d4358eb4f0e2a8130dcfb0f55b;p=bertos.git diff --git a/bertos/cpu/cortex-m3/drv/clock_sam3.c b/bertos/cpu/cortex-m3/drv/clock_sam3.c index 967e3798..ae70d529 100644 --- a/bertos/cpu/cortex-m3/drv/clock_sam3.c +++ b/bertos/cpu/cortex-m3/drv/clock_sam3.c @@ -36,7 +36,58 @@ */ #include "clock_sam3.h" +#include +#include +#include + +/* Value to use when writing CKGR_MOR, to unlock write */ +#define CKGR_KEY 0x37 + +/* + * Try to evaluate the correct divider and multiplier value depending + * on the desired CPU frequency. + * + * We try all combinations in a certain range of divider and multiplier + * values. The range can change, with better match with "strange" + * frequencies, but boot time will be longer. + * + * Limits for SAM3N: divider [1,255], multiplier [1,2047]. + */ +INLINE uint32_t evaluate_pll(void) +{ + int mul, div, best_mul, best_div; + int best_delta = CPU_FREQ; + int freq = 0; + + for (mul = 1; mul <= 8; mul++) + { + for (div = 1; div <= 24; div++) + { + // RC oscillator set to 12 MHz + freq = 12000000 / div * (1 + mul); + if (ABS(CPU_FREQ - freq) < best_delta) { + best_delta = ABS(CPU_FREQ - freq); + best_mul = mul; + best_div = div; + } + } + } + + // Bit 29 must always be set to 1 + return CKGR_PLLR_DIV(best_div) | CKGR_PLLR_MUL(best_mul) | BV(29); +} + void clock_init(void) { + /* Enable and configure internal Fast RC oscillator */ + CKGR_MOR_R = + CKGR_MOR_KEY(CKGR_KEY) // Unlock key + | CKGR_MOR_MOSCRCEN // Main On-Chip RC oscillator enable + | CKGR_MOR_MOSCRCF_12MHZ; // RC oscillator frequency + + /* Master clock: select PLL clock and no prescaling */ + PMC_MCKR_R = PMC_MCKR_CSS_PLL_CLK; + + CKGR_PLLR_R = evaluate_pll(); }