10 CFD on Main Clock with NMI
To use Clock Failure Detection (CFD) on the Main Clock, write the CLKMAIN
setting to the Clock Failure Detection Source (CFDSRC) bit field and ‘1
’ to
the Clock Failure Detection Enable (CFDEN) bit in the Main Clock Control C (CLKCTRL.MCLKCTRLC)
register.
This register has Configuration Change Protection (CCP), so
the ccp_write_io
function in cpufunc.h
should be used
to ensure correct timing for the unlock of the register.
/* Enable Clock Failure Detection on main clock */ ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLC, CLKCTRL_CFDSRC_CLKMAIN_gc | CLKCTRL_CFDEN_bm);
To enable the CFD interrupt as a Non-Maskable Interrupt (NMI), write
‘1
’ to both the Interrupt Type (INTTYPE) bit and the Clock Failure
Detection (CFD) bit in the Main Clock Interrupt Control (CLKCTRL.MCLKINTCTRL) register. This
register also has CCP.
/* Enable Non-Maskable Interrupt for CFD */ ccp_write_io((uint8_t *) &CLKCTRL.MCLKINTCTRL, CLKCTRL_INTTYPE_bm | CLKCTRL_CFD_bm);
When the CFD interrupt has been configured as an NMI, the NMI interrupt vector will be called instead of the CFD vector when the interrupt is triggered.
When entering the Interrupt Service Routine (ISR) for the NMI, the interrupt
source must be found if more than one NMI source is enabled. The CFD interrupt flag in the
Main Clock Interrupt Flags (CLKCTRL.MCLKINTFLAGS) register is ‘1
’ if the CFD
was the trigger.
ISR(NMI_vect) { /* Check which NMI has triggered*/ if(CLKCTRL.MCLKINTFLAGS & CLKCTRL_CFD_bm) { /* This interrupt will trigger if the source for the main clock fails * and the CFD is able to switch to a different working clock. * In this case that means XOSCHF has failed and is replaced by OSCHF. * The main clock is therefore reduced to 4 MHz / 2 = 2 MHz. */ /* Toggle the LED forever */ while(1) { LED0_toggle(); _delay_ms(200); // 200 ms calculated from 16 MHz == 1600 ms } } else { /* A different NMI has been triggered */ } /* Non-Maskable Interrupt bits can only be cleared by a reset */ }
A software reset can be triggered by writing a ‘1
’ to the
Software Reset (SWRST) bit in the Software Reset Register (RSTCTRL.SWRR). This register also
has CCP.
/* Software Reset */ ccp_write_io((uint8_t *) &RSTCTRL.SWRR, RSTCTRL_SWRST_bm);
The code for this example is available in the
CFD-on-main-clock-with-NMI folder in these github
repositories: