00001 /** 00002 \file Robots/LoBot/irccm/LoTimer.c 00003 \brief Timer API for Robolocust's iRobot Create Command Module control 00004 program. 00005 00006 This file defines the functions and variables used to implement the 00007 API for "generalized" one and ten millisecond timers for the iRobot 00008 Create Command Module control program used by Robolocust. This API 00009 provides a means for other parts of the control program to setup "stop 00010 clocks" and perform whatever operations they need while this stop 00011 clock ticks away. Additionally, these timers are "generalized" in the 00012 sense that client modules may register arbitrary callback functions 00013 that will be triggered each time the timer ISR kicks in. 00014 */ 00015 00016 /* 00017 ************************************************************************ 00018 * The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 * 00019 * by the University of Southern California (USC) and the iLab at USC. * 00020 * See http: iLab.usc.edu for information about this project. * 00021 * * 00022 * Major portions of the iLab Neuromorphic Vision Toolkit are protected * 00023 * under the U.S. patent ``Computation of Intrinsic Perceptual Saliency * 00024 * in Visual Environments, and Applications'' by Christof Koch and * 00025 * Laurent Itti, California Institute of Technology, 2001 (patent * 00026 * pending; application number 09/912,225 filed July 23, 2001; see * 00027 * http: pair.uspto.gov/cgi-bin/final/home.pl for current status). * 00028 ************************************************************************ 00029 * This file is part of the iLab Neuromorphic Vision C++ Toolkit. * 00030 * * 00031 * The iLab Neuromorphic Vision C++ Toolkit is free software; you can * 00032 * redistribute it and/or modify it under the terms of the GNU General * 00033 * Public License as published by the Free Software Foundation; either * 00034 * version 2 of the License, or (at your option) any later version. * 00035 * * 00036 * The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope * 00037 * that it will be useful, but WITHOUT ANY WARRANTY; without even the * 00038 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * 00039 * PURPOSE. See the GNU General Public License for more details. * 00040 * * 00041 * You should have received a copy of the GNU General Public License * 00042 * along with the iLab Neuromorphic Vision C++ Toolkit; if not, write * 00043 * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * 00044 * Boston, MA 02111-1307 USA. * 00045 ************************************************************************ 00046 */ 00047 00048 /* 00049 Primary maintainer for this file: mviswana usc edu 00050 $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/irccm/LoTimer.c $ 00051 $Id: LoTimer.c 13781 2010-08-12 17:37:02Z mviswana $ 00052 */ 00053 00054 /*------------------------------ HEADERS ------------------------------*/ 00055 00056 // lobot headers 00057 #include "LoTimer.h" 00058 00059 // AVR headers 00060 #include <avr/interrupt.h> 00061 #include <avr/io.h> 00062 00063 /*----------------------------- CONSTANTS -----------------------------*/ 00064 00065 // Both the 1ms and 10ms timers are associated with a list of arbitrary 00066 // callback functions that facilitate asynchronous operations across the 00067 // entire low-level controller. This enum specifies the maximum number of 00068 // callbacks supported for each "generalized timer." 00069 enum { 00070 LOBOT_MAX_TIMER_CALLBACKS = 5 00071 } ; 00072 00073 /*-------------------------- DATA STRUCTURES --------------------------*/ 00074 00075 // This structure is used to hold each generalized timer's list of 00076 // callbacks. 00077 typedef struct { 00078 int n ; // total number of callbacks in the list 00079 TimerCallback cb[LOBOT_MAX_TIMER_CALLBACKS] ; // callback list entries 00080 } cb_list ; 00081 00082 /*------------------------------ GLOBALS ------------------------------*/ 00083 00084 // This module uses the following variable to keep track of the total 00085 // number of milliseconds that have elapsed since the 1ms timer was 00086 // setup. 00087 static volatile unsigned long g_total_ticks ; 00088 00089 /* 00090 The stop watch implemented by this module works as follows: client 00091 modules setup a timer for some number of milliseconds and then test to 00092 see if the stop watch is running. For example: 00093 00094 lo_setup_timer(1000) ; 00095 while (lo_timer_is_running()) 00096 do_something() ; 00097 00098 These two variables are used internally by this module to implement 00099 the above functionality. 00100 00101 When clients setup a timer, g_stop_watch_ticks will be set to the 00102 number of milliseconds the stop watch should last and the 00103 g_stop_watch_running flag will be set to indicate that the stop watch 00104 is on. 00105 00106 The one millisecond timer's interrupt handler will then count down 00107 g_stop_watch_ticks. When the ticks reach zero, the interrupt handler 00108 will clear the g_stop_watch_running flag to indicate that the stop 00109 watch is done. 00110 00111 DEVNOTE: These two variables are modified by an interrupt service 00112 routine. Therefore, they *must* be declared volatile to prevent the 00113 compiler from optimizing them away. 00114 */ 00115 static volatile unsigned int g_stop_watch_ticks ; 00116 static volatile char g_stop_watch_running ; 00117 00118 // These two variables hold the callbacks for the two "generalized 00119 // timers" implemented by this module. 00120 static volatile cb_list g_timer1_callbacks ; 00121 static volatile cb_list g_timer10_callbacks ; 00122 00123 /*-------------------------- INITIALIZATION ---------------------------*/ 00124 00125 /* 00126 The following function sets up the 8-bit Timer0 to generate an 00127 interrupt every 1 ms (thus its designation within the low-level 00128 controller as timer1). 00129 00130 To do this, we need to set the WGM01 (Waveform Generation Mode) bit in 00131 Timer0's Timer/Counter Control Register (TCCR0A). This will enable 00132 Clear Timer on Compare (CTC) mode so that the hardware automatically 00133 clears the timer's count register after the timer fires (which means 00134 that we don't have to do it in software). 00135 00136 As per the ATmega168 datasheet, the WGM01 bit is bit #1. Since we 00137 don't care about the other bits in TCCR0A, we can set those to zero. 00138 Therefore, the value for TCCR0A will have to 0x02 in order to setup 00139 the timer in the mode we want. 00140 00141 Next, we need to select a clock source for the timer. To do that we 00142 have to set the CS bits in TCCR0B. These are bits 0, 1 and 2. Again, 00143 we don't care about the other bits in this register. 00144 00145 Since we want a timer with one millisecond resolution and the main 00146 clock signal is running at 18.432MHz, we will need a prescaler to 00147 ensure that the counter value we are counting up to can fit in the 00148 8-bit TCNT0 register. 00149 00150 The timer's counter value for a given target frequency is computed 00151 using the following formula: 00152 00153 C = F/(p * f) - 1 00154 00155 where F = the main clock frequency (18.432MHz) 00156 p = the selected prescaler 00157 f = the target frequency 00158 00159 For the ATmega168, Timer0 supports prescaler values of 1 (i.e., no 00160 prescale, which means that the timer runs at the same speed as the 00161 core CPU), 16, 64, 256 and 1024. 00162 00163 Since we want a 1ms timer, our target frequency, f, is 1000Hz. 00164 00165 Thus, the possible counter values for the available prescalers are: 00166 00167 p C 00168 ---- ------ 00169 1 18,431 00170 16 1,151 00171 64 287 00172 256 71 00173 1024 17 00174 00175 Clearly, the first three options are unviable because we will need a 00176 16-bit counter to store those C values. Therefore, we go with one of 00177 the last two in the above table. Quite arbitrarily, we choose p = 1024 00178 and C = 17. 00179 00180 To use a prescaler of 1024, we will have to set bits CS02 and CS00 in 00181 TCCR0B. In hex, the value we're talking about is 0x05. 00182 00183 And, as shown above, the Output Compare Register (OCR0A) will have to 00184 be initialized with a value of 17 (or 0x11 in hexadecimal). 00185 00186 Finally, to actually generate the desired interrupt when OCR0A reaches 00187 a value of 17, we have to setup Timer0's interrupt mask by fiddling 00188 with the right set of bits in the TIMSK0 register. The bit in question 00189 is OCIE0A (Timer/Counter0 Output Compare Match A Interrupt Enable). 00190 00191 As the per the ATmega168 datasheet, OCIE0A is bit #1 in TIMSK0. Thus, 00192 setting TIMSK0 to 0x02 results in the timer interrupt being fired as 00193 configured by TCCR0A, TCCR0B and OCR0A. 00194 */ 00195 static void timer1_init(void) 00196 { 00197 TCCR0A = 0x02 ; // CTC mode 00198 TCCR0B = 0x05 ; // prescaler = 1024 00199 OCR0A = 0x11 ; // count from 0 to 17 for 1ms 00200 TIMSK0 = 0x02 ; // trigger interrupt when OCR0A reaches above value 00201 } 00202 00203 /* 00204 The following function sets up the 8-bit Timer2 to generate an 00205 interrupt every 10 ms (thus its designation within this low-level 00206 control program as timer10). 00207 00208 To setup Timer2 to fire every 10ms, we first need to set the WGM01 00209 (Waveform Generation Mode) bit in Timer2's Timer/Counter Control 00210 Register (TCCR2A). This will enable Clear Timer on Compare (CTC) mode 00211 so that the hardware automatically clears the timer's count register 00212 after the timer fires (which means that we don't have to do it in 00213 software). 00214 00215 As per the ATmega168 datasheet, the WGM01 bit is bit #1. Since we 00216 don't care about the other bits in TCCR2A, we can set those to zero. 00217 Therefore, the value for TCCR2A will have to be 0x02 in order to setup 00218 the timer in the mode we want. 00219 00220 Next, we need to select a clock source for the timer. To do that we 00221 have to set the CS bits in TCCR2B. These are bits 0, 1 and 2. Again, 00222 we don't care about the other bits in this register. 00223 00224 Since we want a timer with 10 ms resolution and the main clock signal 00225 is running at 18.432MHz, we will need a prescaler to ensure that the 00226 counter value we are counting up to can fit in the 8-bit TCNT2 00227 register. 00228 00229 The timer's counter value for a given target frequency is computed 00230 using the following formula: 00231 00232 C = F/(p * f) - 1 00233 00234 where F = the main clock frequency (18.432MHz) 00235 p = the selected prescaler 00236 f = the target frequency 00237 00238 For the ATmega168, Timer2 supports prescaler values of 1 (i.e., no 00239 prescale, which means that the timer runs at the same speed as the 00240 core CPU), 8, 32, 64, 128, 256 and 1024. 00241 00242 Since we want a 10ms timer, our target frequency, f, is 100Hz. 00243 00244 Thus, the possible counter values for the available prescalers are: 00245 00246 p C 00247 ---- ------- 00248 1 184,319 00249 32 5,759 00250 64 2,879 00251 128 1,439 00252 256 719 00253 1024 179 00254 00255 Clearly, the last option is the only viable one because its C value is 00256 the only one that will fit in an 8-bit register. 00257 00258 To use a prescaler of 1024, we will have to set bits CS22, CS21 and 00259 CS20 in TCCR2B. In hex, the value we're talking about is 0x07. 00260 00261 And, as shown above, the Output Compare Register (OCR2A) will have to 00262 be initialized with a value of 179 (B3 in hexadecimal). 00263 00264 Finally, to actually generate the desired interrupt when OCR2A reaches 00265 a value of 17, we have to setup Timer0's interrupt mask by fiddling 00266 with the right set of bits in the TIMSK2 register. The bit in question 00267 is OCIE2A (Timer/Counter2 Output Compare Match A Interrupt Enable). 00268 00269 As the per the ATmega168 datasheet, OCIE2A is bit #1 in TIMSK2. Thus, 00270 setting TIMSK2 to 0x02 results in the timer interrupt being fired as 00271 configured by TCCR2A, TCCR2B and OCR2A. 00272 */ 00273 static void timer10_init(void) 00274 { 00275 TCCR2A = 0x02 ; // CTC mode 00276 TCCR2B = 0x07 ; // prescaler = 1024 00277 OCR2A = 0xB3 ; // count from 0 to 179 for 10ms 00278 TIMSK2 = 0x02 ; // trigger interrupt when OCR2A reaches above value 00279 } 00280 00281 // This function initializes the two "generalized timers" supported by 00282 // this module. 00283 void lo_init_timer(void) 00284 { 00285 timer1_init() ; 00286 timer10_init() ; 00287 } 00288 00289 // Add a 1ms timer callback 00290 void lo_add_timer1_cb(TimerCallback t) 00291 { 00292 if (g_timer1_callbacks.n < LOBOT_MAX_TIMER_CALLBACKS) 00293 g_timer1_callbacks.cb[g_timer1_callbacks.n++] = t ; 00294 } 00295 00296 // Add a 10ms timer callback 00297 void lo_add_timer10_cb(TimerCallback t) 00298 { 00299 if (g_timer10_callbacks.n < LOBOT_MAX_TIMER_CALLBACKS) 00300 g_timer10_callbacks.cb[g_timer10_callbacks.n++] = t ; 00301 } 00302 00303 /*---------------------- TIMER INTERRUPT HANDLERS ---------------------*/ 00304 00305 // Helper function to invoke each of the callback functions stored in the 00306 // supplied callback list. 00307 static void trigger_callbacks(volatile cb_list* callbacks) 00308 { 00309 for (int i = 0; i < callbacks->n; ++i) 00310 (*(callbacks->cb[i]))() ; 00311 } 00312 00313 // Timer0 interrupt handler for the 1ms timer: this "generalized timer" 00314 // is responsible for maintaining the "global clock" (viz., the total 00315 // 1ms ticks since the timer was setup) and for implementing the 1ms 00316 // resolution timer delays. 00317 // 00318 // Additionally, it triggers the 1ms timer callbacks registered by client 00319 // modules. 00320 ISR(TIMER0_COMPA_vect) 00321 { 00322 ++g_total_ticks ; 00323 00324 if (g_stop_watch_ticks) 00325 --g_stop_watch_ticks ; 00326 else 00327 g_stop_watch_running = 0 ; 00328 00329 trigger_callbacks(&g_timer1_callbacks) ; 00330 } 00331 00332 // Timer2 interrupt handler for the 10ms timer: this "generalized timer" 00333 // only triggers the callback functions registered by client modules; it 00334 // has no other task other than helping facilitate application wide 00335 // support for asynchronous operation in 10ms increments. 00336 ISR(TIMER2_COMPA_vect) 00337 { 00338 trigger_callbacks(&g_timer10_callbacks) ; 00339 } 00340 00341 /*----------------------------- TIMER API -----------------------------*/ 00342 00343 // Return the current total number of milliseconds that have elapsed 00344 // since Timer0 was setup. 00345 unsigned long lo_ticks(void) 00346 { 00347 return g_total_ticks ; 00348 } 00349 00350 // Setup a stop watch for the specified number of milliseconds 00351 void lo_setup_timer(unsigned int ms) 00352 { 00353 g_stop_watch_ticks = ms ; 00354 g_stop_watch_running = 1 ; 00355 } 00356 00357 // Check if a stop watch is running 00358 char lo_timer_is_running() 00359 { 00360 return g_stop_watch_running ; 00361 } 00362 00363 // Busy wait for the specified number of milliseconds 00364 void lo_wait(unsigned int ms) 00365 { 00366 g_stop_watch_ticks = ms ; 00367 g_stop_watch_running = 1 ; 00368 while (g_stop_watch_running) 00369 ; 00370 }