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