I have been trying to enable the HIRC MCG mode on a MKL27Z microcontroller. As far as I know, there are at least two ways to do this: to write the code using the device registers or to use KDSK device specific drivers.
For the first approach my could would look like this:
#include "fsl_device_registers.h"
void main(void)
{
MCG_MC |= MCG_MC_HIRCEN_MASK; //enable the HIRC
MCG_MC |= MCG_MC_HIRCLPEN_MASK;
MCG_C1 |= MCG_C1_CLKS(0b00); //use the HIRC oscillator as the system clock
for (int i = 0 ; i < 2000 ; i++)
{if (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) == 0b00) break; // jump out early if CLKST shows HIRC CLK selected before loop finishes
}
}
The problem with this example is that it does not enter the HIRC mode. I have tried the same approach on on enabling other modes and it works. Am I missing something?
The second approach is to use one of the functions provided in the low level HAL driver, fsl_mcglite_hal.h:
static void CLOCK_HAL_SetHircCmd (MCG_Type *base, bool enable)
Although the latter will mean less lines of code, I cannot find any reference to what possible values I could give to base ( I could not find any reference to MCG_Type type).
Any thoughts??
Cheers
Solved! Go to Solution.
"MCG_C1 |=" the '|' is the problem, can't have more than one clock selected in C1 at a time.
I use the code below. Hopefully the editor here does not hose it like it typically does for me:
void clock_usb( void )
{
/* The SOPT1 register is only reset on POR or LVD: */
SIM_SOPT1 = (
// SIM_SOPT1_USBREGEN_MASK | /* USB voltage regulator is enabled [Do we need to do this?] */
SIM_SOPT1_OSC32KSEL( 3U ) /* LPO 1kHz oscillator drives 32 kHz clock for RTC and LPTMR via ERCLK32K */
);
SIM_SOPT2 = (
SIM_SOPT2_TPMSRC( 1U ) | /* 1:IRC48M/MCGPCLK, 2:OSCERCLK, 3:IRC8M/MCGIRCLK: Clock feeds the TPM clock */
SIM_SOPT2_LPUART0SRC( 1U ) | /* 1:IRC48M/MCGPCLK, 2:OSCERCLK, 3:IRC8M/MCGIRCLK: Clock feeds LPUART0 baud generator */
SIM_SOPT2_LPUART1SRC( 1U ) | /* 1:IRC48M/MCGPCLK, 2:OSCERCLK, 3:IRC8M/MCGIRCLK: Clock feeds LPUART0 baud generator */
SIM_SOPT2_CLKOUTSEL( CLKOUT ) | /* 0:None, 2:Bus, 3:LPO-1kHz, 4:IRC8M/LIRC_CLK, 6:OSCERCLK, 7:IRC48M */
SIM_SOPT2_USBSRC_MASK /* 0:External bypass clock (USB_CLKIN), 1:IRC48M */
);
SIM_SCGC4 |= SIM_SCGC4_USBFS_MASK; /* Enable USB module clock */
/*
* When power on or out of reset, Low-power Internal RC (LIRC) at 8
* MHz is selected as the main clock source. To select other clock
* sources, the mode must be set to HIRC before changing to an other
* mode.
*
* Note that the bootloader may have changed clock configuration
* substantially from the data sheet reset values.
*/
MCG_MC = MCG_MC_HIRCEN_MASK; /* High-frequency IRC Enabled. Enables the HIRC, even when MCG_Lite is not working at HIRC mode */
MCG_C1 = (
MCG_C1_CLKS( 0U ) | /* 0:HIRC, 1:LIRC2M or LIRC8M mode, 2:External Clock */
MCG_C1_IRCLKEN_MASK /* Internal Reference Clock LIRC enabled */
);
/*
* Clock Mode Status. This field does not update immediately after
* a write to MCG_C1[CLKS] due to domain synchronization.
*
* Check MCG_S[CLKST] to confirm HIRC clock source is selected
*/
while( (0U << MCG_S_CLKST_SHIFT) != MCG_S_CLKST( 0U ) )
{
nop();
}
#if( defined( USB_VID ) && defined( MCU_MKL27Z4 ) ) /* Only the 43/27 family has USB sync the 25 family does not */
USB0_USBTRC0 = 0x40U; /* Attach Coldfire V1 USB peripheral to the bus */
USB0_CLK_RECOVER_IRC_EN = (USB_CLK_RECOVER_IRC_EN_IRC_EN_MASK|USB_CLK_RECOVER_IRC_EN_REG_EN_MASK); /* Note that bit-0 is reserved and must be set to one, the data sheet does not explain why */
USB0_CLK_RECOVER_CTRL = (USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK|USB_CLK_RECOVER_CTRL_RESTART_IFRTRIM_EN_MASK);
USB0_CLK_RECOVER_INT_STATUS = USB_CLK_RECOVER_INT_STATUS_OVF_ERROR_MASK; /* Combined USB Clock Recovery interrupt status */
USB0_CLK_RECOVER_INT_EN = 0U; /* Is enabled out of reset by default */
#endif
/*
* The MCG_Lite module does not support switch between LIRC 2 MHz
* and 8 MHz directly, because 2 MHz and 8 MHz clock generators
* share circuits and logics. To switch between each other, the
* module must be in HIRC or EXT clock mode.
*
* To enter LIRC8M mode from HIRC or EXT mode:
* 1. 1. Write 0b to MCG_C2[IRCS] to select LIRC 2M. Write 1b to MCG_C2[IRCS] to select LIRC 8M.
* 2. Write 1b to MCG_C1[IRCLKEN] to enable LIRC clock (optional).
* 3. Write 01b to MCG_C1[CLKS] to select LIRC clock source.
* 4. Check MCG_S[CLKST] to confirm LIRC clock source is selected.
*/
MCG_C2 = (
MCG_C2_IRCS_MASK /* Low-frequency Internal Reference Clock Select LIRC 8 MHz */
);
MCG_MC = (MCG_MC_HIRCEN_MASK|MCG_MC_LIRC_DIV2( 1U )); /* High-frequency IRC Enabled. LIRC/2 = 4MHz to match Bus. Use MCGIRCLK for peripherals */
}
Hi Radu Nasui,
You can refer to the KSDK1.3.0, KL27Z644 sample code.
After you install the KSDK1.3.0, please refer to the SystemInit function in system_MKL27Z644.c, and define CLOCK_SETUP=1 in system_MKL27Z644.h.
You can find the system_MKL27Z644.h and system_MKL27Z644.c in default folder: C:\Freescale\KSDK_1.3.0\platform\devices\MKL27Z644\startup
When you configure CLOCK_SETUP=1, the systeminit is using MCG_MODE_HIRC.
#elif (CLOCK_SETUP == 1)
#define DEFAULT_SYSTEM_CLOCK 48000000u /* Default System clock value */
#define CPU_INT_SLOW_CLK_HZ 8000000u /* Value of the slow internal oscillator clock frequency in Hz */
#define MCG_MODE MCG_MODE_HIRC /* Clock generator mode */
/* MCG_C1: CLKS=0,IRCLKEN=0,IREFSTEN=0 */
#define MCG_C1_VALUE 0x00u /* MCG_C1 */
/* MCG_C2: RANGE0=0,HGO0=0,EREFS0=0,IRCS=1 */
#define MCG_C2_VALUE 0x01u /* MCG_C2 */
/* MCG_SC: FCRDIV=0 */
#define MCG_SC_VALUE 0x00u /* MCG_SC */
/* MCG_MC: HIRCEN=1 LIRC_DIV2=0 */
#define MCG_MC_VALUE 0x80u /* MCG_MC */
/* OSC0_CR: ERCLKEN=0,EREFSTEN=0,SC2P=0,SC4P=0,SC8P=0,SC16P=0 */
#define OSC0_CR_VALUE 0x00u /* OSC0_CR */
/* SMC_PMCTRL: RUNM=0,STOPA=0,STOPM=0 */
#define SMC_PMCTRL_VALUE 0x00u /* SMC_PMCTRL */
/* SIM_CLKDIV1: OUTDIV1=0,OUTDIV4=1 */
#define SYSTEM_SIM_CLKDIV1_VALUE 0x10000u /* SIM_CLKDIV1 */
/* SIM_SOPT1: OSC32KSEL=0,OSC32KOUT=0 */
#define SYSTEM_SIM_SOPT1_VALUE 0x00000000u /* SIM_SOPT1 */
/* SIM_SOPT2: LPUART1SRC=0,LPUART0SRC=0,TPMSRC=3,FLEXIOSRC=0,USBSRC=0,CLKOUTSEL=0,RTCCLKOUTSEL=0 */
#define SYSTEM_SIM_SOPT2_VALUE 0x03000000U /* SIM_SOPT2 */
Wish it helps you!
If you still have question, please let me know!
Have a great day,
Jingjing
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Thanks, works this way too!
Do you know though how to find the set of values MCG_Type can take?
Cheers
Hi Radu Nasui,
MCG_Type is defined like this:
typedef struct {
__IO uint8_t C1; /**< MCG Control Register 1, offset: 0x0 */
__IO uint8_t C2; /**< MCG Control Register 2, offset: 0x1 */
uint8_t RESERVED_0[4];
__I uint8_t S; /**< MCG Status Register, offset: 0x6 */
uint8_t RESERVED_1[1];
__IO uint8_t SC; /**< MCG Status and Control Register, offset: 0x8 */
uint8_t RESERVED_2[15];
__IO uint8_t MC; /**< MCG Miscellaneous Control Register, offset: 0x18 */
} MCG_Type, *MCG_MemMapPtr;
Actually, the value of MCG_Type is just the data defined in the header file system_MKL27Z644.h:
#define MCG_C1_VALUE 0x00u /* MCG_C1 */
/* MCG_C2: RANGE0=0,HGO0=0,EREFS0=0,IRCS=1 */
#define MCG_C2_VALUE 0x01u /* MCG_C2 */
/* MCG_SC: FCRDIV=0 */
#define MCG_SC_VALUE 0x00u /* MCG_SC */
/* MCG_MC: HIRCEN=1 LIRC_DIV2=0 */
#define MCG_MC_VALUE 0x80u /* MCG_MC */
Because in the system_MKL27Z644.c, you will get the following code :
MCG->SC = MCG_SC_VALUE; | /* Set SC (internal reference clock divider) */ |
MCG->MC = MCG_MC_VALUE; | /* Set MC (high-frequency IRC enable, second LIRC divider) */ |
MCG->C1 = MCG_C1_VALUE; | /* Set C1 (clock source selection, int. reference enable etc.) */ |
MCG->C2 = MCG_C2_VALUE; | /* Set C2 (ext. and int. reference clock selection) */ |
OSC0->CR = OSC0_CR_VALUE; | /* Set OSC0_CR (OSCERCLK enable, oscillator capacitor load) */ |
Wish it helps you!
If you still have question, please let me know!
Have a great day,
Jingjing
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Thanks for the answer!
I still don't know though how should I call the following function:
uint32_t CLOCK_HAL_GetOutClk ( MCG_Type *base )
I was trying to do the following:
clock = CLOCK_HAL_GetOutClk(MCG_MemMapPtr);
But I am getting an error: expected expression before 'MCG_MemMapPtr'
How should I go about solving this one?
Thanks
Found it.
For reference, all these information can be found in the device header file, in my case MKL27Z644.h
clock = CLOCK_HAL_GetOutClk(MCG);
Cheers
Yes, actually, you can refer to the fsl_clock_MKL27Z644.c file which you can find from :C:\Freescale\KSDK_1.3.0\platform\system\src\clock\MKL27Z644
clock_manager_error_code_t CLOCK_SYS_GetFreq(clock_names_t clockName,
uint32_t *frequency)
{
clock_manager_error_code_t returnCode = kClockManagerSuccess;
switch (clockName)
{
case kCoreClock:
case kSystemClock:
*frequency = CLOCK_SYS_GetCoreClockFreq();
break;
case kPlatformClock:
*frequency = CLOCK_SYS_GetSystemClockFreq();
break;
case kBusClock:
*frequency = CLOCK_SYS_GetBusClockFreq();
break;
case kFlashClock:
*frequency = CLOCK_SYS_GetFlashClockFreq();
break;
case kOsc32kClock:
*frequency = CLOCK_SYS_GetExternalRefClock32kFreq();
break;
case kOsc0ErClock:
*frequency = CLOCK_SYS_GetOsc0ExternalRefClockFreq();
break;
case kIrc48mClock:
*frequency = kMcgliteConst48M;
break;
case kRtcoutClock:
*frequency = CLOCK_SYS_GetRtcOutFreq();
break;
case kMcgOutClock:
*frequency = CLOCK_HAL_GetOutClk(MCG);
break;
case kMcgIrClock:
*frequency = CLOCK_HAL_GetInternalRefClk(MCG);
break;
case kLpoClock:
*frequency = CLOCK_SYS_GetLpoClockFreq();
break;
case kSystickClock:
*frequency = CLOCK_SYS_GetSystickFreq();
break;
default:
*frequency = 0U;
returnCode = kClockManagerNoSuchClockName;
break;
}
return returnCode;
}
this function gives you an example!
Wish it helps you!
If you still have question, please let me know!
Have a great day,
Jingjing
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
"MCG_C1 |=" the '|' is the problem, can't have more than one clock selected in C1 at a time.
I use the code below. Hopefully the editor here does not hose it like it typically does for me:
void clock_usb( void )
{
/* The SOPT1 register is only reset on POR or LVD: */
SIM_SOPT1 = (
// SIM_SOPT1_USBREGEN_MASK | /* USB voltage regulator is enabled [Do we need to do this?] */
SIM_SOPT1_OSC32KSEL( 3U ) /* LPO 1kHz oscillator drives 32 kHz clock for RTC and LPTMR via ERCLK32K */
);
SIM_SOPT2 = (
SIM_SOPT2_TPMSRC( 1U ) | /* 1:IRC48M/MCGPCLK, 2:OSCERCLK, 3:IRC8M/MCGIRCLK: Clock feeds the TPM clock */
SIM_SOPT2_LPUART0SRC( 1U ) | /* 1:IRC48M/MCGPCLK, 2:OSCERCLK, 3:IRC8M/MCGIRCLK: Clock feeds LPUART0 baud generator */
SIM_SOPT2_LPUART1SRC( 1U ) | /* 1:IRC48M/MCGPCLK, 2:OSCERCLK, 3:IRC8M/MCGIRCLK: Clock feeds LPUART0 baud generator */
SIM_SOPT2_CLKOUTSEL( CLKOUT ) | /* 0:None, 2:Bus, 3:LPO-1kHz, 4:IRC8M/LIRC_CLK, 6:OSCERCLK, 7:IRC48M */
SIM_SOPT2_USBSRC_MASK /* 0:External bypass clock (USB_CLKIN), 1:IRC48M */
);
SIM_SCGC4 |= SIM_SCGC4_USBFS_MASK; /* Enable USB module clock */
/*
* When power on or out of reset, Low-power Internal RC (LIRC) at 8
* MHz is selected as the main clock source. To select other clock
* sources, the mode must be set to HIRC before changing to an other
* mode.
*
* Note that the bootloader may have changed clock configuration
* substantially from the data sheet reset values.
*/
MCG_MC = MCG_MC_HIRCEN_MASK; /* High-frequency IRC Enabled. Enables the HIRC, even when MCG_Lite is not working at HIRC mode */
MCG_C1 = (
MCG_C1_CLKS( 0U ) | /* 0:HIRC, 1:LIRC2M or LIRC8M mode, 2:External Clock */
MCG_C1_IRCLKEN_MASK /* Internal Reference Clock LIRC enabled */
);
/*
* Clock Mode Status. This field does not update immediately after
* a write to MCG_C1[CLKS] due to domain synchronization.
*
* Check MCG_S[CLKST] to confirm HIRC clock source is selected
*/
while( (0U << MCG_S_CLKST_SHIFT) != MCG_S_CLKST( 0U ) )
{
nop();
}
#if( defined( USB_VID ) && defined( MCU_MKL27Z4 ) ) /* Only the 43/27 family has USB sync the 25 family does not */
USB0_USBTRC0 = 0x40U; /* Attach Coldfire V1 USB peripheral to the bus */
USB0_CLK_RECOVER_IRC_EN = (USB_CLK_RECOVER_IRC_EN_IRC_EN_MASK|USB_CLK_RECOVER_IRC_EN_REG_EN_MASK); /* Note that bit-0 is reserved and must be set to one, the data sheet does not explain why */
USB0_CLK_RECOVER_CTRL = (USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK|USB_CLK_RECOVER_CTRL_RESTART_IFRTRIM_EN_MASK);
USB0_CLK_RECOVER_INT_STATUS = USB_CLK_RECOVER_INT_STATUS_OVF_ERROR_MASK; /* Combined USB Clock Recovery interrupt status */
USB0_CLK_RECOVER_INT_EN = 0U; /* Is enabled out of reset by default */
#endif
/*
* The MCG_Lite module does not support switch between LIRC 2 MHz
* and 8 MHz directly, because 2 MHz and 8 MHz clock generators
* share circuits and logics. To switch between each other, the
* module must be in HIRC or EXT clock mode.
*
* To enter LIRC8M mode from HIRC or EXT mode:
* 1. 1. Write 0b to MCG_C2[IRCS] to select LIRC 2M. Write 1b to MCG_C2[IRCS] to select LIRC 8M.
* 2. Write 1b to MCG_C1[IRCLKEN] to enable LIRC clock (optional).
* 3. Write 01b to MCG_C1[CLKS] to select LIRC clock source.
* 4. Check MCG_S[CLKST] to confirm LIRC clock source is selected.
*/
MCG_C2 = (
MCG_C2_IRCS_MASK /* Low-frequency Internal Reference Clock Select LIRC 8 MHz */
);
MCG_MC = (MCG_MC_HIRCEN_MASK|MCG_MC_LIRC_DIV2( 1U )); /* High-frequency IRC Enabled. LIRC/2 = 4MHz to match Bus. Use MCGIRCLK for peripherals */
}