forked from sensorium/Mozzi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTimerZero.cpp
More file actions
136 lines (125 loc) · 3.97 KB
/
TimerZero.cpp
File metadata and controls
136 lines (125 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
* TimerZero.cpp
*
* Copyright 2012 Tim Barrass
*
* This file is part of TimerZero, a library for Arduino.
*
* TimerZero 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.
*
* TimerZero 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 TimerZero. If not, see <http://www.gnu.org/licenses/>.
*
*/
// Based on TimerTwo,
// downloaded from https://bitbucket.org/johnmccombs, 4/2/2012
//
// TB2012 added Arduino.h include
// TB2012 replaced Timer 2 prescale factors with ones for Timer 0
// TB2012 replaced all Timer 2 register names with ones for timer 0
// TB2012 search/replaced TimerTwo with TimerZero
// TB2012 changed preScale array to suit Timer0
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <TimerZero.h>
#include <Arduino.h>
// allowed prescale factors
/*
#define PS1 (1 << CS20)
#define PS8 (1 << CS21)
#define PS32 (1 << CS21) | (1 << CS20)
#define PS64 (1 << CS22)
#define PS128 (1 << CS22) | (1 << CS20)
#define PS256 (1 << CS22) | (1 << CS21)
#define PS1024 (1 << CS22) | (1 << CS21) | (1 << CS20)
*/
#define PS1 (1 << CS00)
#define PS8 (1 << CS01)
#define PS64 (1 << CS01) | (1 << CS00)
#define PS256 (1 << CS02)
#define PS1024 (1 << CS02) | (1 << CS00)
// table by prescale = 2^n where n is the table index
static const unsigned char __attribute__((section(".progmem.data"))) preScale[] =
{
PS1, 0, 0, PS8, 0, 0, PS64, 0, PS256, 0, PS1024
};
bool TimerZero::reset_;
void (*TimerZero::f_)();
unsigned TimerZero::period_;
//------------------------------------------------------------------------------
// initialize timer 0
unsigned char TimerZero::init(unsigned usec, void (*f)(), bool reset)
{
f_ = f;
reset_ = reset;
// assume F_CPU is a multiple of 1000000
// number of clock ticks to delay usec microseconds
unsigned long ticks = usec * (F_CPU/1000000);
// determine prescale factor and TOP/OCR2A value
// use minimum prescale factor
unsigned char ps, i;
for (i = 0; i < sizeof(preScale); i++)
{
ps = pgm_read_byte(&preScale[i]);
if (ps && (ticks >> i) <= 256)
break;
}
//return error if usec is too large
if (i == sizeof(preScale))
return false;
period_ = ((long)(ticks >> i) * (1 << i))/ (F_CPU /1000000);
// Serial.println(i, DEC);
// disable timer 0 interrupts
TIMSK0 = 0;
// use system clock (clkI/O)
//ASSR &= ~(1 << AS2);
// Clear Timer on Compare Match (CTC) mode
TCCR0A = (1 << WGM01);
// only need prescale bits in TCCR0B
TCCR0B = ps;
// set TOP so timer period is (ticks >> i)
OCR0A = (ticks >> i) - 1;
return true;
}
//------------------------------------------------------------------------------
// Start timer zero interrupts
void TimerZero::start()
{
TIMSK0 |= (1 << OCIE0A);
}
//------------------------------------------------------------------------------
// Stop timer 2 interrupts
void TimerZero::stop()
{
TIMSK0 = 0;
}
//------------------------------------------------------------------------------
// ISR for timer 0 Compare A interrupt
// TB2012 added ISR_NOBLOCK so it can be interrupted by Timer 1 (audio)
ISR(TIMER0_COMPA_vect, ISR_NOBLOCK)
{
// disable timer 0 interrupts
TIMSK0 = 0;
// call user function
(*TimerZero::f_)();
// in case f_ enabled interrupts
cli();
// clear counter if reset_ is true
if (TimerZero::reset_)
{
// reset counter
TCNT0 = 0;
// clear possible pending interrupt
TIFR0 |= (1 << OCF0A);
}
// enable timer 2 COMPA interrupt
TIMSK0 |= (1 << OCIE0A);
}