EmbeddedRelated.com
Forums

LPC1800 PLL /CMSIS library issues - beware the LOCK bit!

Started by Mike Harrison February 5, 2013
Just found an undocumented issue with PLL1 on the LPC1830 (NGX LPC1830-Xplorer board, Silicon rev A)
The PLL1 LOCK status can bounce low a few times after it initially goes high.

See this scope trace (Source 12MHz Xtal osc, x6 multiplier = 72MHz)
http://electricstuff.co.uk/temp/lpc1800_pll_lock_glitch.jpg

Although this is a minor problem in itself, the library supplied with the NGX IAR examples includes
this unfortunate line in lpc18xx_cgu.c, cgu_EnableEntity :

while((LPC_CGU->PLL1_STAT&1) == 0x0);
/*post check lock status */
if(!(LPC_CGU->PLL1_STAT&1))
while(1);

The post-check can cause a lockup if the lock bit glitches.

I don't know how widespread this library file is, but it appears to originally come from NXP.

It also has another issue in that it changes the PLL settings while the core clock is connected to
the PLL, which can cause odd things to happen :

This is the original code, with a commented out line and a comment that disabling the PLL causes a
hang :

uint32_t CGU_Init(void){
CGU_SetXTALOSC(12000000);
CGU_EnableEntity(CGU_CLKSRC_XTAL_OSC, ENABLE);
CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_CLKSRC_PLL1);
// Disable PLL1 CPU hang???
//CGU_EnableEntity(CGU_CLKSRC_PLL1, DISABLE);
CGU_SetPLL1(6);
CGU_EnableEntity(CGU_CLKSRC_PLL1, ENABLE);
CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_M3);
CGU_UpdateClock();
return 0;

To fix this, add the following line before CGU_SetXTALOSC, and uncomment the disable PLL line :

CGU_EntityConnect(CGU_CLKSRC_IRC, CGU_BASE_M3); // set core to IRC so we can safely switch PLL

An Engineer's Guide to the LPC2100 Series

Il 06/02/2013 00:24, Mike Harrison ha scritto:
>
>
> Just found an undocumented issue with PLL1 on the LPC1830 (NGX
> LPC1830-Xplorer board, Silicon rev A)
> The PLL1 LOCK status can bounce low a few times after it initially
> goes high.
>
> See this scope trace (Source 12MHz Xtal osc, x6 multiplier = 72MHz)
> http://electricstuff.co.uk/temp/lpc1800_pll_lock_glitch.jpg
>
> Although this is a minor problem in itself, the library supplied with
> the NGX IAR examples includes
> this unfortunate line in lpc18xx_cgu.c, cgu_EnableEntity :
>
> while((LPC_CGU->PLL1_STAT&1) == 0x0);
> /*post check lock status */
> if(!(LPC_CGU->PLL1_STAT&1))
> while(1);
>
> The post-check can cause a lockup if the lock bit glitches.
>
> I don't know how widespread this library file is, but it appears to
> originally come from NXP.
>
It is right but during my debugging I suggested a simple modifications
in 2 points of
uint32_t CGU_EnableEntity(CGU_ENTITY_T ClockEntity, uint32_t en)
that are marked:
/*Delay for stable clock*/
for(i = 0;i<1000000;i++);

the 1st is on the last row of this else:
else if(ClockEntity == CGU_CLKSRC_XTAL_OSC){

and the 2nd is just before the while block you copied.
Do you have this release or a different one?
> It also has another issue in that it changes the PLL settings while
> the core clock is connected to
> the PLL, which can cause odd things to happen :
>
> This is the original code, with a commented out line and a comment
> that disabling the PLL causes a
> hang :
>
> uint32_t CGU_Init(void){
> CGU_SetXTALOSC(12000000);
> CGU_EnableEntity(CGU_CLKSRC_XTAL_OSC, ENABLE);
> CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_CLKSRC_PLL1);
> // Disable PLL1 CPU hang???
> //CGU_EnableEntity(CGU_CLKSRC_PLL1, DISABLE);
> CGU_SetPLL1(6);
> CGU_EnableEntity(CGU_CLKSRC_PLL1, ENABLE);
> CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_M3);
> CGU_UpdateClock();
> return 0;
>
> To fix this, add the following line before CGU_SetXTALOSC, and
> uncomment the disable PLL line :
>
> CGU_EntityConnect(CGU_CLKSRC_IRC, CGU_BASE_M3); // set core to IRC so
> we can safely switch PLL
>

there is a big error in the code you copied here because the PLL1 should
be enabled at the end of the procedure this is a copy of the
configuration I worked during the tests (so it is tailored to the Hitex
board but the idea should be the same). It is a test configuration to
test also some operations on the enabled PLL to see if they can work.
This procedure in my tests is faster then programming the PLL1 directly
to 204MHz (apart the emc delays):

void Hitex_CGU_Init(void)
{
uint32_t EMCClk;

__disable_irq();
MemoryPinInit(); // Make sure EMC is in high-speed pin mode

/* Set the XTAL oscillator frequency to 12MHz*/
CGU_SetXTALOSC(__CRYSTAL);
CGU_EnableEntity(CGU_CLKSRC_XTAL_OSC, ENABLE);
CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_BASE_M3);

/* Set PL160M 12*1 = 12 MHz */
CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_CLKSRC_PLL1);
CGU_SetPLL1(1);
CGU_EnableEntity(CGU_CLKSRC_PLL1, ENABLE);

/* Run SPIFI from PL160M, /2 */
CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_CLKSRC_IDIVA);
CGU_EnableEntity(CGU_CLKSRC_IDIVA, ENABLE);
CGU_SetDIV(CGU_CLKSRC_IDIVA, 2);
CGU_EntityConnect(CGU_CLKSRC_IDIVA, CGU_BASE_SPIFI);
CGU_UpdateClock();

LPC_CCU1->CLK_M4_EMCDIV_CFG |= (1<<0) | (1<<5); // Turn
on clock / 2
LPC_CREG->CREG6 |= (1<<16); // EMC divided by 2
LPC_CCU1->CLK_M4_EMC_CFG |= (1<<0); // Turn on clock

/* Set PL160M @ 12*98 MHz */
CGU_SetPLL1(9);

/* Run base M3 clock from PL160M, no division */
CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_M3);

emc_WaitMS(10);

/* Change the clock to 204 MHz */
/* Set PL160M @ 12*150 MHz */
CGU_SetPLL1(17);

emc_WaitMS(10);

CGU_UpdateClock();

EMCFlashInit();

vEMC_InitSRDRAM(SDRAM_BASE_ADDR, SDRAM_WIDTH, SDRAM_SIZE_MBITS,
SDRAM_DATA_BUS_BITS, SDRAM_COL_ADDR_BITS);
LPC_SCU->SFSP3_3 = 0xF3; /* high drive for SCLK */
/* IO pins */
LPC_SCU->SFSP3_4=LPC_SCU->SFSP3_5=LPC_SCU->SFSP3_6=LPC_SCU->SFSP3_7
= 0xD3;
LPC_SCU->SFSP3_8 = 0x13; /* CS doesn't need feedback */

EMCClk = CGU_GetPCLKFrequency(CGU_PERIPHERAL_M3CORE)/2;

if (spifi_init(&sobj, 9, S_RCVCLK | S_FULLCLK, EMCClk)) {
if (spifi_init(&sobj, 9, S_RCVCLK | S_FULLCLK, EMCClk)) {
while(1);
}
}
__enable_irq();
// SPIFI_Init();
}