⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mcg.c

📁 Kinetis_K60开源底层驱动开发包(20120328)
💻 C
📖 第 1 页 / 共 2 页
字号:
int fll_freq(int fll_ref)
{
  int fll_freq_khz;
  
  if (MCG_C4 & MCG_C4_DMX32_MASK) // if DMX32 set
  {
    switch ((MCG_C4 & MCG_C4_DRST_DRS_MASK) >> MCG_C4_DRST_DRS_SHIFT) // determine multiplier based on DRS
    {
    case 0:
      fll_freq_khz = ((fll_ref * 732) / 1000);
      break;
    case 1:
      fll_freq_khz = ((fll_ref * 1464) / 1000);
      break;
    case 2:
      fll_freq_khz = ((fll_ref * 2197) / 1000);
      break;
    case 3:
      fll_freq_khz = ((fll_ref * 2929) / 1000);
      break;
    }
  }
  else // if DMX32 = 0
  {
    switch ((MCG_C4 & MCG_C4_DRST_DRS_MASK) >> MCG_C4_DRST_DRS_SHIFT) // determine multiplier based on DRS
    {
    case 0:
      fll_freq_khz = ((fll_ref * 640) / 1000);
      break;
    case 1:
      fll_freq_khz = ((fll_ref * 1280) / 1000);
      break;
    case 2:
      fll_freq_khz = ((fll_ref * 1920) / 1000);
      break;
    case 3:
      fll_freq_khz = ((fll_ref * 2560) / 1000);
      break;
    }
  }    
  return fll_freq_khz;
} // fll_freq

int fei_fbe(unsigned char crystal_val, unsigned char hgo_val)
{
  unsigned char frdiv_val;
  int i;
  
  if ((crystal_val > 15) && (crystal_val != 24)) {return 1;} // return 1 if one of the available crystal options is not available
  
  if (hgo_val > 0)
  {
    hgo_val = 1; // force hgo_val to 1 if > 0
  }

#if (defined(K60_CLK))
     MCG_C2 = MCG_C2_RANGE(1); // select external clock and set range to provide correct FRDIV range
#else
// Enable external oscillator, select range based on crystal frequency
  if (crystal_val < 4)
  {
    MCG_C2 = MCG_C2_RANGE(1) | (MCG_C2_HGO_MASK << MCG_C2_HGO_SHIFT) | MCG_C2_EREFS_MASK;
  }
  else
  {
    MCG_C2 = MCG_C2_RANGE(2) | (MCG_C2_HGO_MASK << MCG_C2_HGO_SHIFT) | MCG_C2_EREFS_MASK;
  }
#endif

  switch (crystal_val) // determine FRDIV based on reference clock frequency
    {
    case 0:
      frdiv_val = 1;
      break;
    case 1:
      frdiv_val = 2;
      break;
    case 2:
    case 3:
    case 4:
      frdiv_val = 3;
      break;
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
      frdiv_val = 4;
      break;
    default:
      frdiv_val = 5;        
      break;
    }
// Select external oscilator and Reference Divider and clear IREFS to start ext osc
// CLKS=2, FRDIV=frdiv_val, IREFS=0, IRCLKEN=0, IREFSTEN=0
  MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(frdiv_val);

  /* if we aren't using an osc input we don't need to wait for the osc to init */
#if (!defined(K60_CLK))
//  while (!(MCG_S & MCG_S_OSCINIT_MASK)){};  // wait for oscillator to initialize
  for (i = 0 ; i < 10000 ; i++)
  {
    if (MCG_S & MCG_S_OSCINIT_MASK) break; // jump out early if OSCINIT sets before loop finishes
  }
  if (!(MCG_S & MCG_S_OSCINIT_MASK)) return 2; // check bit is really set and return with error if not set
#endif

//  while (MCG_S & MCG_S_IREFST_MASK){}; // wait for Reference clock Status bit to clear
  for (i = 0 ; i < 2000 ; i++)
  {
    if (!(MCG_S & MCG_S_IREFST_MASK)) break; // jump out early if IREFST clears before loop finishes
  }
  if (MCG_S & MCG_S_IREFST_MASK) return 3; // check bit is really clear and return with error if not set
  
//  while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2){}; // Wait for clock status bits to show clock source is ext ref clk
  for (i = 0 ; i < 2000 ; i++)
  {
    if (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) == 0x2) break; // jump out early if CLKST shows EXT CLK slected before loop finishes
  }
  if (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2) return 4; // check EXT CLK is really selected and return with error if not
  
  return ((crystal_val + 1) * 2 * 1000); // MCGOUT frequency in kHz = crystal value * 2 * 1000

// Now in FBE
}

