Configuring PLL (writing N, P and K values into register) produces an interrupt?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hi all,

I have used the following code to configure a PLL module and, consequently, the rest of the clocks that are derived from fPLL signal. It is similar to the structure used in examples, in fact, I copied the structure to make sure there are no mistakes.

XMC_SCU_CLOCK_CONFIG_t clock_config =
{
.syspll_config.n_div = 80U,
.syspll_config.p_div = 2U,
.syspll_config.k_div = 4U,
.syspll_config.mode = XMC_SCU_CLOCK_SYSPLL_MODE_NORMAL,
.syspll_config.clksrc = XMC_SCU_CLOCK_SYSPLLCLKSRC_OSCHP,
.enable_oschp = true,
.enable_osculp = false,
.calibration_mode = XMC_SCU_CLOCK_FOFI_CALIBRATION_MODE_FACTORY,
.fstdby_clksrc = XMC_SCU_HIB_STDBYCLKSRC_OSI,
.fsys_clksrc = XMC_SCU_CLOCK_SYSCLKSRC_PLL,
.fsys_clkdiv = 1U,
.fcpu_clkdiv = 1U,
.fccu_clkdiv = 1U,
.fperipheral_clkdiv = 1U
};


However, the code "breaks" when the above configuration is called from inside the main() function. However, if I use the default settings, the code works. I have tracked the problem down to this particular command inside the XMC_SCU_CLOCK_StartSystemPll(source, mode, ndiv, pdiv, kdiv):

    SCU_PLL->PLLCON1 = (uint32_t)((SCU_PLL->PLLCON1 & ~(SCU_PLL_PLLCON1_NDIV_Msk | SCU_PLL_PLLCON1_K2DIV_Msk |
SCU_PLL_PLLCON1_PDIV_Msk)) | ((ndiv - 1UL) << SCU_PLL_PLLCON1_NDIV_Pos) |
((kdiv_temp - 1UL) << SCU_PLL_PLLCON1_K2DIV_Pos) |
((pdiv - 1UL)<< SCU_PLL_PLLCON1_PDIV_Pos));


The "Disassembly" window indicates that the code stops working properly at the following line, after stopping on '08000ccc' and stepping into '08000cce'.

1333 SCU_PLL->PLLCON1 = (uint32_t)((SCU_PLL->PLLCON1 & ~(SCU_PLL_PLLCON1_NDIV_Msk | SCU_PLL_PLLCON1_K2DIV_Msk |
08000cc8: ldr r1, [pc, #252] ; (0x8000dc8 )
08000cca: ldr r3, [pc, #252] ; (0x8000dc8 )
08000ccc: ldr r2, [r3, #8]
08000cce: ldr r3, [pc, #252] ; (0x8000dcc )


Regards,
Andrey
0 Likes
3 Replies
chismo
Employee
Employee
First like received
Hello Andrey,

I believe the problem is because the PLL loss of lock trap is enabled after startup.
From the code:

/* disconnect Oscillator from PLL */
SCU_PLL->PLLCON0 |= (uint32_t)SCU_PLL_PLLCON0_FINDIS_Msk;

/* Setup divider settings for main PLL */
SCU_PLL->PLLCON1 = (uint32_t)((SCU_PLL->PLLCON1 & ~(SCU_PLL_PLLCON1_NDIV_Msk | SCU_PLL_PLLCON1_K2DIV_Msk |
SCU_PLL_PLLCON1_PDIV_Msk)) | ((ndiv - 1UL) << SCU_PLL_PLLCON1_NDIV_Pos) |
((kdiv_temp - 1UL) << SCU_PLL_PLLCON1_K2DIV_Pos) |
((pdiv - 1UL)<< SCU_PLL_PLLCON1_PDIV_Pos));


You will see that prior to the PLL configuration (write to PLLCON1 register), the oscillator is disconnected and this triggers a trap event if trap is enabled.

As a workaround, I suggest to disable the trap before running the clock init function:

SCU_TRAP->TRAPDIS=0x1FD; // Restore TRAPDIS settings to default values
XMC_SCU_CLOCK_Init(&clock_config);


I will also feedback this issue to the relevant colleagues.

Regards,
Min Wei
0 Likes
Not applicable
Hi Min Wei,

Thank you for your reply! Unfortunately, resetting TRAPDIS register nor doing so in conjunction with clearing trap requests with TRAPCLR did not solve the problem. I will continue to look into this issue and will make sure to post here if I happen to find a solution.

As a side note, perhaps this may be useful - I followed some steps listed in an article that describes how to "debug and diagnose Hard Faults on ARM Cortex-M CPUs". As a result of inserting a snippet that the website provides into the Default Hadnler, the "position" of the interrupt in the NVIC is copied into R2.The value that ended up in that register is '2', which is an NMI Handler? (Aside: I've heard that the name of the default interrupt that is shown in the "Disassmebler" is of no significance - but in case it is, it was listed as VADC3_G3_IRQHandler). Hopefully that sheds some more light on the issue.

Regards,
Andrey
0 Likes
Not applicable
Hi Min Wei,

You are right about the issue - PLL loss of lock trap is triggered when VCO is disconnected from the oscillator. Unfortunately I am not sure why disabling trap requests from outside the XMC_SCU_CLOCK_Init() function did not resolve the issue - however, adding the following piece of code inside the header file did its job.

   /* Switch to prescaler mode */
SCU_PLL->PLLCON0 |= (uint32_t)SCU_PLL_PLLCON0_VCOBYP_Msk;

/* Updated on Jan. 25, 2016
* Clear and Disable VCO Lock Trap Request and Clear Trap Flag
* Fixed trap generation error when VCO is disconnected from Oscillator
*/

SCU_TRAP->TRAPCLR |= SCU_TRAP_TRAPCLR_SVCOLCKT_Msk;
SCU_TRAP->TRAPDIS |= SCU_TRAP_TRAPDIS_SVCOLCKT_Msk;

/* End Update */

/* disconnect Oscillator from PLL */
SCU_PLL->PLLCON0 |= (uint32_t)SCU_PLL_PLLCON0_FINDIS_Msk;


Also, the following command is present in the system_xmc.c file, but is missing in xmc4_scu.h file. Without both clearing and enabling the trap request generation, the initialization produces an interrupt. I believe this occurs because trap request flags are set regardless of whether a certain trap is enabled or disabled - the latter determines whether the uC does anything (e.g. generate an interrupt) upon "seeing" that flag.

    /* Switch to normal mode */
SCU_PLL->PLLCON0 &= (uint32_t)~SCU_PLL_PLLCON0_VCOBYP_Msk;
while ((SCU_PLL->PLLSTAT & SCU_PLL_PLLSTAT_VCOBYST_Msk) != 0U)
{
/* wait for normal mode */
}

/* Updated on Jan. 25, 2016
* Re-enable VCO Lock Trap Request
* Fixed trap generation error when VCO is disconnected from Oscillator
*/
SCU_TRAP->TRAPCLR |= SCU_TRAP_TRAPCLR_SVCOLCKT_Msk;
SCU_TRAP->TRAPDIS &= ~SCU_TRAP_TRAPDIS_SVCOLCKT_Msk;

/* End update */


Thank you once again for a great troubleshooting suggestion that led to fixing this issue.

Regards,
Andrey
0 Likes