// Copyright 2009 Olivier Gillet. // // Author: Olivier Gillet (ol.gillet@gmail.com) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // ----------------------------------------------------------------------------- // // Definitions of timer and related PWM registers. #ifndef AVRLIB_TIMER_H_ #define AVRLIB_TIMER_H_ // interrupt.h is not strictly needed here, but .cc files including the timer // classes are likely to also define interrupt handlers (and we have macros for // that). #include #include #include "avrlib/avrlib.h" namespace avrlib { SpecialFunctionRegister(TCCR0A); SpecialFunctionRegister(TCCR0B); SpecialFunctionRegister(TCCR1A); SpecialFunctionRegister(TCCR1B); SpecialFunctionRegister(TCCR2A); SpecialFunctionRegister(TCCR2B); SpecialFunctionRegister(TIMSK0); SpecialFunctionRegister(TIMSK1); SpecialFunctionRegister(TIMSK2); SpecialFunctionRegister(TCNT0); SpecialFunctionRegister16(TCNT1); SpecialFunctionRegister(TCNT2); SpecialFunctionRegister(OCR0A); SpecialFunctionRegister(OCR0B); SpecialFunctionRegister(OCR1A); SpecialFunctionRegister(OCR1B); SpecialFunctionRegister(OCR2A); SpecialFunctionRegister(OCR2B); #ifdef HAS_TIMER3 SpecialFunctionRegister(TCCR3A); SpecialFunctionRegister(TCCR3B); SpecialFunctionRegister(TIMSK3); SpecialFunctionRegister(TCNT3); SpecialFunctionRegister(OCR3A); SpecialFunctionRegister(OCR3B); #endif // HAS_TIMER3 enum TimerMode { TIMER_NORMAL = 0, TIMER_PWM_PHASE_CORRECT = 1, TIMER_CTC = 2, TIMER_FAST_PWM = 3, }; template struct TimerImpl { typedef ControlRegisterA A; typedef ControlRegisterB B; static inline uint8_t value() { return *ValueRegister::ptr(); } static inline void Start() { *InterruptRegister::ptr() |= _BV(0); } static inline void Stop() { *InterruptRegister::ptr() &= ~(_BV(0)); } static inline void StartInputCapture() { *InterruptRegister::ptr() |= _BV(5); } static inline void StopInputCapture() { *InterruptRegister::ptr() &= ~(_BV(5)); } static inline void StartCompare() { *InterruptRegister::ptr() |= _BV(1); } static inline void StopCompare() { *InterruptRegister::ptr() &= ~(_BV(1)); } static inline void set_mode(TimerMode mode) { // Sets the mode registers. *ControlRegisterA::ptr() = (*ControlRegisterA::ptr() & 0xfc) | mode; } static inline void set_mode( uint8_t wg_mode_1, uint8_t wg_mode_2, uint8_t prescaler) { // Sets the mode registers. *ControlRegisterA::ptr() = wg_mode_1; *ControlRegisterB::ptr() = wg_mode_2 | prescaler; } static inline void set_value(uint16_t value) { *ValueRegister::ptr() = value; } // These are the values for MCUs clocked at 20 MHz // // Timer speed // value | fast | accurate // -------------------------------------- // 1 | 78.125 kHz | 39.215 kHz // 2 | 9.765 kHz | 4.901 kHz // 3 | 1220.7 Hz | 612.7 Hz // 4 | 305.2 Hz | 153.2 Hz // 5 | 76.3 Hz | 38.3 Hz static inline void set_prescaler(uint8_t prescaler) { *ControlRegisterB::ptr() = (*ControlRegisterB::ptr() & 0xf8) | prescaler; } }; template struct NumberedTimer { }; template<> struct NumberedTimer<0> { typedef TimerImpl< TCCR0ARegister, TCCR0BRegister, TIMSK0Register, TCNT0Register> Impl; }; template<> struct NumberedTimer<1> { typedef TimerImpl< TCCR1ARegister, TCCR1BRegister, TIMSK1Register, TCNT1Register> Impl; }; template<> struct NumberedTimer<2> { typedef TimerImpl< TCCR2ARegister, TCCR2BRegister, TIMSK2Register, TCNT2Register> Impl; }; #ifdef HAS_TIMER3 template<> struct NumberedTimer<3> { typedef TimerImpl< TCCR3ARegister, TCCR3BRegister, TIMSK3Register, TCNT3Register> Impl; }; #endif // HAS_TIMER3 template struct Timer { typedef typename NumberedTimer::Impl Impl; static inline uint8_t value() { return Impl::value(); } static inline void Start() { Impl::Start(); } static inline void Stop() { Impl::Stop(); } static inline void StartInputCapture() { Impl::StartInputCapture(); } static inline void StopInputCapture() { Impl::StopInputCapture(); } static inline void StartCompare() { Impl::StartCompare(); } static inline void StopCompare() { Impl::StopCompare(); } static inline void set_mode(TimerMode mode) { Impl::set_mode(mode); } static inline void set_mode(uint8_t a, uint8_t b, uint8_t c) { Impl::set_mode(a, b, c); } static inline void set_prescaler(uint8_t prescaler) { Impl::set_prescaler(prescaler); } }; template struct PwmChannel { typedef BitInRegister EnabledBit; enum { has_pwm = 1 }; static inline void Start() { EnabledBit::set(); } static inline void Stop() { EnabledBit::clear(); } static inline void Write(uint8_t value) { *PwmRegister::ptr() = value; } static inline void set_frequency(uint16_t f) { OCR1A = f; OCR1B = f >> 1; } static inline void set_frequency_pulse(uint16_t f) { OCR1A = f; OCR1B = f - (f >> 2); } }; struct NoPwmChannel { enum { has_pwm = 0 }; static inline void Start() { } static inline void Stop() { } static inline void Write(uint8_t value) { } }; typedef PwmChannel, COM0A1, OCR0ARegister> PwmChannel0A; typedef PwmChannel, COM0B1, OCR0BRegister> PwmChannel0B; typedef PwmChannel, COM1A1, OCR1ARegister> PwmChannel1A; typedef PwmChannel, COM1B1, OCR1BRegister> PwmChannel1B; typedef PwmChannel, COM2A1, OCR2ARegister> PwmChannel2A; typedef PwmChannel, COM2B1, OCR2BRegister> PwmChannel2B; // Readable aliases for timer interrupts. #define TIMER_0_TICK ISR(TIMER0_OVF_vect) #define TIMER_1_TICK ISR(TIMER1_OVF_vect) #define TIMER_2_TICK ISR(TIMER2_OVF_vect) #ifdef HAS_TIMER3 #define TIMER_3_TICK ISR(TIMER3_OVF_vect) #endif // HAS_TIMER3 } // namespace avrlib #endif // AVRLIB_TIMER_H_