void fbe_pbe(unsigned char prdiv_val, unsigned char vdiv_val)
{  
  MCG_C5 = MCG_C5_PRDIV(prdiv_val);    //set PLL ref divider

// the PLLS bit is set to enable the PLL, MCGOUT still sourced from ext ref clk  
  MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(24);
  
  while (!(MCG_S & MCG_S_PLLST_MASK)){}; // wait for PLL status bit to set

  while (!(MCG_S & MCG_S_LOCK_MASK)){}; // Wait for LOCK bit to set
// now in PBE 
// PBE frequency = FBE frequency, no need to change frequency
}

int pbe_pee(unsigned char crystal_val)
{
  unsigned char prdiv, vdiv;  
  MCG_C1 &= ~MCG_C1_CLKS_MASK; // switch CLKS mux to select PLL as MCG_OUT
  // Wait for clock status bits to update 
  while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3){} 

  prdiv = ((MCG_C5 & MCG_C5_PRDIV_MASK) + 1);
  vdiv = ((MCG_C6 & MCG_C6_VDIV_MASK) + 24);
  
  return (((((crystal_val + 1) * 2)/prdiv) * vdiv) * 1000); //calculate PLL output frequency
}

int pee_pbe(unsigned char crystal_val)
{  
  MCG_C1 |= MCG_C1_CLKS(2); // switch CLKS mux to select external reference clock as MCG_OUT
  // Wait for clock status bits to update 
  while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2){}; 

return ((crystal_val + 1) * 2000); // MCGOUT frequency in kHz

} // pee_pbe, freq = REF_CLK

void pbe_fbe(void)
{
  MCG_C6 &= ~MCG_C6_PLLS_MASK; // clear PLLs to disable PLL, still clocked from ext ref clk
  
  while (MCG_S & MCG_S_PLLST_MASK){}; // wait for PLLS status bit to set
// FBE frequency = PBE frequency, no need to change frequency  
} 

void fbe_fbi_fast(void)
{
  unsigned char temp_reg;
  
  MCG_C2 |= MCG_C2_IRCS_MASK; // select fast IRC by setting IRCS
  
  temp_reg = MCG_C1;
  temp_reg &= ~MCG_C1_CLKS_MASK;
  temp_reg |= MCG_C1_CLKS(1); // select IRC as MCGOUT
  MCG_C1 = temp_reg; // update MCG_C1
  
  while (!(MCG_S & MCG_S_IRCST_MASK)){}; // wait until internal reference switches to fast clock.
  
  while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x1){}; // Wait for clock status bits to update
// fast IRC clock speed is determined by FCTRIM value and must be trimmed to a known frequency
} //fbe_fbi_fast

void fbe_fbi_slow(void)
{
  unsigned char temp_reg;
  
  MCG_C2 &= ~MCG_C2_IRCS_MASK; // select slow IRC by clearing IRCS
  
  temp_reg = MCG_C1;
  temp_reg &= ~MCG_C1_CLKS_MASK;
  temp_reg |= MCG_C1_CLKS(1); // select IRC as MCGOUT
  MCG_C1 = temp_reg; // update MCG_C1
  
  while (!(MCG_S & MCG_S_IRCST_MASK)){}; // wait until internal reference switches to fast clock.
  
  while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x1){}; // Wait for clock status bits to update
// fast IRC clock speed is determined by FCTRIM value and must be trimmed to a known frequency
} //fbe_fbi_slow

void fbi_blpi(void)
{ 
  MCG_C2 |= MCG_C2_LP_MASK; //set LP bit to disable the FLL 
// no change in MCGOUT frequency  
} 


