Project

General

Profile

Revision 1461

Added by Brad Neuman over 14 years ago

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

View differences:

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