Appendix

Here are the code examples for each case used in the technical brief.

XOSCHF with External Crystal

#define F_CPU 16000000ul

#include <avr/io.h>
#include <avr/cpufunc.h>

void CLOCK_XOSCHF_crystal_init(void);

static inline void LED0_init(void)
{
	PORTB.DIRSET = PIN3_bm;
}

int main(void)
{
	CLOCK_XOSCHF_crystal_init();

	/* Turn on LED0 to show successful clock init */
	LED0_init();

	/* Replace with your application code */
	while(1)
	{
	}
}


void CLOCK_XOSCHF_crystal_init(void)
{
	/* Enable crystal oscillator with frequency range 16 MHz and 4K cycles start-up time */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL_RUNSTDBY_bm
	             | CLKCTRL_CSUTHF_4K_gc
	             | CLKCTRL_FRQRANGE_16M_gc
	             | CLKCTRL_SELHF_CRYSTAL_gc
	             | CLKCTRL_ENABLE_bm);

	/* Confirm crystal oscillator start-up */
	while(!(CLKCTRL.MCLKSTATUS & CLKCTRL_EXTS_bm))
	{
		;
	}

	/* Clear Main Clock Prescaler */
	ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLB, 0x00);

	/* Set the main clock to use XOSCHF as source, and enable the CLKOUT pin */
	ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_EXTCLK_gc | CLKCTRL_CLKOUT_bm);

	/* Wait for system oscillator changing to complete */
	while(CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)
	{
		;
	}

	/* Clear RUNSTDBY for power save during sleep */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL.XOSCHFCTRLA & ~CLKCTRL_RUNSTDBY_bm);

	/* Change complete and the main clock is 16 MHz */
}

XOSCHF with External Clock

#define F_CPU 16000000ul

#include <avr/io.h>
#include <avr/cpufunc.h>

void CLOCK_XOSCHF_clock_init(void);

static inline void LED0_init(void)
{
	PORTB.DIRSET = PIN3_bm;
}

int main(void)
{
	CLOCK_XOSCHF_clock_init();

	/* Turn on LED0 to show successful clock init */
	LED0_init();

	/* Replace with your application code */
	while(1)
	{
	}
}


void CLOCK_XOSCHF_clock_init(void)
{
	/* Enable external (32 MHz) clock input */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL_SELHF_EXTCLOCK_gc | CLKCTRL_ENABLE_bm);

	/* Set Main Clock Prescaler */
	ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm);

	/* Set the main clock to use XOSCHF as source, and enable the CLKOUT pin */
	ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_EXTCLK_gc | CLKCTRL_CLKOUT_bm);

	/* Wait for system oscillator changing to complete */
	while(CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)
	{
		;
	}

	/* Change complete and the main clock is 32 MHz / 2 = 16 MHz */
}

RTC with XOSCHF

#include <avr/io.h>
#include <avr/cpufunc.h>
#include <avr/interrupt.h>

void CLOCK_XOSCHF_crystal_init(void);
void TIMER_RTC_init(void);

static inline void LED0_init(void)
{
	PORTB.DIRSET = PIN3_bm;
	PORTB.OUTSET = PIN3_bm;
}

static inline void LED0_toggle(void)
{
	PORTB.OUTTGL = PIN3_bm;
}

int main(void)
{
	CLOCK_XOSCHF_crystal_init();
	TIMER_RTC_init();
	LED0_init();

	/* Enable global interrupts */
	sei();

	/* Replace with your application code */
	while(1)
	{
	}
}


void CLOCK_XOSCHF_crystal_init(void)
{
	/* Enable crystal oscillator with frequency range 8 MHz and 1K cycles start-up time */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL_RUNSTDBY_bm
	             | CLKCTRL_CSUTHF_1K_gc
	             | CLKCTRL_FRQRANGE_8M_gc
	             | CLKCTRL_SELHF_CRYSTAL_gc
	             | CLKCTRL_ENABLE_bm);

	/* Confirm crystal oscillator start-up */
	while(!(CLKCTRL.MCLKSTATUS & CLKCTRL_EXTS_bm))
	{
		;
	}

	/* Clear RUNSTDBY for power save during sleep */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL.XOSCHFCTRLA & ~CLKCTRL_RUNSTDBY_bm);
}


