GEORGE VERNON

MK20DX256VLQ10 Core Clock and USB Configuration

Discussion created by GEORGE VERNON on Sep 3, 2013
Latest reply on Jan 30, 2014 by Jei Chou

I recently had an issue operating the MK20DX256VLQ10 processor core clock at 96MHz and getting the USB host to operate at full speed. It appeared that when the core clock was set to 96MHz, the USB wanted to clock data at 24Mbits/s. Initially I opted to set the core clock to 48MHz and derive the USB clock using SIM_CLKDIV2 set to divide by 1. This set the USB to clock data at the nominal 12Mbits/s full speed rate, but was somewhat dissatisfying from the standpoint that the processor should be able to operate at 96MHz.

 

In setting up the system, the processor clock was one of the earliest items initialized during start up. In the system we are using, we have an external 8MHz clock oscillator operating the processor. To generate 96MHz, this is first divided by 2 then multiplied in the PLL by 24. After the core clock is operating, the start up sequence continues by setting up the peripheral clock gates and port initializations. Very late in the start up sequence, the USB is initialized. Part of the USB initialization is setting the clock divider, SIM_CLKDIV2, to produce the 48MHz USB reference clock.

 

Freescale technical support was able to reproduce the problem, and suggested a solution which I have implemented. This appears to have solved the issue. Apparently, setting SIM_CLKDIV2 after the core clock has been set up causes the USB block to ignore the result so that it continues to operate at the core clock rate of 96MHz (doubling the output bit rate at full speed). The solution is to set the USB clock divide before setting the core clock. By setting SIM_CLKDIV2 to the appropriate factor before setting up the PLL, the USB block will use the divided output to correctly clock the bus at 12Mbits/s for full speed.

 

I haven't seen this behavior documented elsewhere and spent quite a bit of time searching, so I thought posting this would help others who might have come across this issue. I am posting the code snippet below which initializes the USB and processor clock in our design for reference. Note that all of this code was generated by processor expert. I have moved the portion of code which sets up the USB clock from the USB_LDD.c file to the code which initializes the processor clock.

 

_____________________________________________________________________________________

 

// set USB clock divider for 96MHz core, moved from function USB_LDD_Init() in USB_LDD.c

  /* Clock setting */

  /* Input clock source:      PLL clock */

  /* Input clock frequency:   96 MHz */

  /* Input clock multiplier:  1 */

  /* Input clock divider:     2 */

  /* Module clock frequency:  48 MHz */

  /* SIM_SOPT2: USBSRC=1 */

  SIM_SOPT2 |= SIM_SOPT2_USBSRC_MASK;  /* Divided PllFll clock */

  /* SIM_CLKDIV2: USBDIV=2,USBFRAC=0 */

  SIM_CLKDIV2 = 0x02;

 

// continuation of processor clock initialization

  /* Enable module clock */

  /* SIM_SCGC4: USBOTG=1 */

  SIM_SCGC4 |= SIM_SCGC4_USBOTG_MASK;                                  

 

  /* System clock initialization */

  /* SIM_SCGC5: PORTE=1,PORTD=1,PORTC=1,PORTB=1,PORTA=1 */

  SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK |

               SIM_SCGC5_PORTD_MASK |

               SIM_SCGC5_PORTC_MASK |

               SIM_SCGC5_PORTB_MASK |

               SIM_SCGC5_PORTA_MASK;   /* Enable clock gate for ports to enable pin routing */

  /* SIM_CLKDIV1: OUTDIV1=0,OUTDIV2=1,OUTDIV3=1,OUTDIV4=3,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0 */

  SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0x00) |

                SIM_CLKDIV1_OUTDIV2(0x01) |

                SIM_CLKDIV1_OUTDIV3(0x01) |

                SIM_CLKDIV1_OUTDIV4(0x03); /* Update system prescalers */

  /* SIM_SOPT2: PLLFLLSEL=1 */

  SIM_SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK; /* Select PLL as a clock source for various peripherals */

  /* SIM_SOPT1: OSC32KSEL=2 */

  SIM_SOPT1 = (uint32_t)((SIM_SOPT1 & (uint32_t)~(uint32_t)(

               SIM_SOPT1_OSC32KSEL(0x01)

              )) | (uint32_t)(

               SIM_SOPT1_OSC32KSEL(0x02)

              ));                      /* System oscillator drives 32 kHz clock for various peripherals */

  /* PORTA_PCR18: ISF=0,MUX=0 */

  PORTA_PCR18 &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));                                  

  /* Switch to FBE Mode */

  /* MCG_C2: LOCRE0=0,??=0,RANGE0=2,HGO0=0,EREFS0=0,LP=0,IRCS=0 */

  MCG_C2 = MCG_C2_RANGE0(0x02);                                  

  /* OSC_CR: ERCLKEN=1,??=0,EREFSTEN=1,??=0,SC2P=0,SC4P=0,SC8P=0,SC16P=0 */

  OSC_CR = (OSC_CR_ERCLKEN_MASK | OSC_CR_EREFSTEN_MASK);                                  

  /* MCG_C7: OSCSEL=0 */

  MCG_C7 &= (uint8_t)~(uint8_t)(MCG_C7_OSCSEL_MASK);                                  

  /* MCG_C1: CLKS=2,FRDIV=3,IREFS=0,IRCLKEN=1,IREFSTEN=1 */

  MCG_C1 = MCG_C1_CLKS(0x02) |

           MCG_C1_FRDIV(0x03) |

           MCG_C1_IRCLKEN_MASK |

           MCG_C1_IREFSTEN_MASK;      

  /* MCG_C4: DMX32=0,DRST_DRS=0 */

  MCG_C4 &= (uint8_t)~(uint8_t)((MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0x03)));                                  

  /* MCG_C5: ??=0,PLLCLKEN0=0,PLLSTEN0=1,PRDIV0=1 */

  MCG_C5 = (MCG_C5_PLLSTEN0_MASK | MCG_C5_PRDIV0(0x01));                                  

  /* MCG_C6: LOLIE0=0,PLLS=0,CME0=0,VDIV0=0 */

  MCG_C6 = MCG_C6_VDIV0(0x00);                                  

  while((MCG_S & MCG_S_IREFST_MASK) != 0x00U) { /* Check that the source of the FLL reference clock is the external reference clock. */

  }

  while((MCG_S & 0x0CU) != 0x08U) {    /* Wait until external reference clock is selected as MCG output */

  }

  /* Switch to PBE Mode */

  /* MCG_C6: LOLIE0=0,PLLS=1,CME0=0,VDIV0=0 */

  MCG_C6 = (MCG_C6_PLLS_MASK | MCG_C6_VDIV0(0x00));                                  

  while((MCG_S & 0x0CU) != 0x08U) {    /* Wait until external reference clock is selected as MCG output */

  }

  while((MCG_S & MCG_S_LOCK0_MASK) == 0x00U) { /* Wait until locked */

  }

  /* Switch to PEE Mode */

  /* MCG_C1: CLKS=0,FRDIV=3,IREFS=0,IRCLKEN=1,IREFSTEN=1 */

  MCG_C1 = MCG_C1_CLKS(0x00) |

           MCG_C1_FRDIV(0x03) |

           MCG_C1_IRCLKEN_MASK |

           MCG_C1_IREFSTEN_MASK;      

  while((MCG_S & 0x0CU) != 0x0CU) {    /* Wait until output of the PLL is selected */

  }

  /*** End of PE initialization code after reset ***/

Outcomes