int atc (unsigned char irc, int irc_freq)
{
    uint32 temp_reg = 0;
    unsigned char temp_reg8 = 0;
    uint32 orig_SIM_CLKDIV1;
    unsigned short atcv;
    unsigned char clks_val;
    unsigned int i;
             
    printf("\n-------------------------------------------\n");
    printf("  MCG AutoTrim Utility\n");
    printf("-------------------------------------------\n");
    printf("\n");
    {
        if (irc > 0) // force irc to 1 if greater than 0
        {
          irc = 1;
        }
        
        clks_val = ((MCG_C1 & MCG_C1_CLKS_MASK) >> 6);
        
        if (((clks_val == 1) || (clks_val ==3)))
        {
          printf("\nAuto trim error - cannot use the internal clock source.\r\n\n");
          return 1; //error using IRC as system clock
        }
              
        if ((clks_val == 0) && (!(MCG_C6 & MCG_C6_PLLS_MASK)) && (MCG_C1 & MCG_C1_IREFS_MASK))
        {
          printf("\nAuto trim error - cannot use the FLL with internal clock source.\r\n\n");
          return 2; // error using FLL with IRC
        }
        if (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 3)
        {
          printf("\nWARNING - PLL is not the internal clock source. Auto trim value will not be correct\r\n\n");
        }
                
        if(!irc) //determine if slow or fast IRC to be trimmed
        {
          if (irc_freq < 31250) // check frequency is above min spec.
          {
            printf("\nAuto trim error - target frequency is below 31250 Hz.\r\n\n");
            return 3;
          }
          if (irc_freq > 39062) // check frequency is below max spec.
          {
            printf("\nAuto trim error - target frequency is above 39062 Hz.\r\n\n");
            return 4;
          }         
        }
        else
        {
          if (irc_freq < 3000000) // check frequency is above min spec.
          {
            printf("\nAuto trim error - target frequency is below 3 MHz.\r\n\n");
            return 5;
          }
          if (irc_freq > 5000000) // check frequency is below max spec.
          {
            printf("\nAuto trim error - target frequency is above 5 MHz.\r\n\n");
            return 6;
          }            
        } // if
        for (i=0;i<0xffff;i++);
        orig_SIM_CLKDIV1 = SIM_CLKDIV1;        // backup current divider value
        temp_reg = SIM_CLKDIV1;                // bus clock needs to be between 8 and 16 MHz
        temp_reg &= ~SIM_CLKDIV1_OUTDIV2_MASK; // clear bus divider field
        temp_reg |= SIM_CLKDIV1_OUTDIV2(5);    //divide 96MHz PLL by 6 = 16MHz bus clock
        SIM_CLKDIV1 = temp_reg; 
// Set up autocal registers, must use floating point calculation
        if (irc)
          atcv = (unsigned short)(128.0f * (21.0f * (16000000.0f / (float)irc_freq))); 
        else
          atcv = (unsigned short)(21.0f * (16000000.0f / (float)irc_freq));
        
        MCG_ATCVL = (atcv & 0xFF); //Set ATCVL to lower 8 bits of count value
        MCG_ATCVH = ((atcv & 0xFF00) >> 8); // Set ATCVH to upper 8 bits of count value

// Enable autocal
        MCG_ATC = 0x0; // clear auto trim control register
        temp_reg8 |= (MCG_ATC_ATME_MASK | (irc << MCG_ATC_ATMS_SHIFT)); //Select IRC to trim and enable trim machine
        MCG_ATC = temp_reg8;
        
        while (MCG_ATC & MCG_ATC_ATME_MASK) {}; //poll for ATME bit to clear
        
        SIM_CLKDIV1 = orig_SIM_CLKDIV1; //restore the divider value
        
        if (MCG_ATC & MCG_ATC_ATMF_MASK) // check if error flag set
        {
          printf("Autotrim error.\r\n\n");
          printf("\n");
          printf("MCG_C1   = %#02X \r\n", (MCG_C1));
          printf("MCG_C2   = %#02X \r\n", (MCG_C2));
          printf("MCG_C3   = %#02X \r\n", (MCG_C3));
          printf("MCG_C4   = %#02X \r\n", (MCG_C4)) ;
          printf("MCG_C5   = %#02X \r\n", (MCG_C5));
          printf("MCG_C6   = %#02X \r\n\n", (MCG_C6));
          printf("MCG_S    = %#02X \r\n\n", (MCG_S)) ;
          printf("MCG_ATC   = %#02X \r\n",   (MCG_ATC)) ;
          printf("MCG_ATCVL = %#02X \r\n",   (MCG_ATCVL)) ;
          printf("MCG_ATVCH = %#02X \r\n",   (MCG_ATCVH));
          MCG_ATC |= MCG_ATC_ATMF_MASK; // clear fail flag
          return 7;
        } 
        else 
        {      
          printf("Autotrim Passed.\r\n\n");
          printf("MCG_C3   = %#02X \r\n", (MCG_C3));
          printf("MCG_C4   = %#02X \r\n", (MCG_C4));
          // Check trim value is not at either extreme of the range
          if (!irc)
          {
            if ((MCG_C3 == 0xFF) || (MCG_C3 == 0))
            {
              printf("\nAutotrim result is not valid.\r\n\n");
              return 8;
            }
          }
          else
          {
            if ((((MCG_C4 & MCG_C4_FCTRIM_MASK) >> MCG_C4_FCTRIM_SHIFT) == 0xF) ||
              (((MCG_C4 & MCG_C4_FCTRIM_MASK) >> MCG_C4_FCTRIM_SHIFT) == 0))
            {
              printf("\nAutotrim result is not valid.\r\n\n");
              return 8;
            }
          }
        }
          
    }// end else
    return irc;
}// end atc

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -