Problem with PE initialisation of K64 oscillator

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problem with PE initialisation of K64 oscillator

Jump to solution
919 Views
matthewkendall
Contributor V

We have a board using a Kinetis K64 part, and software built on MQX with a BSP cloned from that for the K64 tower, which uses Processor Expert to initialise the CPU.

A difference between our board and the tower is that we have a 12MHz crystal connected to the system oscillator pins, whereas the tower and other Freescale demo boards such as Freedom board generally feed an external clock signal in.

We have made the necessary changes to the Processor Expert component to enable and use the oscillator, but are seeing a problem with the way in which the Processor Expert-generated code initialises this, resulting in a problem starting up.

We have the "Oscillator Operating Mode" setting configured for "High Gain". What we are seeing is that the CPU starts in FEI mode and then the Processor Expert-generated CPU_SetClockConfigGenMode() in CPI_Init.c carefully moves to FBE (running from the oscillator directly, FLL enabled but unused), then to PBE (ditto, PLL enabled but unused), then to PEE (running from the oscillator multiplied by the PLL).

This all looks good, except that the High Gain bit in the MCG_C2 register is not set until the final PBE->PEE transition. At this point the oscillator is already started and the CPU is using it directly. Turning on high gain at this point causes a big disruption in the oscillator that resets the CPU (I guess one of the loss-of-clock bits trips).

It seems to me that if I request high gain, this should be configured from the start, when the oscillator is first enabled on the FEI->FBE transition, not later after we are already running from it.

Specifically, my complaint is that CPU_DEFAULT_FBE_MCG_C2 and CPU_DEFAULT_PBE_MCG_C2 in the Processor Expert-generated CPU_Config.h are not consistent with the chosen "Oscillator Operating Mode". If I choose high gain then this bit should be set in those constants, and hence used in FBE and PBE modes on the way to the final PEE mode.

Changing those constants fixes our startup problems but is clearly not ideal since the fix has to be re-applied every time the file is re-generated.

0 Kudos
1 Solution
387 Views
marek_neuzil
NXP Employee
NXP Employee

Hello Matthew,

We have analyzed the problem and there is a bug. PEx development team will fix the bug in the next release.

In the meantime you can use the following workaround in your application (added source code is marked by red color of the text):

Note: The CPU_Init.c program module contains static code that can be modified by users (it is not impacted by generating of the PEx project). If you have the standalone mode of your project you can do the modification without impact on other project. if you do this modification in a project that is created in linked mode the modification will change source code of other projects (it is shared source code file).

