X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Favr%2Fdrv%2Ftimer_xmega.c;fp=bertos%2Fcpu%2Favr%2Fdrv%2Ftimer_xmega.c;h=5bebf1c4a927b3bbb4bc34a4127af85fe820594a;hb=7af1283ce327bfe58eae21e167d20a47acf5bbd0;hp=0000000000000000000000000000000000000000;hpb=4c9e017d1b5cad3501d8d93aef46ec513bb03fd0;p=bertos.git diff --git a/bertos/cpu/avr/drv/timer_xmega.c b/bertos/cpu/avr/drv/timer_xmega.c new file mode 100644 index 00000000..5bebf1c4 --- /dev/null +++ b/bertos/cpu/avr/drv/timer_xmega.c @@ -0,0 +1,126 @@ +/** + * \file + * + * + * \author Onno + * + * \brief Low-level timer module for AVR XMEGA (implementation). + * + * This file is heavily inspired by the AVR implementation for BeRTOS, + * but uses a different approach for implementing the different debug + * ports, by using the timer structs. + * + * This module is automatically included so no need to include + * in test list. + * notest: xmega + */ + +#include +#include // BV() + +#include +#include + +#include + +/* Helper MACROS taken from the Atmel examples and altered + * + * The AVR XMEGA has different structures for TC0 and TC1, + * however these only differ in the amount of compare/capture + * channels, so for this purpose they can be used exactly the same + */ + +//check if the bitvalues of the TC0 and TC1 Timer/Counters are really the same +#if TC0_CLKSEL_gm != TC1_CLKSEL_gm || TC0_WGMODE_gm != TC1_WGMODE_gm || TC0_OVFINTLVL_gm != TC1_OVFINTLVL_gm + #error TC0 and TC1 Timer/Counters cannot be configured with the same bitvalues +#endif + +#define TIMER_CONFIG_CLOCK_SOURCE(_clkSel)\ + ((TIMERCOUNTER).CTRLA = ((TIMERCOUNTER).CTRLA & ~TC0_CLKSEL_gm) | _clkSel) + +#define TIMER_CLEAR_FLAGS() ((TIMERCOUNTER).INTFLAGS = 0xFF) + +#define TIMER_SET_PERIOD( _period ) ( (TIMERCOUNTER).PER = (_period) ) + +#define TIMER_SET_OVERFLOW_INTERRUPT_LEVEL( _interruptLevel )\ + ((TIMERCOUNTER).INTCTRLA = ( (TIMERCOUNTER).INTCTRLA & ~TC0_OVFINTLVL_gm ) | _interruptLevel) + +#define TIMER_CONFIG_WGM(_wgm)\ + ((TIMERCOUNTER).CTRLB = ( (TIMERCOUNTER).CTRLB & ~TC0_WGMODE_gm ) | _wgm) + +#define TIMER_RESET() ( (TIMERCOUNTER).CTRLFSET = TC_CMD_RESET_gc ) + +//Define TIMER_PRESCALE_REG_VALUE bases on the provided +//TIMER_PRESCALER value +#if TIMER_PRESCALER == 0 + #define TIMER_CLKSEL_gc TC_CLKSEL_OFF_gc +#elif TIMER_PRESCALER == 1 + #define TIMER_CLKSEL_gc TC_CLKSEL_DIV1_gc +#elif TIMER_PRESCALER == 2 + #define TIMER_CLKSEL_gc TC_CLKSEL_DIV2_gc +#elif TIMER_PRESCALER == 4 + #define TIMER_CLKSEL_gc TC_CLKSEL_DIV4_gc +#elif TIMER_PRESCALER == 16 + #define TIMER_CLKSEL_gc TC_CLKSEL_DIV16_gc +#elif TIMER_PRESCALER == 64 + #define TIMER_CLKSEL_gc TC_CLKSEL_DIV64_gc +#elif TIMER_PRESCALER == 256 + #define TIMER_CLKSEL_gc TC_CLKSEL_DIV256_gc +#elif TIMER_PRESCALER == 1024 + #define TIMER_CLKSEL_gc TC_CLKSEL_DIV1024_gc +#else + #error Invalid value for TIMER_PRESCALER has been defined! Using default of 1 + #define TIMER_CLKSEL_gc TC_CLKSEL_DIV1_gc +#endif + +void timer_hw_init(void) +{ + //Save and disable IRQ + cpu_flags_t flags; + IRQ_SAVE_DISABLE(flags); + //disable the timer + TIMER_CONFIG_CLOCK_SOURCE(TC_CLKSEL_OFF_gc); + //clear all flags + TIMER_CLEAR_FLAGS(); + //setup the Periode register value + //CNT register will be reset to 0 when CNT == PER + TIMER_SET_PERIOD(TIMER_PERIOD_VALUE); + //set the Waveform Generation Mode to Normal + TIMER_CONFIG_WGM(TC_WGMODE_NORMAL_gc); + //enable the overflow interrupt + //use the highest priority + TIMER_SET_OVERFLOW_INTERRUPT_LEVEL(TC_OVFINTLVL_HI_gc); + //enable timer by setting the correct prescaler/clock + TIMER_CONFIG_CLOCK_SOURCE(TIMER_CLKSEL_gc); + //Restore IRQ + IRQ_RESTORE(flags); +}