00001 /*! \file pulse.c \brief Pulse/frequency generation function library. */ 00002 //***************************************************************************** 00003 // 00004 // File Name : 'pulse.c' 00005 // Title : Pulse/frequency generation function library 00006 // Author : Pascal Stang - Copyright (C) 2000-2002 00007 // Created : 2002-08-19 00008 // Revised : 2003-05-29 00009 // Version : 0.7 00010 // Target MCU : Atmel AVR Series 00011 // Editor Tabs : 4 00012 // 00013 // This code is distributed under the GNU Public License 00014 // which can be found at http://www.gnu.org/licenses/gpl.txt 00015 // 00016 //***************************************************************************** 00017 00018 #ifndef WIN32 00019 #include <avr/io.h> 00020 #include <avr/signal.h> 00021 #include <avr/interrupt.h> 00022 #include <avr/pgmspace.h> 00023 #endif 00024 00025 #include "global.h" 00026 #include "timer.h" 00027 #include "pulse.h" 00028 00029 // Global variables 00030 // pulse generation registers 00031 volatile static unsigned char PulseT1AMode; 00032 volatile static unsigned short PulseT1ACount; 00033 volatile static unsigned short PulseT1APeriodTics; 00034 volatile static unsigned char PulseT1BMode; 00035 volatile static unsigned short PulseT1BCount; 00036 volatile static unsigned short PulseT1BPeriodTics; 00037 00038 // pulse mode bit definitions 00039 // PULSE_MODE_COUNTED 00040 // if true, the requested number of pulses are output, then output is turned off 00041 // if false, pulses are output continuously 00042 #define PULSE_MODE_CONTINUOUS 0x00 00043 #define PULSE_MODE_COUNTED 0x01 00044 00045 // functions 00046 00047 void pulseInit(void) 00048 { 00049 // initialize timer1 for pulse operation 00050 pulseT1Init(); 00051 } 00052 00053 void pulseT1Init(void) 00054 { 00055 // try to make sure that timer1 is in "normal" mode 00056 // most importantly, turn off PWM mode 00057 timer1PWMOff(); 00058 00059 // set some reasonable initial values 00060 // in case the user forgets to 00061 PulseT1AMode = 0; 00062 PulseT1BMode = 0; 00063 PulseT1ACount = 0; 00064 PulseT1BCount = 0; 00065 PulseT1APeriodTics = 0x8000; 00066 PulseT1BPeriodTics = 0x8000; 00067 00068 // attach the pulse service routines to 00069 // the timer 1 output compare A and B interrupts 00070 timerAttach(TIMER1OUTCOMPAREA_INT,pulseT1AService); 00071 timerAttach(TIMER1OUTCOMPAREB_INT,pulseT1BService); 00072 } 00073 00074 void pulseT1Off(void) 00075 { 00076 // turns pulse outputs off immediately 00077 00078 // set pulse counters to zero (finished) 00079 PulseT1ACount = 0; 00080 PulseT1BCount = 0; 00081 // disconnect OutputCompare action from OC1A pin 00082 cbi(TCCR1A,COM1A1); 00083 cbi(TCCR1A,COM1A0); 00084 // disconnect OutputCompare action from OC1B pin 00085 cbi(TCCR1A,COM1B1); 00086 cbi(TCCR1A,COM1B0); 00087 // detach the pulse service routines 00088 timerDetach(TIMER1OUTCOMPAREA_INT); 00089 timerDetach(TIMER1OUTCOMPAREB_INT); 00090 } 00091 00092 void pulseT1ASetFreq(u16 freqHz) 00093 { 00094 // set the frequency of the pulse output 00095 // we need to find the requested period/2 (in timer tics) 00096 // from the frequency (in hertz) 00097 00098 // calculate how many tics in period/2 00099 // this is the (timer tic rate)/(2*requested freq) 00100 PulseT1APeriodTics = ((u32)F_CPU/((u32)timer1GetPrescaler()*2*freqHz)); 00101 } 00102 00103 void pulseT1BSetFreq(u16 freqHz) 00104 { 00105 // set the frequency of the pulse output 00106 // we need to find the requested period/2 (in timer tics) 00107 // from the frequency (in hertz) 00108 00109 // calculate how many tics in period/2 00110 // this is the (timer tic rate)/(2*requested freq) 00111 PulseT1BPeriodTics = ((u32)F_CPU/((u32)timer1GetPrescaler()*2*freqHz)); 00112 } 00113 00114 void pulseT1ARun(u16 nPulses) 00115 { 00116 // set the number of pulses we want and the mode 00117 if(nPulses) 00118 { 00119 // if the nPulses is non-zero, use "counted" mode 00120 PulseT1AMode |= PULSE_MODE_COUNTED; 00121 PulseT1ACount = nPulses<<1; 00122 } 00123 else 00124 { 00125 // if nPulses is zero, run forever 00126 PulseT1AMode &= ~PULSE_MODE_COUNTED; 00127 PulseT1ACount = 1<<1; 00128 } 00129 // set OutputCompare action to toggle OC1A pin 00130 cbi(TCCR1A,COM1A1); 00131 sbi(TCCR1A,COM1A0); 00132 00133 // now the "enabling" stuff 00134 00135 // set the output compare one pulse cycle ahead of current timer position 00136 // to make sure we don't have to wait until the timer overflows and comes 00137 // back to the current value 00138 // set future output compare time to TCNT1 + PulseT1APeriodTics 00139 //outw(OCR1A, inw(TCNT1) + PulseT1APeriodTics); 00140 OCR1A += PulseT1APeriodTics; 00141 00142 // enable OutputCompare interrupt 00143 sbi(TIMSK, OCIE1A); 00144 } 00145 00146 void pulseT1BRun(u16 nPulses) 00147 { 00148 // set the number of pulses we want and the mode 00149 if(nPulses) 00150 { 00151 // if the nPulses is non-zero, use "counted" mode 00152 PulseT1BMode |= PULSE_MODE_COUNTED; 00153 PulseT1BCount = nPulses<<1; 00154 } 00155 else 00156 { 00157 // if nPulses is zero, run forever 00158 PulseT1BMode &= ~PULSE_MODE_COUNTED; 00159 PulseT1BCount = 1<<1; 00160 } 00161 // set OutputCompare action to toggle OC1B pin 00162 // (note: with all the A's and B's flying around, TCCR1A is not a bug) 00163 cbi(TCCR1A,COM1B1); 00164 sbi(TCCR1A,COM1B0); 00165 00166 // now the "enabling" stuff 00167 00168 // set the output compare one pulse cycle ahead of current timer position 00169 // to make sure we don't have to wait until the timer overflows and comes 00170 // back to the current value 00171 // set future output compare time to TCNT1 + PulseT1APeriodTics 00172 //outw(OCR1B, inw(TCNT1) + PulseT1BPeriodTics); 00173 OCR1B += PulseT1BPeriodTics; 00174 00175 // enable OutputCompare interrupt 00176 sbi(TIMSK, OCIE1B); 00177 } 00178 00179 void pulseT1AStop(void) 00180 { 00181 // stop output regardless of remaining pulses or mode 00182 // go to "counted" mode 00183 PulseT1AMode |= PULSE_MODE_COUNTED; 00184 // set pulses to zero 00185 PulseT1ACount = 0; 00186 } 00187 00188 void pulseT1BStop(void) 00189 { 00190 // stop output regardless of remaining pulses or mode 00191 // go to "counted" mode 00192 PulseT1BMode |= PULSE_MODE_COUNTED; 00193 // set pulses to zero 00194 PulseT1BCount = 0; 00195 } 00196 00197 u16 pulseT1ARemaining(void) 00198 { 00199 // return the number of pulses remaining for channel A 00200 // add 1 to make sure we round up, >>1 equivalent to /2 00201 return (PulseT1ACount+1)>>1; 00202 } 00203 00204 u16 pulseT1BRemaining(void) 00205 { 00206 // return the number of pulses remaining for channel A 00207 // add 1 to make sure we round up, >>1 equivalent to /2 00208 return (PulseT1BCount+1)>>1; 00209 } 00210 00211 void pulseT1AService(void) 00212 { 00213 // check if TimerPulseACount is non-zero 00214 // (i.e. pulses are still requested) 00215 if(PulseT1ACount) 00216 { 00217 //u16 OCValue; 00218 // read in current value of output compare register OCR1A 00219 //OCValue = inp(OCR1AL); // read low byte of OCR1A 00220 //OCValue += inp(OCR1AH)<<8; // read high byte of OCR1A 00221 // increment OCR1A value by PulseT1APeriodTics 00222 //OCValue += PulseT1APeriodTics; 00223 // set future output compare time to this new value 00224 //outp((OCValue>>8), OCR1AH); // write high byte 00225 //outp((OCValue & 0x00FF),OCR1AL); // write low byte 00226 00227 // the following line should be identical in operation 00228 // to the lines above, but for the moment, I'm not convinced 00229 // this method is bug-free. At least it's simpler! 00230 //outw(OCR1A, inw(OCR1A) + PulseT1APeriodTics); 00231 // change again 00232 OCR1A += PulseT1APeriodTics; 00233 00234 // decrement the number of pulses executed 00235 if(PulseT1AMode & PULSE_MODE_COUNTED) 00236 PulseT1ACount--; 00237 } 00238 else 00239 { 00240 // pulse count has reached zero 00241 // disable the output compare's action on OC1A pin 00242 cbi(TCCR1A,COM1A1); 00243 cbi(TCCR1A,COM1A0); 00244 // and disable the output compare's interrupt to stop pulsing 00245 cbi(TIMSK, OCIE1A); 00246 } 00247 } 00248 00249 void pulseT1BService(void) 00250 { 00251 // check if TimerPulseACount is non-zero 00252 // (i.e. pulses are still requested) 00253 if(PulseT1BCount) 00254 { 00255 //u16 OCValue; 00256 // read in current value of output compare register OCR1B 00257 //OCValue = inp(OCR1BL); // read low byte of OCR1B 00258 //OCValue += inp(OCR1BH)<<8; // read high byte of OCR1B 00259 // increment OCR1B value by PulseT1BPeriodTics 00260 //OCValue += PulseT1BPeriodTics; 00261 // set future output compare time to this new value 00262 //outp((OCValue>>8), OCR1BH); // write high byte 00263 //outp((OCValue & 0x00FF),OCR1BL); // write low byte 00264 00265 // the following line should be identical in operation 00266 // to the lines above, but for the moment, I'm not convinced 00267 // this method is bug-free. At least it's simpler! 00268 //outw(OCR1B, inw(OCR1B) + PulseT1BPeriodTics); 00269 // change again 00270 OCR1B += PulseT1BPeriodTics; 00271 00272 00273 // decrement the number of pulses executed 00274 if(PulseT1BMode & PULSE_MODE_COUNTED) 00275 PulseT1BCount--; 00276 } 00277 else 00278 { 00279 // pulse count has reached zero 00280 // disable the output compare's action on OC1B pin 00281 cbi(TCCR1A,COM1B1); 00282 cbi(TCCR1A,COM1B0); 00283 // and disable the output compare's interrupt to stop pulsing 00284 cbi(TIMSK, OCIE1B); 00285 } 00286 }