changing PLL settings @ runtime on SAM7X

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 :frowning:

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