3.2 Configure the CFD to Detect Failures on the Main Clock
Todo:
- Edit the CLOCK_CFD_CLKMAIN_init() function so that the CFD is set up to monitor the main clock and generates an NMI upon clock failure
- Set up the NMI handler
- Create a main clock failure using the software test
- Enable the CFD and set the main
clock as the source by
adding:
ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLC, CLKCTRL_CFDSRC_CLKMAIN_gc | CLKCTRL_CFDEN_bm);
to CLOCK_CFD_CLKMAIN_init(). - Enable the CFD interrupt and set
the interrupt type to NMI by writing:
ccp_write_io((uint8_t *) &CLKCTRL.MCLKINTCTRL, CLKCTRL_INTTYPE_bm | CLKCTRL_CFD_bm);
Info: The CFD can create a normal interrupt or non-maskable interrupt depending on the setting in the Interrupt Type (INTTYPE) bit in the Main Clock Interrupt Control (CLKCTRL.MCLKINTCTRL) register. The advantage with an NMI is that the interrupt will trigger even if the microcontroller is in an interrupt or the global interrupt is disabled. This ensures that the interrupt will be executed straight away, and the error can be handled straight away. The only way to exit an NMI is by a device reset. - In the
ISR(NMI_vect), add the code to check if a CFD triggered
the NMI and to blink the
LED:
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. */ /* Toggle the LED forever */ while(1) { LED0_toggle(); _delay_ms(200); // 200 ms calculated from 16 MHz == 800 ms } } else { /* A different NMI has been triggered */ }
Info: There is only one interrupt vector for all the NMIs, so to be sure which NMI caused the interrupt, check the respective interrupt flags. - In the
ISR(PORTB_PORT_vect), add the code to trigger a clock
failure when SW0 is
pressed:
ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLC, CLKCTRL.MCLKCTRLC | CLKCTRL_CFDTST_bm);
Info: When setting the Clock Failure Detection Test (CFDTST) bit in the Main Clock Control C (MCLKCTRL) register, hardware simulates a clock failure to test the CFD feature. - Verify that the solution/project builds by selecting the Build → Build Solution from the top menu bare in Atmel Studio or by pressing the F7 key.
- Flash the device by selecting the Debug → Start without debugging from the top menu bar in Atmel Studio or by pressing the Ctrl+Alt+F5 keys.
Result: After pressing SW0, the LED0 will start blinking with a lower frequency. This
because the main clock source is switched to the start-up clock source, and the Main
Clock Control B (CLKCTRL.MCLKCTRLB) register will be written to the reset value when
a clock failure is detected. The number of clock ticks needed to create the
delay_ms(200) is calculated using the XOSCHF clock frequency
of 16 MHz, resulting in the delay_ms being four times as slow
when the clock source is switched to the 4 MHz internal clock.
Info: The start-up clock source is decided by the Clock
Select (CLKSEL) bit field in the Oscillator Configuration (OSCCFG) fuse.
Warning: As the MCLKCTRLB
register is written to its default values by the CFD, the clock will not be
available on the CLKOUT pin until it is set by the user again.