summaryrefslogtreecommitdiff
path: root/trunk/darwin/firmware/Sanguino/Sanguino3G/SanguinoMaster/Timer1.h
blob: ab3571cb02ab9377c683213fffbd39d6fa33a03d (plain)
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
137
138
139
140
141
// Yep, this is actually -*- c++ -*-

#ifndef _TIMER1_H_
#define _TIMER1_H_

//these routines provide an easy interface for controlling timer1 interrupts

inline void enableTimer1Interrupt()
{
  TIMSK1 |= (1<<OCIE1A);
}

inline void disableTimer1Interrupt()
{
  TIMSK1 &= ~(1<<OCIE1A);
	TIMSK1 &= ~(1<<ICIE1);
}

inline void setTimer1Resolution(byte r)
{
  //from table 15-5 in that atmega168 datasheet:
  // we're setting CS12 - CS10 which correspond to the binary numbers 0-5
  // 0 = no timer
  // 1 = no prescaler
  // 2 = clock/8
  // 3 = clock/64
  // 4 = clock/256
  // 5 = clock/1024

  if (r > 5)
    r = 5;

  TCCR1B &= B11111000;
  TCCR1B |= r;
}

inline void setTimer1Ceiling(unsigned int c)
{
  OCR1A = c;
}


unsigned int getTimer1Ceiling(unsigned long ticks)
{
  // our slowest speed at our highest resolution ( (2^16-1) * 0.0625 usecs = 4095 usecs)
  if (ticks <= 65535L)
    return (ticks & 0xffff);
  // our slowest speed at our next highest resolution ( (2^16-1) * 0.5 usecs = 32767 usecs)
  else if (ticks <= 524280L)
    return ((ticks / 8) & 0xffff);
  // our slowest speed at our medium resolution ( (2^16-1) * 4 usecs = 262140 usecs)
  else if (ticks <= 4194240L)
    return ((ticks / 64) & 0xffff);
  // our slowest speed at our medium-low resolution ( (2^16-1) * 16 usecs = 1048560 usecs)
  else if (ticks <= 16776960L)
    return (ticks / 256);
  // our slowest speed at our lowest resolution ((2^16-1) * 64 usecs = 4194240 usecs)
  else if (ticks <= 67107840L)
    return (ticks / 1024);
  //its really slow... hopefully we can just get by with super slow.
  else
    return 65535;
}

byte getTimer1Resolution(unsigned long ticks)
{
  // these also represent frequency: 1000000 / ticks / 2 = frequency in hz.

  // our slowest speed at our highest resolution ( (2^16-1) * 0.0625 usecs = 4095 usecs (4 millisecond max))
  // range: 8Mhz max - 122hz min
  if (ticks <= 65535L)
    return 1;
  // our slowest speed at our next highest resolution ( (2^16-1) * 0.5 usecs = 32767 usecs (32 millisecond max))
  // range:1Mhz max - 15.26hz min
  else if (ticks <= 524280L)
    return 2;
  // our slowest speed at our medium resolution ( (2^16-1) * 4 usecs = 262140 usecs (0.26 seconds max))
  // range: 125Khz max - 1.9hz min
  else if (ticks <= 4194240L)
    return 3;
  // our slowest speed at our medium-low resolution ( (2^16-1) * 16 usecs = 1048560 usecs (1.04 seconds max))
  // range: 31.25Khz max - 0.475hz min
  else if (ticks <= 16776960L)
    return 4;
  // our slowest speed at our lowest resolution ((2^16-1) * 64 usecs = 4194240 usecs (4.19 seconds max))
  // range: 7.812Khz max - 0.119hz min
  else if (ticks <= 67107840L)
    return 5;
  //its really slow... hopefully we can just get by with super slow.
  else
    return 5;
}

inline void setTimer1Ticks(unsigned long ticks)
{
  // ticks is the delay between interrupts in 62.5 nanosecond ticks.
  //
  // we break it into 5 different resolutions based on the delay. 
  // then we set the resolution based on the size of the delay.
  // we also then calculate the timer ceiling required. (ie what the counter counts to)
  // the result is the timer counts up to the appropriate time and then fires an interrupt.

  setTimer1Ceiling(getTimer1Ceiling(ticks));
  setTimer1Resolution(getTimer1Resolution(ticks));
}

inline void setTimer1Micros(unsigned long micros)
{
  //16 ticks in a microsecond.
  unsigned long ticks = micros * 16;
  
  setTimer1Ticks(ticks);
}

void setupTimer1Interrupt()
{
  //clear the registers
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1C = 0;
  TIMSK1 = 0;

  //waveform generation = 0100 = CTC
  TCCR1B &= ~(1<<WGM13);
  TCCR1B |=  (1<<WGM12);
  TCCR1A &= ~(1<<WGM11); 
  TCCR1A &= ~(1<<WGM10);

  //output mode = 00 (disconnected)
  TCCR1A &= ~(1<<COM1A1); 
  TCCR1A &= ~(1<<COM1A0);
  TCCR1A &= ~(1<<COM1B1); 
  TCCR1A &= ~(1<<COM1B0);

  //start off with a slow frequency.
  setTimer1Resolution(5);
  setTimer1Ceiling(65535);
  disableTimer1Interrupt();
}

#endif