I have to change PLL settings to lower clock speed so as to achieve a low-power feature.
I tried with the following:
typedef enum
{
CLOCK_DIV1 = AT91C_PMC_PRES_CLK,
CLOCK_DIV2 = AT91C_PMC_PRES_CLK_2,
CLOCK_DIV4 = AT91C_PMC_PRES_CLK_4,
CLOCK_DIV8 = AT91C_PMC_PRES_CLK_8,
CLOCK_DIV16 = AT91C_PMC_PRES_CLK_16,
CLOCK_DIV32 = AT91C_PMC_PRES_CLK_32,
CLOCK_DIV64 = AT91C_PMC_PRES_CLK_64,
}PllOutputPrescaler_t;
bool ChangePllClock(uint16_t div, uint16_t mul, PllOutputPrescaler_t pres)
{
AT91PS_PMC pPMC = AT91C_BASE_PMC;
if(0 == div || div > 255) return false;
if(0 == mul || mul > 2047) return false;
if((EXT_OC/div)<1000000UL) return false; // PLL input must be at least 1MHz
// maybe
pPMC->PMC_MCKR |= AT91C_PMC_CSS_MAIN_CLK ;
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
pPMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2 ;
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
// 1 Enabling the Main Oscillator:
// it should be already enabled
// 2 Checking the Main Oscillator Frequency (Optional)
// 3 Setting PLL and divider:
// PLLCOUNT pll startup time estimate at : 0.844 ms
// PLLCOUNT 28 = 0.000844 /(1/32768)
pPMC->PMC_PLLR = ((AT91C_CKGR_DIV & div) |
(AT91C_CKGR_PLLCOUNT & (28<<8)) |
(AT91C_CKGR_MUL & ((mul-1)<<16)));
// Wait the startup time
while(!(pPMC->PMC_SR & AT91C_PMC_LOCK));
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
// 4. Selection of Master Clock and Processor Clock
pPMC->PMC_MCKR = pres ;
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
pPMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
return true;
}
I have a crystal @18.432 MHz, In startup I set PLL to run MCK about 48MHz.
In this contest I try to call
ChangePllClock(18, 1, AT91C_PMC_PRES_CLK_2);
but fw will hang
I cannot understand why.
what is the correct sequnce. maybe I must disable the interrups?
note that if I only change prescaler all works.
thanks