void TIMER_RTC_init(void)
{
	while(RTC.STATUS > 0)
	{
		/* Wait for RTC registers to synchronize */
	}

	/* Configure RTC to use XOSCHF as source */
	RTC.CLKSEL = RTC_CLKSEL_EXTCLK_gc;

	/* Replace with your application configuration */
	RTC.PER = 0xffff;
	RTC.INTCTRL = RTC_OVF_bm;
	RTC.CTRLA = RTC_PRESCALER_DIV32_gc | RTC_RTCEN_bm;
}


ISR(RTC_CNT_vect)
{
	/* This interrupt will trigger every time the RTC overflows */
	LED0_toggle();

	/* Clear the RTC overflow interrupt flag */
	RTC.INTFLAGS = RTC_OVF_bm;
}

TCD with XOSCHF

#include <avr/io.h>
#include <avr/cpufunc.h>

void CLOCK_XOSCHF_crystal_init(void);
void TIMER_TCD0_init(void);

int main(void)
{
	CLOCK_XOSCHF_crystal_init();
	TIMER_TCD0_init();

	/* Replace with your application code */
	while(1)
	{
	}
}


void CLOCK_XOSCHF_crystal_init(void)
{
	/* Enable crystal oscillator with frequency range 16 MHz and 4K cycles start-up time */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL_RUNSTDBY_bm
	             | CLKCTRL_CSUTHF_4K_gc
	             | CLKCTRL_FRQRANGE_16M_gc
	             | CLKCTRL_SELHF_CRYSTAL_gc
	             | CLKCTRL_ENABLE_bm);

	/* Confirm crystal oscillator start-up */
	while(!(CLKCTRL.MCLKSTATUS & CLKCTRL_EXTS_bm))
	{
		;
	}

	/* Clear RUNSTDBY for power save during sleep */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL.XOSCHFCTRLA & ~CLKCTRL_RUNSTDBY_bm);
}


void TIMER_TCD0_init(void)
{
	/* Configure the TCD with XOSCHF (16 MHz) as source */
	TCD0.CTRLA = TCD_CLKSEL_EXTCLK_gc | TCD_CNTPRES_DIV1_gc | TCD_SYNCPRES_DIV1_gc;

	/* Replace with your application configuration */

	/* Enable TCD0 */
	TCD0.CTRLA |= TCD_ENABLE_bm;
}

TCD with XOSCHF and PLL

#include <avr/io.h>
#include <avr/cpufunc.h>

void CLOCK_XOSCHF_crystal_PLL_init(void);
void TIMER_TCD0_init(void);

int main(void)
{
	CLOCK_XOSCHF_crystal_PLL_init();
	TIMER_TCD0_init();

	/* Replace with your application code */
	while(1)
	{
	}
}


void CLOCK_XOSCHF_crystal_PLL_init(void)
{
	/* Enable crystal oscillator with frequency range 16 MHz and 4K cycles start-up time */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL_RUNSTDBY_bm
	             | CLKCTRL_CSUTHF_4K_gc
	             | CLKCTRL_FRQRANGE_16M_gc
	             | CLKCTRL_SELHF_CRYSTAL_gc
	             | CLKCTRL_ENABLE_bm);

	/* Confirm crystal oscillator start-up */
	while(!(CLKCTRL.MCLKSTATUS & CLKCTRL_EXTS_bm))
	{
		;
	}

	/* Set the PLL to use XOSCHF as source, and select 3x multiplication factor */
	ccp_write_io((uint8_t *) &CLKCTRL.PLLCTRLA, CLKCTRL_SOURCE_bm | CLKCTRL_MULFAC_3x_gc);

	/* Clear RUNSTDBY for power save during sleep */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL.XOSCHFCTRLA & ~CLKCTRL_RUNSTDBY_bm);
}


void TIMER_TCD0_init(void)
{
	/* Configure the TCD with PLL (48 MHz) as source */
	TCD0.CTRLA = TCD_CLKSEL_PLL_gc | TCD_CNTPRES_DIV1_gc | TCD_SYNCPRES_DIV1_gc;

	/* Replace with your application configuration */

	/* Enable TCD0 */
	TCD0.CTRLA |= TCD_ENABLE_bm;
}

CFD on XOSCHF

#define F_CPU 16000000ul

#include <avr/io.h>
#include <avr/cpufunc.h>
#include <avr/interrupt.h>

void CLOCK_XOSCHF_crystal_init(void);
void CLOCK_CFD_XOSCHF_init(void);

static inline void LED0_init(void)
{
	PORTB.DIRSET = PIN3_bm;
	PORTB.OUTSET = PIN3_bm;
}

