Revision 1461
updated all the library code to have sensible _init behavior.
Almost all of the library components have a global variable which gets set after init and the functions inside will fail with an error code if init has not been called. Also, the init functions themselves check this variable and will bail out without doing any damage if that init has already been called
time.c | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (c) 2007 Colony Project |
|
3 |
* |
|
4 |
* Permission is hereby granted, free of charge, to any person |
|
5 |
* obtaining a copy of this software and associated documentation |
|
6 |
* files (the "Software"), to deal in the Software without |
|
7 |
* restriction, including without limitation the rights to use, |
|
8 |
* copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
9 |
* copies of the Software, and to permit persons to whom the |
|
10 |
* Software is furnished to do so, subject to the following |
|
11 |
* conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be |
|
14 |
* included in all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
17 |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|
18 |
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
19 |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
20 |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|
21 |
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
22 |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|
23 |
* OTHER DEALINGS IN THE SOFTWARE. |
|
24 |
**/ |
|
25 |
|
|
26 |
|
|
27 |
/** |
|
28 |
* @file time.c |
|
29 |
* @brief Timer code |
|
30 |
* |
|
31 |
* Implementation of functions for timers. |
|
32 |
* |
|
33 |
* @author Colony Project, CMU Robotics Club |
|
34 |
**/ |
|
35 |
|
|
36 |
/* |
|
37 |
time.c |
|
38 |
anything that requires a delay |
|
39 |
mostly delay_ms |
|
40 |
|
|
41 |
author: Robotics Club, Colony Project |
|
42 |
|
|
43 |
Change Log: |
|
44 |
2.5.07 - Kevin |
|
45 |
Aaron fixed the orb/servo code and made them use timer3 but compare registers B and C. He hard set the prescaler |
|
46 |
to 8 so the RTC broke. Changed it so that we use a 8 prescaler which sets the compare match at 1/16th of a second. |
|
47 |
You now count how many 16ths of a second you want until you trigger your actual interrupt. Works. Changed defines |
|
48 |
for time so you can still call rtc_init with a scale but now it is defined in terms of actual time like second, quarter_second |
|
49 |
etc. Read that section in the time.h file for more information. Tested and works, though the clock drifts more than |
|
50 |
it used to |
|
51 |
1.30.07 - Kevin |
|
52 |
Modified the clock to run on timer3 on the Dragonfly. Works with decent accuracy. Using a prescaler of 256 |
|
53 |
the timer counts up to a precomputer value which will trigger an interrupt and reset the timer. Multiples of |
|
54 |
256 change it by that multiple. Refer to the time.h file for all possible prescalers. |
|
55 |
The interrupt will call a specified function _rtc_func every pulse. |
|
56 |
All of it has been tested and it works. |
|
57 |
|
|
58 |
*/ |
|
59 |
#include <avr/interrupt.h> |
|
60 |
#include <util/delay.h> |
|
61 |
#include "time.h" |
|
62 |
|
|
1 |
/** |
|
2 |
* Copyright (c) 2007 Colony Project |
|
3 |
* |
|
4 |
* Permission is hereby granted, free of charge, to any person |
|
5 |
* obtaining a copy of this software and associated documentation |
|
6 |
* files (the "Software"), to deal in the Software without |
|
7 |
* restriction, including without limitation the rights to use, |
|
8 |
* copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
9 |
* copies of the Software, and to permit persons to whom the |
|
10 |
* Software is furnished to do so, subject to the following |
|
11 |
* conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be |
|
14 |
* included in all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
17 |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|
18 |
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
19 |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
20 |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|
21 |
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
22 |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|
23 |
* OTHER DEALINGS IN THE SOFTWARE. |
|
24 |
**/ |
|
63 | 25 |
|
26 |
|
|
27 |
/** |
|
28 |
* @file time.c |
|
29 |
* @brief Timer code |
|
30 |
* |
|
31 |
* Implementation of functions for timers. |
|
32 |
* |
|
33 |
* @author Colony Project, CMU Robotics Club |
|
34 |
**/ |
|
35 |
|
|
36 |
/* |
|
37 |
time.c |
|
38 |
anything that requires a delay |
|
39 |
mostly delay_ms |
|
40 |
|
|
41 |
author: Robotics Club, Colony Project |
|
42 |
|
|
43 |
Change Log: |
|
44 |
2.5.07 - Kevin |
|
45 |
Aaron fixed the orb/servo code and made them use timer3 but compare registers B and C. He hard set the prescaler |
|
46 |
to 8 so the RTC broke. Changed it so that we use a 8 prescaler which sets the compare match at 1/16th of a second. |
|
47 |
You now count how many 16ths of a second you want until you trigger your actual interrupt. Works. Changed defines |
|
48 |
for time so you can still call rtc_init with a scale but now it is defined in terms of actual time like second, quarter_second |
|
49 |
etc. Read that section in the time.h file for more information. Tested and works, though the clock drifts more than |
|
50 |
it used to |
|
51 |
1.30.07 - Kevin |
|
52 |
Modified the clock to run on timer3 on the Dragonfly. Works with decent accuracy. Using a prescaler of 256 |
|
53 |
the timer counts up to a precomputer value which will trigger an interrupt and reset the timer. Multiples of |
|
54 |
256 change it by that multiple. Refer to the time.h file for all possible prescalers. |
|
55 |
The interrupt will call a specified function _rtc_func every pulse. |
|
56 |
All of it has been tested and it works. |
|
57 |
|
|
58 |
*/ |
|
59 |
#include <avr/interrupt.h> |
|
60 |
#include <util/delay.h> |
|
61 |
#include "time.h" |
|
62 |
|
|
63 |
|
|
64 | 64 |
/* Calculate how many cycles to delay for to get 1 ms. Based on F_CPU which should be defined by the makefile */ |
65 | 65 |
#ifdef F_CPU |
66 | 66 |
#define WAIT_CYCLES ((F_CPU / 1000) / 10) |
67 | 67 |
#else |
68 | 68 |
#define WAIT_CYCLES (8000 / 10) |
69 | 69 |
#endif |
70 |
|
|
71 |
static volatile int _rtc_val = 0; |
|
72 |
static volatile int _rtc_pulse = 0; |
|
73 |
static volatile int _rtc_scale = 32; //Defaults to 1 Second per pulse |
|
74 |
static void (*_rtc_f)(void) = 0; |
|
75 | 70 |
|
76 | 71 |
|
77 |
|
|
78 |
/** |
|
79 |
* @defgroup time Time |
|
80 |
* @brief Time functions |
|
81 |
* |
|
82 |
* Functions dealing with time. |
|
83 |
* |
|
84 |
* @{ |
|
85 |
**/ |
|
86 |
|
|
87 |
/** |
|
88 |
* Delays for the specified number of milliseconds. |
|
72 |
unsigned char time_initd = 0; |
|
73 |
|
|
74 |
static volatile int _rtc_val = 0; |
|
75 |
static volatile int _rtc_pulse = 0; |
|
76 |
static volatile int _rtc_scale = 32; //Defaults to 1 Second per pulse |
|
77 |
static void (*_rtc_f)(void) = 0; |
|
78 |
|
|
79 |
|
|
80 |
|
|
81 |
/** |
|
82 |
* @defgroup time Time |
|
83 |
* @brief Time functions |
|
84 |
* |
|
85 |
* Functions dealing with time. |
|
86 |
* |
|
87 |
* @{ |
|
88 |
**/ |
|
89 |
|
|
90 |
/** |
|
91 |
* Delays for the specified number of milliseconds. |
|
89 | 92 |
* It depends on F_CPU to be defined in order to calculate how many cycles |
90 | 93 |
* it should delay. If it is not defined, a default clock of 8MHz is assumed. |
91 | 94 |
* |
92 | 95 |
* We use _delay_loop_2 which will run assembly instructions that should be |
93 | 96 |
* 4 cycles long. Optimizations must be enabled for this to be true. |
94 | 97 |
* That function is called to ensure around 1ms per execution. To generate |
95 |
* multiple ms we run a for loop of how many milliseconds are desired.
|
|
98 |
* multiple ms we run a for loop of how many milliseconds are desired. |
|
96 | 99 |
* |
97 | 100 |
* The error should be just the skew on the oscillator as the formula to |
98 | 101 |
* calculate delay cycles should always be a whole number. The is some skew |
99 | 102 |
* in practice though it is unavoidable. Delaying for less than 1s should make |
100 | 103 |
* the error negligable. |
101 |
*
|
|
102 |
* @param ms the number of milliseconds to delay for
|
|
103 |
**/
|
|
104 |
* |
|
105 |
* @param ms the number of milliseconds to delay for |
|
106 |
**/ |
|
104 | 107 |
void delay_ms(int ms) { |
105 | 108 |
for (; ms > 0; ms--) { |
106 | 109 |
_delay_loop_2(WAIT_CYCLES); |
107 | 110 |
} |
108 | 111 |
} |
109 | 112 |
|
110 |
|
|
111 |
/* Prescales defined in time.h. SECOND will give you 1 second. |
|
112 |
More scales are defined in the time.h file. |
|
113 |
rtc_func is the address to a function that you want called every clock tick. */ |
|
114 |
/** |
|
115 |
* Initializes the real time clock. Prescales are defined in time.h. |
|
116 |
* For example, SECOND will give 1 second. The specified function is |
|
117 |
* called every clock tick. For the real time clock to activate, |
|
118 |
* interrupts must be enabled. (through sei() ) |
|
119 |
* |
|
120 |
* @param prescale_opt the period with which the timer is triggered |
|
121 |
* @param rtc_func the function called when the timer is triggered |
|
122 |
* |
|
123 |
* @see rtc_get, rtc_reset |
|
124 |
* |
|
125 |
**/ |
|
126 |
void rtc_init(int prescale_opt, void (*rtc_func)(void)) { |
|
127 |
|
|
128 |
//Clear timer register for Timer 3 |
|
129 |
TCNT3 = 0; |
|
130 |
|
|
131 |
/* This sets the Waveform Generation Module to CTC (Clear Timer on Compare) Mode (100) |
|
132 |
See page135 in Atmega128 Docs for more modes and explanations */ |
|
133 |
TCCR3B |= _BV(WGM32); |
|
134 |
|
|
135 |
/* This sets the prescaler for the system clock (8MHz) ie: divides the clock by some number. |
|
136 |
Currently set to a prescaler of 8 because that is what the orb and servos use (they are on this timer as well) |
|
137 |
See page137 in Atemga128 Docs for all the available prescalers */ |
|
138 |
TCCR3B |= _BV(CS31); |
|
139 |
|
|
140 |
/* Sets the two regsiters that we compare against. So the timer counts up to this number and |
|
141 |
then resets back to 0 and calls the compare match interrupt. |
|
142 |
8x10^6 / 8 = 1/16 Second. All values are based off of this number. Do not change it unless you |
|
143 |
are l337*/ |
|
144 |
|
|
145 |
OCR3A = 0xF424; |
|
146 |
|
|
147 |
/* Enable Output Compare A Interrupt. When OCR3A is met by the timer TCNT3 this interrupt will be |
|
148 |
triggerd. (See page140 in Atmega128 Docs for more information */ |
|
149 |
ETIMSK |= _BV(OCIE3A); |
|
150 |
|
|
151 |
/* Store the pointer to the function to be used in the interrupt */ |
|
152 |
_rtc_f = rtc_func; |
|
153 |
|
|
154 |
/* Store how many 1/16ths of a second you want to let by before triggering an interrupt */ |
|
155 |
_rtc_scale = prescale_opt; |
|
156 |
} |
|
157 |
|
|
158 |
/** |
|
159 |
* Returns the time elapsed in seconds since the last call to |
|
160 |
* rtc_init or rtc_reset. |
|
161 |
* |
|
162 |
* @return the number of seconds since the last call to rtc_init or rtc_reset |
|
163 |
* |
|
164 |
* @see rtc_init, rtc_reset |
|
165 |
**/ |
|
166 |
int rtc_get(void) { |
|
167 |
return _rtc_val; |
|
168 |
} |
|
169 |
|
|
170 |
/** |
|
171 |
* Resets the real time clock counter to 0. |
|
172 |
* |
|
173 |
* @see rtc_init, rtc_get |
|
174 |
**/ |
|
175 |
void rtc_reset(void) { |
|
176 |
_rtc_val = 0; |
|
177 |
} |
|
178 |
|
|
179 |
/** @} **/ //end defgroup |
|
180 |
|
|
181 |
/* Called every pulse. Function in _rtc_f is called every _rtc_scale and also the counter is updated. |
|
182 |
Bascially, since the pulse is hard set at 1/16s you want to count how many 16ths of a second have passed |
|
183 |
and when it reaches the amount of time you want, execute the code. */ |
|
184 |
SIGNAL(TIMER3_COMPA_vect) { |
|
185 |
|
|
186 |
if (_rtc_pulse == _rtc_scale) { |
|
187 |
//Increment the real time clock counter |
|
188 |
_rtc_val++; |
|
189 |
|
|
190 |
//Calls the function tied to the real time clock if defined |
|
191 |
if(_rtc_f != 0) |
|
192 |
_rtc_f(); |
|
193 |
|
|
194 |
//Resets the pulse until the next scale is matched |
|
195 |
_rtc_pulse = 0; |
|
196 |
} |
|
197 |
|
|
198 |
//Updates the amount of pulses seen since the last scale match |
|
199 |
_rtc_pulse++; |
|
200 |
|
|
201 |
} |
|
113 |
|
|
114 |
/* Prescales defined in time.h. SECOND will give you 1 second. |
|
115 |
More scales are defined in the time.h file. |
|
116 |
rtc_func is the address to a function that you want called every clock tick. */ |
|
117 |
/** |
|
118 |
* Initializes the real time clock. Prescales are defined in time.h. |
|
119 |
* For example, SECOND will give 1 second. The specified function is |
|
120 |
* called every clock tick. For the real time clock to activate, |
|
121 |
* interrupts must be enabled. (through sei() ) |
|
122 |
* |
|
123 |
* @param prescale_opt the period with which the timer is triggered |
|
124 |
* @param rtc_func the function called when the timer is triggered |
|
125 |
* |
|
126 |
* @return 0 if init succesfull, an error code otherwise |
|
127 |
* |
|
128 |
* @see rtc_get, rtc_reset |
|
129 |
* |
|
130 |
**/ |
|
131 |
int rtc_init(int prescale_opt, void (*rtc_func)(void)) { |
|
132 |
|
|
133 |
if(time_initd) { |
|
134 |
return ERROR_INIT_ALREADY_INITD; |
|
135 |
} |
|
136 |
|
|
137 |
//Clear timer register for Timer 3 |
|
138 |
TCNT3 = 0; |
|
139 |
|
|
140 |
/* This sets the Waveform Generation Module to CTC (Clear Timer on Compare) Mode (100) |
|
141 |
See page135 in Atmega128 Docs for more modes and explanations */ |
|
142 |
TCCR3B |= _BV(WGM32); |
|
143 |
|
|
144 |
/* This sets the prescaler for the system clock (8MHz) ie: divides the clock by some number. |
|
145 |
Currently set to a prescaler of 8 because that is what the orb and servos use (they are on this timer as well) |
|
146 |
See page137 in Atemga128 Docs for all the available prescalers */ |
|
147 |
TCCR3B |= _BV(CS31); |
|
148 |
|
|
149 |
/* Sets the two regsiters that we compare against. So the timer counts up to this number and |
|
150 |
then resets back to 0 and calls the compare match interrupt. |
|
151 |
8x10^6 / 8 = 1/16 Second. All values are based off of this number. Do not change it unless you |
|
152 |
are l337*/ |
|
153 |
|
|
154 |
OCR3A = 0xF424; |
|
155 |
|
|
156 |
/* Enable Output Compare A Interrupt. When OCR3A is met by the timer TCNT3 this interrupt will be |
|
157 |
triggerd. (See page140 in Atmega128 Docs for more information */ |
|
158 |
ETIMSK |= _BV(OCIE3A); |
|
159 |
|
|
160 |
/* Store the pointer to the function to be used in the interrupt */ |
|
161 |
_rtc_f = rtc_func; |
|
162 |
|
|
163 |
/* Store how many 1/16ths of a second you want to let by before triggering an interrupt */ |
|
164 |
_rtc_scale = prescale_opt; |
|
165 |
|
|
166 |
time_initd = 1; |
|
167 |
|
|
168 |
return 0; |
|
169 |
} |
|
170 |
|
|
171 |
/** |
|
172 |
* Returns the time elapsed in seconds since the last call to |
|
173 |
* rtc_init or rtc_reset. |
|
174 |
* |
|
175 |
* @return the number of seconds since the last call to rtc_init or rtc_reset |
|
176 |
* |
|
177 |
* @see rtc_init, rtc_reset |
|
178 |
**/ |
|
179 |
int rtc_get(void) { |
|
180 |
return _rtc_val; |
|
181 |
} |
|
182 |
|
|
183 |
/** |
|
184 |
* Resets the real time clock counter to 0. |
|
185 |
* |
|
186 |
* @see rtc_init, rtc_get |
|
187 |
**/ |
|
188 |
void rtc_reset(void) { |
|
189 |
_rtc_val = 0; |
|
190 |
} |
|
191 |
|
|
192 |
/** @} **/ //end defgroup |
|
193 |
|
|
194 |
/* Called every pulse. Function in _rtc_f is called every _rtc_scale and also the counter is updated. |
|
195 |
Bascially, since the pulse is hard set at 1/16s you want to count how many 16ths of a second have passed |
|
196 |
and when it reaches the amount of time you want, execute the code. */ |
|
197 |
SIGNAL(TIMER3_COMPA_vect) { |
|
198 |
|
|
199 |
if (_rtc_pulse == _rtc_scale) { |
|
200 |
//Increment the real time clock counter |
|
201 |
_rtc_val++; |
|
202 |
|
|
203 |
//Calls the function tied to the real time clock if defined |
|
204 |
if(_rtc_f != 0) |
|
205 |
_rtc_f(); |
|
206 |
|
|
207 |
//Resets the pulse until the next scale is matched |
|
208 |
_rtc_pulse = 0; |
|
209 |
} |
|
210 |
|
|
211 |
//Updates the amount of pulses seen since the last scale match |
|
212 |
_rtc_pulse++; |
|
213 |
|
|
214 |
} |
Also available in: Unified diff