📄 mcg.c
字号:
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 + -