static inline void LED0_toggle(void)
{
	PORTB.OUTTGL = PIN3_bm;
}

int main(void)
{
	CLOCK_XOSCHF_crystal_init();
	CLOCK_CFD_XOSCHF_init();
	LED0_init();

	/* Enable global interrupts */
	sei();

	/* Replace with your application code */
	while(1)
	{
	}
}


void CLOCK_XOSCHF_crystal_init(void)
{
	/* Enable crystal oscillator
	 * with frequency range 16 MHz and 4K cycles start-up time
	 */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL_RUNSTDBY_bm
	             | CLKCTRL_CSUTHF_4K_gc
	             | CLKCTRL_FRQRANGE_16M_gc
	             | CLKCTRL_SELHF_CRYSTAL_gc
	             | CLKCTRL_ENABLE_bm);

	/* Confirm crystal oscillator start-up */
	while(!(CLKCTRL.MCLKSTATUS & CLKCTRL_EXTS_bm))
	{
		;
	}
}


void CLOCK_CFD_XOSCHF_init(void)
{
	/* Enable Clock Failure Detection on XOSCHF */
	ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLC, CLKCTRL_CFDSRC_XOSCHF_gc | CLKCTRL_CFDEN_bm);

	/* Enable regular interrupt for CFD */
	ccp_write_io((uint8_t *) &CLKCTRL.MCLKINTCTRL, CLKCTRL_CFD_bm);
}


ISR(CLKCTRL_CFD_vect)
{
	/* This interrupt will trigger every time the CFD detects XOSCHF has stopped
	 * The Main Clock source is OSCHF so the CPU is not affected
	 */
	LED0_toggle();

	/* Clear the CFD interrupt flag */
	CLKCTRL.MCLKINTFLAGS = CLKCTRL_CFD_bm;
}

CFD on Main Clock with NMI

#define F_CPU 16000000ul

#include <avr/io.h>
#include <avr/cpufunc.h>
#include <avr/interrupt.h>
#include <util/delay.h>

void CLOCK_XOSCHF_crystal_init(void);
void CLOCK_CFD_CLKMAIN_init(void);

static inline void LED0_init(void)
{
	PORTB.DIRSET = PIN3_bm;
}

static inline void LED0_toggle(void)
{
	PORTB.OUTTGL = PIN3_bm;
}

int main(void)
{
	CLOCK_XOSCHF_crystal_init();
	CLOCK_CFD_CLKMAIN_init();
	LED0_init();

	/* Enable global interrupts */
	sei();

	/* Replace with your application code */
	while(1)
	{
		LED0_toggle();
		_delay_ms(200);
	}
}


void CLOCK_XOSCHF_crystal_init(void)
{
	/* Enable crystal oscillator
	 * with frequency range 16 MHz and 4K cycles start-up time
	 */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL_RUNSTDBY_bm
	             | CLKCTRL_CSUTHF_4K_gc
	             | CLKCTRL_FRQRANGE_16M_gc
	             | CLKCTRL_SELHF_CRYSTAL_gc
	             | CLKCTRL_ENABLE_bm);

	/* Confirm crystal oscillator start-up */
	while(!(CLKCTRL.MCLKSTATUS & CLKCTRL_EXTS_bm))
	{
		;
	}

	/* Clear Main Clock Prescaler */
	ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLB, 0x00);

	/* Set the main clock to use XOSCHF as source, and enable the CLKOUT pin */
	ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_EXTCLK_gc
	             | CLKCTRL_CLKOUT_bm);

	/* Wait for system oscillator changing to complete */
	while(CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)
	{
		;
	}

	/* Clear RUNSTDBY for power save when not in use */
	ccp_write_io((uint8_t *) &CLKCTRL.XOSCHFCTRLA, CLKCTRL.XOSCHFCTRLA & ~CLKCTRL_RUNSTDBY_bm);

	/* Change complete and the main clock is 16 MHz */
}


void CLOCK_CFD_CLKMAIN_init(void)
{
	/* Enable Clock Failure Detection on main clock */
	ccp_write_io((uint8_t *) &CLKCTRL.MCLKCTRLC, CLKCTRL_CFDSRC_CLKMAIN_gc
	             | CLKCTRL_CFDEN_bm);

	/* Enable interrupt for CFD */
	ccp_write_io((uint8_t *) &CLKCTRL.MCLKINTCTRL, CLKCTRL_INTTYPE_bm
	             | CLKCTRL_CFD_bm);
}


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 */
}