Hello,
I'm not able to change MCG mode from FEE to FEI in case of Loss Of Clock.
I'm using a custom board mounting MK22FX512VLK12 or MK22FX512V12 (mask 3N03G). On the custom board is also mounted an external I2C RTC, which 32-kHz output is used as reference clock for the RTC oscillator.
At startup, MCU starts by default in FEI mode (using the internal 32-kHz clock). In the main, I change then the MCG mode from FEI to FEE, using the external 32-kHz as reference clock.
I also enable the external clock monitor for generating an interrupt in case of loss of clock (CME1 = 1, LOCRE1= 0).
In case of loss of lock then (removing a jumper on the board that cuts off the 32-kHz signal), within the MCG ISR I change the MCG mode from FEE to FEI, but the bit IREFST remains 0, meaning that the source of the FLL reference clock is still the external one.
Is it possible to change MCGmode from FEE to FEI in case of loss of clock without resetting the MCU? I have found no documentation about that.
Here is my very simple example code
void setFEE (void)
{
MCG_C7 |= MCG_C7_OSCSEL_MASK;
MCG_C1 = 0;
MCG_C4 |= (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0x03));
while ((MCG_S & MCG_S_IREFST_MASK) != 0x00U)
{
;
}
while ((MCG_S & 0x0CU) != 0x00U)
{
;
}
MCG_C8 = MCG_C8_CME1_MASK;
NVICIP57 = NVIC_IP_PRI57(0x80);
NVICISER1 |= NVIC_ISER_SETENA(0x2000000);
}
void setFEI (void)
{
MCG_C7 |= MCG_C7_OSCSEL_MASK;
MCG_C1 |= MCG_C1_IREFS_MASK;
MCG_C4 |= (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0x03));
MCG_C8 &= ~(MCG_C8_CME1_MASK);
while((MCG_S & MCG_S_IREFST_MASK) == 0x00U)
{
/* I'm stucking here when configuring from FEE to FEI within ISR. */
;
}
while((MCG_S & 0x0CU) != 0x00U)
{
;
}
}
void lossOfLockIsr ()
{
MCG_S = (MCG_S_LOLS_MASK | MCG_S_CLKST(0x00));
Cpu_SetFEIMode ();
NVICIP57 &= ~NVIC_IP_PRI57(0x80);
NVICICER1 = NVIC_ICER_CLRENA(0x2000000);
}
void main (void)
{
setFEE ();
while (1)
;
}
If a reset request is generated instead of interrupt (LOCRE1 = 1), everything is working correctly (MCU resets and it starts in FEI mode by default, with IREFST bit set to 1).
Hi,
It's supported to switch to the FEI from the FEE, and I've attached the code as below, please for details.
int fll_freq(int fll_ref)
{
int fll_freq_hz;
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_hz = (fll_ref * 732);
if (fll_freq_hz < 20000000) {return 0x33;}
else if (fll_freq_hz > 25000000) {return 0x34;}
break;
case 1:
fll_freq_hz = (fll_ref * 1464);
if (fll_freq_hz < 40000000) {return 0x35;}
else if (fll_freq_hz > 50000000) {return 0x36;}
break;
case 2:
fll_freq_hz = (fll_ref * 2197);
if (fll_freq_hz < 60000000) {return 0x37;}
else if (fll_freq_hz > 75000000) {return 0x38;}
break;
case 3:
fll_freq_hz = (fll_ref * 2929);
if (fll_freq_hz < 80000000) {return 0x39;}
else if (fll_freq_hz > 100000000) {return 0x3A;}
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_hz = (fll_ref * 640);
if (fll_freq_hz < 20000000) {return 0x33;}
else if (fll_freq_hz > 25000000) {return 0x34;}
break;
case 1:
fll_freq_hz = (fll_ref * 1280);
if (fll_freq_hz < 40000000) {return 0x35;}
else if (fll_freq_hz > 50000000) {return 0x36;}
break;
case 2:
fll_freq_hz = (fll_ref * 1920);
if (fll_freq_hz < 60000000) {return 0x37;}
else if (fll_freq_hz > 75000000) {return 0x38;}
break;
case 3:
fll_freq_hz = (fll_ref * 2560);
if (fll_freq_hz < 80000000) {return 0x39;}
else if (fll_freq_hz > 100000000) {return 0x3A;}
break;
}
}
return fll_freq_hz;
} // fll_freq
int fee_fei(int slow_irc_freq)
{
short i;
int mcg_out;
// Check MCG is in FEE mode
if (!((((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) == 0x0) && // check CLKS mux has selcted FLL
(!(MCG_S & MCG_S_IREFST_MASK)) && // check FLL ref is external ref clk
(!(MCG_S & MCG_S_PLLST_MASK)))) // check PLLS mux has selected FLL
{
return 0x2; // return error code
}
// Check IRC frequency is within spec.
if ((slow_irc_freq < 31250) || (slow_irc_freq > 39063))
{
return 0x31;
}
// Check resulting FLL frequency
mcg_out = fll_freq(slow_irc_freq);
if (mcg_out < 0x5B) {return mcg_out;} // If error code returned, return the code to calling function
// Ensure clock monitor is disabled before switching to FEI otherwise a loss of clock will trigger
MCG_C6 &= ~MCG_C6_CME0_MASK;
// Change FLL reference clock from external to internal by setting IREFS bit
MCG_C1 |= MCG_C1_IREFS_MASK; // select internal reference
// wait for Reference clock to switch to internal reference
for (i = 0 ; i < 2000 ; i++)
{
if (MCG_S & MCG_S_IREFST_MASK) break; // jump out early if IREFST sets before loop finishes
}
if (!(MCG_S & MCG_S_IREFST_MASK)) return 0x12; // check bit is really set and return with error if not set
// Now in FEI mode
return mcg_out;
} // fee_fei
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi,
thank you for the support.
I've just tried using your code, but I'm still not be able to change back MCG to FEI mode.
I got stuck here
if (MCG_S & MCG_S_IREFST_MASK) break; // jump out early if IREFST sets before loop finishes
So the function returns with the code 0x12
if (!(MCG_S & MCG_S_IREFST_MASK)) return 0x12; // check bit is really set and return with error if not set
It's like that IREFST bit is never set (the same thing happens using my code).
Did you try the code? Using which board/MCU?
Hi,
This code is from the TWR-K60D100 example demo, and the K22 contains the MCG module which is as same as the K60_100.
And the code can work well on the TWR-K60D100 board.
I was wondering if you can share your project, then I can reproduce this same issue on the FRDM-K22F board.
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi,
some updates:
the code you provided (and also mine), works well if "loss of lock" event is not triggered. I mean, as still as the external 32khz is active, I can change between FEI/FEE and viceversa without problems.
The problem occurs if external 32khz is "killed" (in my case, removing a jumper on the board). In this case, software is still running because of DCO feedback, ISR is triggered but configuring MCG back to FEI just fails.
Anyway, attached to this message you will find the KSDK project for testing it: you should be able to compile without problems regenerating PE code and (maybe) changing KSDK path.
Thank you for the support.
Alessandro
Hi,
Thanks for your reply.
I think remove the jumper to stop the external 32KHz to feed the MCU is the root accuse of the issue.
I'd like to confirm with you about when you remove the jumper on the board.
I'm looking forward to your reply.
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi,
that's exactly what I'm trying to do.
I'd like to change from FEE to FEI whenever a "loss of clock" event occurs: for forcing such event, I'm removing the jumper in order to kill the external source clock reference and to trigger the interrupt, changing then MCG to FEI.
I'd like to understand if this operation is legal or not: in such scenario, IREFST bit is never set.
Reading the datasheet, this operation should be possible (it just says that changing from FEE to FEI and viceversa is allowed, without saying if external source clock reference must be present or not).
Thanks again for the support.
Alessandro
Hi,
I'd like to confirm the steps of forcing the "loss of clock" event.
Did you remove the jumper before you start changing the MCG mode from the FEE to FEI or not?
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi,
I remove the jumper before changing from FEE to FEI.
The steps I do are reported as follows:
1. power on the board (MCU starts with FEI mode by default);
2. after startup, I change MCG mode from FEI to FEE;
3. I enable the MCG interrupt in the vector table in case of loss of clock event;
/* Enable the loss of lock interrupt in MCG module. */
MCG_C8 = MCG_C8_CME1_MASK;
/* Set priority and enable interrupt. */
NVICIP57 = NVIC_IP_PRI57(0x80);
NVICISER1 |= NVIC_ISER_SETENA(0x2000000);
4. I then start my application as usual;
At some point, I remove the jumper in order to generate the "loss of clock" event. The MCG ISR is then triggered and executed.
PE_ISR(Cpu_INT_MCGInterrupt)
{
MCG_S = (MCG_S_LOLS_MASK | MCG_S_CLKST(0x00)); /* Clear Loss of Lock status flag */
/* Switch to FEI mode. */
Cpu_SetFEIMode ();
}
When the ISR is executed, the 32-kHz external reference clock is already "dead".
Hi,
We have a similar issue. Did you find a solution?
Hi,
sorry for the delayed response.
No solution for the problem: if I cutoff the external 32khz signal, the ISR triggers but can't change mode to FEI.
Despite it, the board continues to run normally because of the 'feedback signal' named DCOOUT (on the datasheet it can be found under the Multipurpose Clock Generator (MCG) block diagram).
Our final solution was to generate a reset in case of LOC, saving a flag in the no reset ram, and configuring the FEI after the reset.