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