// 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_