void CPU_SetClockConfigGenMode(LDD_TClockConfiguration ConfigID)
{
  CPU_TClockGenMode NextMode;
  CPU_TClockGenRegs NextModeRegs;
  CPU_TClockGenMode TargetMode = CPU_ClockConfigDescriptors[ConfigID].Mode;
  . . . 
  . . .
  . . .
  NextMode = CPU_GetClockGenMode(); /* Identify the currently active MCG mode */
  do {
    NextMode = ClockGenModeMatrix[NextMode & CPU_MCG_MODE_INDEX_MASK][TargetMode & CPU_MCG_MODE_INDEX_MASK];
    if (NextMode == (TargetMode & CPU_MCG_MODE_INDEX_MASK)) {
      NextModeRegs = CPU_ClockConfigDescriptors[ConfigID].GenRegs;
    } else {
      NextModeRegs = *CPU_ClockGenModeRegs[NextMode & CPU_MCG_MODE_INDEX_MASK];
    }
    switch (NextMode & CPU_MCG_MODE_INDEX_MASK) {

      . . . 

      . . .

      . . .

      case CPU_MCG_MODE_FEE:
      case CPU_MCG_MODE_FBE:
        MCG_C2 = ((NextModeRegs.MCG_C2_value) & (uint8_t)(~(MCG_C2_FCFTRIM_MASK))) | MCG_C2_HGO_MASK | (MCG_C2 & MCG_C2_FCFTRIM_MASK); /* Set C2 (freq. range, ext. and int. reference selection etc.; trim values not changed) */
        OSC_CR = NextModeRegs.OSC_CR_value; /* Set OSC_CR (OSCERCLK enable, oscillator capacitor load) */           
        if (TargetMode & CPU_CLOCK_RTC_OSC_MASK) {
          MCG_C7 = MCG_C7_OSCSEL(1);  /* Select RTC oscillator as MCG clock source */
        } else if (TargetMode & CPU_CLOCK_IRC48M_MASK) {
          MCG_C7 = MCG_C7_OSCSEL(2);  /* Select IRC 48MHz as MCG clock source */
        } else {
          MCG_C7 = 0;                  /* Select system oscillator as MCG clock source */
        }
        MCG_C1 = NextModeRegs.MCG_C1_value; /* Set C1 (clock source selection, FLL ext. reference divider, int. reference enable etc.) */
        if ((TargetMode & CPU_CLOCK_EXTERNAL_CRYSTAL_MASK) != 0) {
          while((MCG_S & MCG_S_OSCINIT0_MASK) == 0x00U) { /* Check that the oscillator is running */
          }
        }
        while((MCG_S & MCG_S_IREFST_MASK) != 0x00U) { /* Check that the source of the FLL reference clock is the external reference clock. */
        }
        MCG_C4 = ((NextModeRegs.MCG_C4_value) & (uint8_t)(~(MCG_C4_FCTRIM_MASK | MCG_C4_SCFTRIM_MASK))) | (MCG_C4 & (MCG_C4_FCTRIM_MASK | MCG_C4_SCFTRIM_MASK)); /* Set C4 (FLL output; trim values not changed) */
        MCG_C5 = NextModeRegs.MCG_C5_value; /* Set C5 (PLL settings, PLL reference divider etc.) */
        if (TargetMode & CPU_CLOCK_PLL_MASK) {
          MCG_C5 |= MCG_C5_PLLCLKEN0_MASK;
        }
        MCG_C6 = NextModeRegs.MCG_C6_value; /* Set C6 (PLL select, VCO divider etc.) */
        break;

      . . . 

      . . .

      . . .

      case CPU_MCG_MODE_PEE:
      case CPU_MCG_MODE_PBE:
        OSC_CR = NextModeRegs.OSC_CR_value; /* Set OSC_CR (OSCERCLK enable, oscillator capacitor load) */
        if (TargetMode & CPU_CLOCK_RTC_OSC_MASK) {
          MCG_C7 = MCG_C7_OSCSEL(1);  /* Select RTC oscillator as MCG clock source */
        } else if (TargetMode & CPU_CLOCK_IRC48M_MASK) {
          MCG_C7 = MCG_C7_OSCSEL(2);  /* Select IRC 48MHz as MCG clock source */
        } else {
          MCG_C7 = 0;                  /* Select system oscillator as MCG clock source */
        }
        MCG_C1 = NextModeRegs.MCG_C1_value; /* Set C1 (clock source selection, FLL ext. reference divider, int. reference enable etc.) */
        MCG_C2 = ((NextModeRegs.MCG_C2_value) & (uint8_t)(~(MCG_C2_FCFTRIM_MASK))) | MCG_C2_HGO_MASK | (MCG_C2 & MCG_C2_FCFTRIM_MASK); /* Set C2 (freq. range, ext. and int. reference selection etc.; trim values not changed) */
        if ((TargetMode & CPU_MCG_MODE_INDEX_MASK) == CPU_MCG_MODE_PEE) {
          MCG_C5 = CPU_ClockConfigDescriptors[ConfigID].GenRegs.MCG_C5_value; /* Set C5 (PLL settings, PLL reference divider etc.) */
          MCG_C6 = CPU_ClockConfigDescriptors[ConfigID].GenRegs.MCG_C6_value; /* Set C6 (PLL select, VCO divider etc.) */
        } else {
          MCG_C5 = NextModeRegs.MCG_C5_value; /* Set C5 (PLL settings, PLL reference divider etc.) */
          MCG_C6 = NextModeRegs.MCG_C6_value; /* Set C6 (PLL select, VCO divider etc.) */
        }
        while((MCG_S & MCG_S_LOCK0_MASK) == 0x00U) { /* Wait until PLL is locked*/
        }
        break;
      default:
        break;           
    }
    . . . 
    . . .
    . . .

View solution in original post

0 Kudos
1 Reply
388 Views
marek_neuzil
NXP Employee
NXP Employee

Hello Matthew,

We have analyzed the problem and there is a bug. PEx development team will fix the bug in the next release.

In the meantime you can use the following workaround in your application (added source code is marked by red color of the text):

Note: The CPU_Init.c program module contains static code that can be modified by users (it is not impacted by generating of the PEx project). If you have the standalone mode of your project you can do the modification without impact on other project. if you do this modification in a project that is created in linked mode the modification will change source code of other projects (it is shared source code file).

void CPU_SetClockConfigGenMode(LDD_TClockConfiguration ConfigID)
{
  CPU_TClockGenMode NextMode;
  CPU_TClockGenRegs NextModeRegs;
  CPU_TClockGenMode TargetMode = CPU_ClockConfigDescriptors[ConfigID].Mode;
  . . . 
  . . .
  . . .
  NextMode = CPU_GetClockGenMode(); /* Identify the currently active MCG mode */
  do {
    NextMode = ClockGenModeMatrix[NextMode & CPU_MCG_MODE_INDEX_MASK][TargetMode & CPU_MCG_MODE_INDEX_MASK];
    if (NextMode == (TargetMode & CPU_MCG_MODE_INDEX_MASK)) {
      NextModeRegs = CPU_ClockConfigDescriptors[ConfigID].GenRegs;
    } else {
      NextModeRegs = *CPU_ClockGenModeRegs[NextMode & CPU_MCG_MODE_INDEX_MASK];
    }
    switch (NextMode & CPU_MCG_MODE_INDEX_MASK) {

      . . . 

      . . .

      . . .

      case CPU_MCG_MODE_FEE:
      case CPU_MCG_MODE_FBE:
        MCG_C2 = ((NextModeRegs.MCG_C2_value) & (uint8_t)(~(MCG_C2_FCFTRIM_MASK))) | MCG_C2_HGO_MASK | (MCG_C2 & MCG_C2_FCFTRIM_MASK); /* Set C2 (freq. range, ext. and int. reference selection etc.; trim values not changed) */
        OSC_CR = NextModeRegs.OSC_CR_value; /* Set OSC_CR (OSCERCLK enable, oscillator capacitor load) */           
        if (TargetMode & CPU_CLOCK_RTC_OSC_MASK) {
          MCG_C7 = MCG_C7_OSCSEL(1);  /* Select RTC oscillator as MCG clock source */
        } else if (TargetMode & CPU_CLOCK_IRC48M_MASK) {
          MCG_C7 = MCG_C7_OSCSEL(2);  /* Select IRC 48MHz as MCG clock source */
        } else {
          MCG_C7 = 0;                  /* Select system oscillator as MCG clock source */
        }
        MCG_C1 = NextModeRegs.MCG_C1_value; /* Set C1 (clock source selection, FLL ext. reference divider, int. reference enable etc.) */
        if ((TargetMode & CPU_CLOCK_EXTERNAL_CRYSTAL_MASK) != 0) {
          while((MCG_S & MCG_S_OSCINIT0_MASK) == 0x00U) { /* Check that the oscillator is running */
          }
        }
        while((MCG_S & MCG_S_IREFST_MASK) != 0x00U) { /* Check that the source of the FLL reference clock is the external reference clock. */
        }
        MCG_C4 = ((NextModeRegs.MCG_C4_value) & (uint8_t)(~(MCG_C4_FCTRIM_MASK | MCG_C4_SCFTRIM_MASK))) | (MCG_C4 & (MCG_C4_FCTRIM_MASK | MCG_C4_SCFTRIM_MASK)); /* Set C4 (FLL output; trim values not changed) */
        MCG_C5 = NextModeRegs.MCG_C5_value; /* Set C5 (PLL settings, PLL reference divider etc.) */
        if (TargetMode & CPU_CLOCK_PLL_MASK) {
          MCG_C5 |= MCG_C5_PLLCLKEN0_MASK;
        }
        MCG_C6 = NextModeRegs.MCG_C6_value; /* Set C6 (PLL select, VCO divider etc.) */
        break;

      . . . 

      . . .

      . . .

      case CPU_MCG_MODE_PEE:
      case CPU_MCG_MODE_PBE:
        OSC_CR = NextModeRegs.OSC_CR_value; /* Set OSC_CR (OSCERCLK enable, oscillator capacitor load) */
        if (TargetMode & CPU_CLOCK_RTC_OSC_MASK) {
          MCG_C7 = MCG_C7_OSCSEL(1);  /* Select RTC oscillator as MCG clock source */
        } else if (TargetMode & CPU_CLOCK_IRC48M_MASK) {
          MCG_C7 = MCG_C7_OSCSEL(2);  /* Select IRC 48MHz as MCG clock source */
        } else {
          MCG_C7 = 0;                  /* Select system oscillator as MCG clock source */
        }
        MCG_C1 = NextModeRegs.MCG_C1_value; /* Set C1 (clock source selection, FLL ext. reference divider, int. reference enable etc.) */
        MCG_C2 = ((NextModeRegs.MCG_C2_value) & (uint8_t)(~(MCG_C2_FCFTRIM_MASK))) | MCG_C2_HGO_MASK | (MCG_C2 & MCG_C2_FCFTRIM_MASK); /* Set C2 (freq. range, ext. and int. reference selection etc.; trim values not changed) */
        if ((TargetMode & CPU_MCG_MODE_INDEX_MASK) == CPU_MCG_MODE_PEE) {
          MCG_C5 = CPU_ClockConfigDescriptors[ConfigID].GenRegs.MCG_C5_value; /* Set C5 (PLL settings, PLL reference divider etc.) */
          MCG_C6 = CPU_ClockConfigDescriptors[ConfigID].GenRegs.MCG_C6_value; /* Set C6 (PLL select, VCO divider etc.) */
        } else {
          MCG_C5 = NextModeRegs.MCG_C5_value; /* Set C5 (PLL settings, PLL reference divider etc.) */
          MCG_C6 = NextModeRegs.MCG_C6_value; /* Set C6 (PLL select, VCO divider etc.) */
        }
        while((MCG_S & MCG_S_LOCK0_MASK) == 0x00U) { /* Wait until PLL is locked*/
        }
        break;
      default:
        break;           
    }
    . . . 
    . . .
    . . .

0 Kudos