Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

# pulse.c

Go to the documentation of this file.

    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 }