Hello
until now, I have used the FRO96 for USB0 clocking. I would like to be able to switch it to the USBPLL instead.
I'm having difficulties in doing this and I'm not able to find any samples in the SDK that uses the USBPLL (all examples uses FRO96)
I have the code below, any pointers to where the problem is ?
#ifdef USBPLL
// Does not work
const usb_pll_setup_t usb_pllSetup = {
.msel = 15U,
.nsel = 1U,
.psel = 0U,
.direct = false,
.bypass = false,
.fbsel = true,
.inputRate = 12000000U,
};
CLOCK_SetUsbPLLFreq(&usb_pllSetup);
POWER_DisablePD(kPDRUNCFG_PD_USB0_PHY); // Turn on USB Phy
CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 1, false);
CLOCK_AttachClk(kUSB_PLL_to_USB0_CLK); // Attach USB PLL clock to USB
// enable usb0 host clock
CLOCK_EnableClock(kCLOCK_Usbhsl0);
*((uint32_t *)(USBFSH_BASE + 0x5C)) |= USBFSH_PORTMODE_DEV_ENABLE_MASK;
// disable usb0 host clock
CLOCK_DisableClock(kCLOCK_Usbhsl0);
// enable USB IP clock
CLOCK_EnableUsbfs0DeviceClock(kCLOCK_UsbSrcUsbPll, CLOCK_GetFreq(kCLOCK_UsbPll));
#else
// Works
// We use the FRO for the USB clock, turn it on and set it to 96 MHz
POWER_DisablePD(kPDRUNCFG_PD_FRO_EN); // Ensure FRO is on
CLOCK_SetupFROClocking(96000000U); // Set up high frequency FRO output to selected frequency
POWER_DisablePD(kPDRUNCFG_PD_USB0_PHY); // Turn on USB Phy
CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 1, false);
CLOCK_AttachClk(kFRO_HF_to_USB0_CLK); // Attach FRO clock to USB
// enable usb0 host clock
CLOCK_EnableClock(kCLOCK_Usbhsl0);
*((uint32_t *)(USBFSH_BASE + 0x5C)) |= USBFSH_PORTMODE_DEV_ENABLE_MASK;
// disable usb0 host clock
CLOCK_DisableClock(kCLOCK_Usbhsl0);
// enable USB IP clock
CLOCK_EnableUsbfs0DeviceClock(kCLOCK_UsbSrcFro, CLOCK_GetFreq(kCLOCK_FroHf));
#endif
Inside devices\LPC54608\drivers\fsl_clock.c file, there are two modules:
CLOCK_EnableUsbfs0DeviceClock() and CLOCK_EnableUsbhs0DeviceClock(),
When you call CLOCK_EnableUsbfs0DeviceClock(), the first parameter, clock_usb_src_t, use "kCLOCK_UsbPll",
the second parameter doesn't matter because this routine assumes PLL input is 12MHz OSC only.
Since external OSC is the only option as USBPLL input, be careful that you need to power up XTAL related in PDRUNCFG, take a close look in CLOCK_SetUsbPLLFreq() and also make sure your external OSC is connected and working.
/*! @brief USB clock source definition. */
typedef enum _clock_usb_src
{
kCLOCK_UsbSrcFro = (uint32_t)kCLOCK_FroHf, /*!< Use FRO 96 or 48 MHz. */
kCLOCK_UsbSrcSystemPll = (uint32_t)kCLOCK_PllOut, /*!< Use System PLL output. */
kCLOCK_UsbSrcMainClock = (uint32_t)kCLOCK_CoreSysClk, /*!< Use Main clock. */
kCLOCK_UsbSrcUsbPll = (uint32_t)kCLOCK_UsbPll, /*!< Use USB PLL clock. */
kCLOCK_UsbSrcNone = SYSCON_USB0CLKSEL_SEL(7) /*!< Use None, this may be selected in order to reduce power when no output is needed.. */
} clock_usb_src_t;
Thanks Tang,
So the last line in the #ifdef USBPLL can be changed to this:
// enable USB IP clock
CLOCK_EnableUsbfs0DeviceClock(kCLOCK_UsbSrcUsbPll, 0);
I'm pretty sure that the external clock/OSC is working (I hope) as I already use it for the main PLL (running at 180 MHz), the code I use for this is:
void BOARD_BootClockPLL180M(void) {
POWER_DisablePD(kPDRUNCFG_PD_FRO_EN); // Ensure FRO is on
CLOCK_AttachClk(
kFRO12M_to_MAIN_CLK); // Switch to FRO 12MHz first to ensure we can change voltage without accidentally
// being below the voltage for current speed
POWER_SetVoltageForFreq(
12000000U); // Set voltage for the one of the fastest clock outputs: System clock output
CLOCK_SetFLASHAccessCyclesForFreq(12000000U); // Set FLASH wait states for core
// Set up SYS PLL
const pll_setup_t pllSetup = {
.pllctrl = SYSCON_SYSPLLCTRL_SELI(32U) | SYSCON_SYSPLLCTRL_SELP(16U) | SYSCON_SYSPLLCTRL_SELR(0U),
.pllmdec = (SYSCON_SYSPLLMDEC_MDEC(8191U)),
.pllndec = (SYSCON_SYSPLLNDEC_NDEC(770U)),
.pllpdec = (SYSCON_SYSPLLPDEC_PDEC(98U)),
.pllRate = 180000000U,
.flags = PLL_SETUPFLAG_WAITLOCK | PLL_SETUPFLAG_POWERUP};
CLOCK_AttachClk(kEXT_CLK_to_SYS_PLL); // Set sys pll clock source from external crystal
CLOCK_SetPLLFreq(&pllSetup);
POWER_SetVoltageForFreq(
180000000U); // Set voltage for the one of the fastest clock outputs: System clock output
CLOCK_SetFLASHAccessCyclesForFreq(180000000U); // Set FLASH wait states for core
CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U, false); // Reset divider counter and set divider to value 1
CLOCK_SetClkDiv(kCLOCK_DivEmcClk, 0U, true); // Reset EMCCLKDIV divider counter and halt it
CLOCK_SetClkDiv(kCLOCK_DivEmcClk, 2U, false); // Set EMCCLKDIV divider to value 2
CLOCK_AttachClk(kSYS_PLL_to_MAIN_CLK); // Switch System clock to SYS PLL 180MHz
// Switch MAINCLKSELA to FRO12M even it is not used for MAINCLKSELB
SYSCON->MAINCLKSELA = ((SYSCON->MAINCLKSELA & ~SYSCON_MAINCLKSELA_SEL_MASK) | SYSCON_MAINCLKSELA_SEL(0U));
SystemCoreClock = BOARD_BootClockPLL180M_CORE_CLOCK;
So something else must be wrong ?
Is there no example of the usage of the USB PLL available ??
Yes, maybe something else is wrong. The SDK has USB examples for both HS and FS. USB PLL must be
used for USB HS, so these modules should have been tested.
Can you double check the fill-up of pll_setup before CLOCK_SetUsbPLLFreq() is called and the return value
of this function? There is also a modules, CLOCK_GetUsbPLLOutFromSetup(), you can check if you have
the correct setup value before PLL configuration.
Thanks Tang,
I figure I must do something wrong. I followed the CLOCK-SetUsbPLLFreq() function, the pll_setup looks like this:
I can follow the function until it waits for a lock, which never happens!
The USBPLL registers (from SYSCON) looks like this:
When looking at the SYSPLL (which runs at 180 MHz from external xtal), the registers looks like this:
Is there something more I can check to narrow what I have done wrong ?
If th lock never happen after USB PLL configured, while SYSPLL at 180MHz works using xtal, then, your M, P, N, values or mode may be wrong. Have you tried the value and mode from SDK?
Tang,
I got the values etc from the MCUXpresso config tool, this was the code snippet I took from the "clock_config.c" window:
In my own code, I setup the USBPLL after I have configured and switched to the SYSPLL running at 180 MHz.
/* Setup USB PLL (PL160 such that USB_clock to 48MHz going to USB HS PHY. */
/* USB PLL is configured to integer mode:
FCLKOUT = (M * FCLKIN)/N
FCCO = 2 * P * FCLKOUT
FCLKIN = 12MHz, M = 16 (bit 7~0) (msel=3), N = 2 (bit 11~10) (nsel=1), and P = 1 (bit 9~8) (psel=0)
fbsel bit 14 is set. FCLKOUT is 96MHz, FCCO = 192MHz. */
LPC_SYSCON->USBPLLCTRL = (0x1 << 14) | (0xF << 0) | (0x1 << 10) | (0x0 << 8);
while (!(LPC_SYSCON->USBPLLSTAT & 0x01)) {}; /* Wait Until PLL Locked */
Once it locks, USB0CLKDIV needs to be set to 1, divided by 2, to get 48MHz.
You can also use the M, P, N value from SDK, once set USB PLL, then instead of setting
USB1CLKSEL and USB1CLKDIV registers, you can route USB PLL to USB0 by setting USB0CLKSEL and USB1CLKDIV registers respectively.
If you think MCUXpresso clock configuration tool has issues, you can report from their website directly.
Tang,
this also does not work for me. For now I will give up and continue using the FRO96 for USB and hope that a suitable sample using the USBPLL will be included in the SDK at some point (which I think it should have had in the first place..)
Also the documentation of the USBPLL in the UM is not exactly overwhelming :smileywink: