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 extern short __attribute__ ((progmem)) TimerPrescaleFactor[]; 00031 // pulse generation registers 00032 volatile static unsigned char PulseT1AMode; 00033 volatile static unsigned short PulseT1ACount; 00034 volatile static unsigned short PulseT1APeriodTics; 00035 volatile static unsigned char PulseT1BMode; 00036 volatile static unsigned short PulseT1BCount; 00037 volatile static unsigned short PulseT1BPeriodTics; 00038 00039 // pulse mode bit definitions 00040 // PULSE_MODE_COUNTED 00041 // if true, the requested number of pulses are output, then output is turned off 00042 // if false, pulses are output continuously 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 // get the current prescaler setting 00099 u16 prescaleDiv = 1<<(PRG_RDB(TimerPrescaleFactor+(inp(TCCR1B) & TIMER_PRESCALE_MASK))); 00100 // calculate how many tics in period/2 00101 // this is the (timer tic rate)/(2*requested freq) 00102 PulseT1APeriodTics = ((u32)F_CPU/((u32)prescaleDiv*2*freqHz)); 00103 } 00104 00105 void pulseT1BSetFreq(u16 freqHz) 00106 { 00107 // set the frequency of the pulse output 00108 // we need to find the requested period/2 (in timer tics) 00109 // from the frequency (in hertz) 00110 00111 // get the current prescaler setting 00112 u16 prescaleDiv = 1<<(PRG_RDB(TimerPrescaleFactor+(inp(TCCR1B) & TIMER_PRESCALE_MASK))); 00113 // calculate how many tics in period/2 00114 // this is the (timer tic rate)/(2*requested freq) 00115 PulseT1BPeriodTics = ((u32)F_CPU/((u32)prescaleDiv*2*freqHz)); 00116 } 00117 00118 void pulseT1ARun(u16 nPulses) 00119 { 00120 // set the number of pulses we want and the mode 00121 if(nPulses) 00122 { 00123 // if the nPulses is non-zero, use "counted" mode 00124 PulseT1AMode |= PULSE_MODE_COUNTED; 00125 PulseT1ACount = nPulses<<1; 00126 } 00127 else 00128 { 00129 // if nPulses is zero, run forever 00130 PulseT1AMode &= ~PULSE_MODE_COUNTED; 00131 PulseT1ACount = 1<<1; 00132 } 00133 // set OutputCompare action to toggle OC1A pin 00134 cbi(TCCR1A,COM1A1); 00135 sbi(TCCR1A,COM1A0); 00136 00137 // now the "enabling" stuff 00138 00139 // set the output compare one pulse cycle ahead of current timer position 00140 // to make sure we don't have to wait until the timer overflows and comes 00141 // back to the current value 00142 // set future output compare time to TCNT1 + PulseT1APeriodTics 00143 outw(OCR1A, inw(TCNT1) + PulseT1APeriodTics); 00144 00145 // enable OutputCompare interrupt 00146 sbi(TIMSK, OCIE1A); 00147 } 00148 00149 void pulseT1BRun(u16 nPulses) 00150 { 00151 // set the number of pulses we want and the mode 00152 if(nPulses) 00153 { 00154 // if the nPulses is non-zero, use "counted" mode 00155 PulseT1BMode |= PULSE_MODE_COUNTED; 00156 PulseT1BCount = nPulses<<1; 00157 } 00158 else 00159 { 00160 // if nPulses is zero, run forever 00161 PulseT1BMode &= ~PULSE_MODE_COUNTED; 00162 PulseT1BCount = 1<<1; 00163 } 00164 // set OutputCompare action to toggle OC1B pin 00165 // (note: with all the A's and B's flying around, TCCR1A is not a bug) 00166 cbi(TCCR1A,COM1B1); 00167 sbi(TCCR1A,COM1B0); 00168 00169 // now the "enabling" stuff 00170 00171 // set the output compare one pulse cycle ahead of current timer position 00172 // to make sure we don't have to wait until the timer overflows and comes 00173 // back to the current value 00174 // set future output compare time to TCNT1 + PulseT1APeriodTics 00175 outw(OCR1B, inw(TCNT1) + PulseT1BPeriodTics); 00176 00177 // enable OutputCompare interrupt 00178 sbi(TIMSK, OCIE1B); 00179 } 00180 00181 void pulseT1AStop(void) 00182 { 00183 // stop output regardless of remaining pulses or mode 00184 // go to "counted" mode 00185 PulseT1AMode |= PULSE_MODE_COUNTED; 00186 // set pulses to zero 00187 PulseT1ACount = 0; 00188 } 00189 00190 void pulseT1BStop(void) 00191 { 00192 // stop output regardless of remaining pulses or mode 00193 // go to "counted" mode 00194 PulseT1BMode |= PULSE_MODE_COUNTED; 00195 // set pulses to zero 00196 PulseT1BCount = 0; 00197 } 00198 00199 u16 pulseT1ARemaining(void) 00200 { 00201 // return the number of pulses remaining for channel A 00202 // add 1 to make sure we round up, >>1 equivalent to /2 00203 return (PulseT1ACount+1)>>1; 00204 } 00205 00206 u16 pulseT1BRemaining(void) 00207 { 00208 // return the number of pulses remaining for channel A 00209 // add 1 to make sure we round up, >>1 equivalent to /2 00210 return (PulseT1BCount+1)>>1; 00211 } 00212 00213 void pulseT1AService(void) 00214 { 00215 // check if TimerPulseACount is non-zero 00216 // (i.e. pulses are still requested) 00217 if(PulseT1ACount) 00218 { 00219 //u16 OCValue; 00220 // read in current value of output compare register OCR1A 00221 //OCValue = inp(OCR1AL); // read low byte of OCR1A 00222 //OCValue += inp(OCR1AH)<<8; // read high byte of OCR1A 00223 // increment OCR1A value by PulseT1APeriodTics 00224 //OCValue += PulseT1APeriodTics; 00225 // set future output compare time to this new value 00226 //outp((OCValue>>8), OCR1AH); // write high byte 00227 //outp((OCValue & 0x00FF),OCR1AL); // write low byte 00228 00229 // the following line should be identical in operation 00230 // to the lines above, but for the moment, I'm not convinced 00231 // this method is bug-free. At least it's simpler! 00232 outw(OCR1A, inw(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 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 }