You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
6.8 KiB
C++
221 lines
6.8 KiB
C++
/*
|
|
MsTimer2.h - Using timer2 with 1ms resolution
|
|
Javier Valencia <javiervalencia80@gmail.com>
|
|
|
|
https://github.com/PaulStoffregen/MsTimer2
|
|
|
|
History:
|
|
6/Jun/14 - V0.7 added support for Teensy 3.0 & 3.1
|
|
29/Dec/11 - V0.6 added support for ATmega32u4, AT90USB646, AT90USB1286 (paul@pjrc.com)
|
|
some improvements added by Bill Perry
|
|
note: uses timer4 on Atmega32u4
|
|
29/May/09 - V0.5 added support for Atmega1280 (thanks to Manuel Negri)
|
|
19/Mar/09 - V0.4 added support for ATmega328P (thanks to Jerome Despatis)
|
|
11/Jun/08 - V0.3
|
|
changes to allow working with different CPU frequencies
|
|
added support for ATMega128 (using timer2)
|
|
compatible with ATMega48/88/168/8
|
|
10/May/08 - V0.2 added some security tests and volatile keywords
|
|
9/May/08 - V0.1 released working on ATMEGA168 only
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <MsTimer2.h>
|
|
|
|
unsigned long MsTimer2::msecs;
|
|
void (*MsTimer2::func)();
|
|
volatile unsigned long MsTimer2::count;
|
|
volatile char MsTimer2::overflowing;
|
|
volatile unsigned int MsTimer2::tcnt2;
|
|
#if defined(__arm__) && defined(TEENSYDUINO)
|
|
static IntervalTimer itimer;
|
|
#endif
|
|
|
|
void MsTimer2::set(unsigned long ms, void (*f)()) {
|
|
float prescaler = 0.0;
|
|
|
|
if (ms == 0)
|
|
msecs = 1;
|
|
else
|
|
msecs = ms;
|
|
|
|
func = f;
|
|
|
|
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
|
TIMSK2 &= ~(1<<TOIE2);
|
|
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
|
|
TCCR2B &= ~(1<<WGM22);
|
|
ASSR &= ~(1<<AS2);
|
|
TIMSK2 &= ~(1<<OCIE2A);
|
|
|
|
if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64
|
|
TCCR2B |= (1<<CS22);
|
|
TCCR2B &= ~((1<<CS21) | (1<<CS20));
|
|
prescaler = 64.0;
|
|
} else if (F_CPU < 1000000UL) { // prescaler set to 8
|
|
TCCR2B |= (1<<CS21);
|
|
TCCR2B &= ~((1<<CS22) | (1<<CS20));
|
|
prescaler = 8.0;
|
|
} else { // F_CPU > 16Mhz, prescaler set to 128
|
|
TCCR2B |= ((1<<CS22) | (1<<CS20));
|
|
TCCR2B &= ~(1<<CS21);
|
|
prescaler = 128.0;
|
|
}
|
|
#elif defined (__AVR_ATmega8__)
|
|
TIMSK &= ~(1<<TOIE2);
|
|
TCCR2 &= ~((1<<WGM21) | (1<<WGM20));
|
|
TIMSK &= ~(1<<OCIE2);
|
|
ASSR &= ~(1<<AS2);
|
|
|
|
if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64
|
|
TCCR2 |= (1<<CS22);
|
|
TCCR2 &= ~((1<<CS21) | (1<<CS20));
|
|
prescaler = 64.0;
|
|
} else if (F_CPU < 1000000UL) { // prescaler set to 8
|
|
TCCR2 |= (1<<CS21);
|
|
TCCR2 &= ~((1<<CS22) | (1<<CS20));
|
|
prescaler = 8.0;
|
|
} else { // F_CPU > 16Mhz, prescaler set to 128
|
|
TCCR2 |= ((1<<CS22) && (1<<CS20));
|
|
TCCR2 &= ~(1<<CS21);
|
|
prescaler = 128.0;
|
|
}
|
|
#elif defined (__AVR_ATmega128__)
|
|
TIMSK &= ~(1<<TOIE2);
|
|
TCCR2 &= ~((1<<WGM21) | (1<<WGM20));
|
|
TIMSK &= ~(1<<OCIE2);
|
|
|
|
if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64
|
|
TCCR2 |= ((1<<CS21) | (1<<CS20));
|
|
TCCR2 &= ~(1<<CS22);
|
|
prescaler = 64.0;
|
|
} else if (F_CPU < 1000000UL) { // prescaler set to 8
|
|
TCCR2 |= (1<<CS21);
|
|
TCCR2 &= ~((1<<CS22) | (1<<CS20));
|
|
prescaler = 8.0;
|
|
} else { // F_CPU > 16Mhz, prescaler set to 256
|
|
TCCR2 |= (1<<CS22);
|
|
TCCR2 &= ~((1<<CS21) | (1<<CS20));
|
|
prescaler = 256.0;
|
|
}
|
|
#elif defined (__AVR_ATmega32U4__)
|
|
TCCR4B = 0;
|
|
TCCR4A = 0;
|
|
TCCR4C = 0;
|
|
TCCR4D = 0;
|
|
TCCR4E = 0;
|
|
if (F_CPU >= 16000000L) {
|
|
TCCR4B = (1<<CS43) | (1<<PSR4);
|
|
prescaler = 128.0;
|
|
} else if (F_CPU >= 8000000L) {
|
|
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<CS40) | (1<<PSR4);
|
|
prescaler = 64.0;
|
|
} else if (F_CPU >= 4000000L) {
|
|
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<PSR4);
|
|
prescaler = 32.0;
|
|
} else if (F_CPU >= 2000000L) {
|
|
TCCR4B = (1<<CS42) | (1<<CS40) | (1<<PSR4);
|
|
prescaler = 16.0;
|
|
} else if (F_CPU >= 1000000L) {
|
|
TCCR4B = (1<<CS42) | (1<<PSR4);
|
|
prescaler = 8.0;
|
|
} else if (F_CPU >= 500000L) {
|
|
TCCR4B = (1<<CS41) | (1<<CS40) | (1<<PSR4);
|
|
prescaler = 4.0;
|
|
} else {
|
|
TCCR4B = (1<<CS41) | (1<<PSR4);
|
|
prescaler = 2.0;
|
|
}
|
|
tcnt2 = (int)((float)F_CPU * 0.001 / prescaler) - 1;
|
|
OCR4C = tcnt2;
|
|
return;
|
|
#elif defined(__arm__) && defined(TEENSYDUINO)
|
|
// nothing needed here
|
|
#else
|
|
#error Unsupported CPU type
|
|
#endif
|
|
|
|
tcnt2 = 256 - (int)((float)F_CPU * 0.001 / prescaler);
|
|
}
|
|
|
|
void MsTimer2::start() {
|
|
count = 0;
|
|
overflowing = 0;
|
|
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
|
TCNT2 = tcnt2;
|
|
TIMSK2 |= (1<<TOIE2);
|
|
#elif defined (__AVR_ATmega128__)
|
|
TCNT2 = tcnt2;
|
|
TIMSK |= (1<<TOIE2);
|
|
#elif defined (__AVR_ATmega8__)
|
|
TCNT2 = tcnt2;
|
|
TIMSK |= (1<<TOIE2);
|
|
#elif defined (__AVR_ATmega32U4__)
|
|
TIFR4 = (1<<TOV4);
|
|
TCNT4 = 0;
|
|
TIMSK4 = (1<<TOIE4);
|
|
#elif defined(__arm__) && defined(TEENSYDUINO)
|
|
itimer.begin(MsTimer2::_overflow, 1000);
|
|
#endif
|
|
}
|
|
|
|
void MsTimer2::stop() {
|
|
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
|
TIMSK2 &= ~(1<<TOIE2);
|
|
#elif defined (__AVR_ATmega128__)
|
|
TIMSK &= ~(1<<TOIE2);
|
|
#elif defined (__AVR_ATmega8__)
|
|
TIMSK &= ~(1<<TOIE2);
|
|
#elif defined (__AVR_ATmega32U4__)
|
|
TIMSK4 = 0;
|
|
#elif defined(__arm__) && defined(TEENSYDUINO)
|
|
itimer.end();
|
|
#endif
|
|
}
|
|
|
|
void MsTimer2::_overflow() {
|
|
count += 1;
|
|
|
|
if (count >= msecs && !overflowing) {
|
|
overflowing = 1;
|
|
count = count - msecs; // subtract ms to catch missed overflows
|
|
// set to 0 if you don't want this.
|
|
(*func)();
|
|
overflowing = 0;
|
|
}
|
|
}
|
|
|
|
#if defined (__AVR__)
|
|
#if defined (__AVR_ATmega32U4__)
|
|
ISR(TIMER4_OVF_vect) {
|
|
#else
|
|
ISR(TIMER2_OVF_vect) {
|
|
#endif
|
|
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
|
TCNT2 = MsTimer2::tcnt2;
|
|
#elif defined (__AVR_ATmega128__)
|
|
TCNT2 = MsTimer2::tcnt2;
|
|
#elif defined (__AVR_ATmega8__)
|
|
TCNT2 = MsTimer2::tcnt2;
|
|
#elif defined (__AVR_ATmega32U4__)
|
|
// not necessary on 32u4's high speed timer4
|
|
#endif
|
|
MsTimer2::_overflow();
|
|
}
|
|
#endif // AVR
|
|
|