| Line No. | Rev | Author | Line |
|---|---|---|---|
| 1 | 6 | kaklik | /*! \file pulse.c \brief Pulse/frequency generation function library. */ |
| 2 | //***************************************************************************** |
||
| 3 | // |
||
| 4 | // File Name : 'pulse.c' |
||
| 5 | // Title : Pulse/frequency generation function library |
||
| 6 | // Author : Pascal Stang - Copyright (C) 2000-2002 |
||
| 7 | // Created : 2002-08-19 |
||
| 8 | // Revised : 2003-05-29 |
||
| 9 | // Version : 0.7 |
||
| 10 | // Target MCU : Atmel AVR Series |
||
| 11 | // Editor Tabs : 4 |
||
| 12 | // |
||
| 13 | // This code is distributed under the GNU Public License |
||
| 14 | // which can be found at http://www.gnu.org/licenses/gpl.txt |
||
| 15 | // |
||
| 16 | //***************************************************************************** |
||
| 17 | |||
| 18 | #include <avr/io.h> |
||
| 19 | #include <avr/interrupt.h> |
||
| 20 | #include <avr/pgmspace.h> |
||
| 21 | |||
| 22 | #include "global.h" |
||
| 23 | #include "timer.h" |
||
| 24 | #include "pulse.h" |
||
| 25 | |||
| 26 | // Global variables |
||
| 27 | // pulse generation registers |
||
| 28 | volatile static unsigned char PulseT1AMode; |
||
| 29 | volatile static unsigned short PulseT1ACount; |
||
| 30 | volatile static unsigned short PulseT1APeriodTics; |
||
| 31 | volatile static unsigned char PulseT1BMode; |
||
| 32 | volatile static unsigned short PulseT1BCount; |
||
| 33 | volatile static unsigned short PulseT1BPeriodTics; |
||
| 34 | |||
| 35 | // pulse mode bit definitions |
||
| 36 | // PULSE_MODE_COUNTED |
||
| 37 | // if true, the requested number of pulses are output, then output is turned off |
||
| 38 | // if false, pulses are output continuously |
||
| 39 | #define PULSE_MODE_CONTINUOUS 0x00 |
||
| 40 | #define PULSE_MODE_COUNTED 0x01 |
||
| 41 | |||
| 42 | // functions |
||
| 43 | |||
| 44 | void pulseInit(void) |
||
| 45 | { |
||
| 46 | // initialize timer1 for pulse operation |
||
| 47 | pulseT1Init(); |
||
| 48 | } |
||
| 49 | |||
| 50 | void pulseT1Init(void) |
||
| 51 | { |
||
| 52 | // try to make sure that timer1 is in "normal" mode |
||
| 53 | // most importantly, turn off PWM mode |
||
| 54 | timer1PWMOff(); |
||
| 55 | |||
| 56 | // set some reasonable initial values |
||
| 57 | // in case the user forgets to |
||
| 58 | PulseT1AMode = 0; |
||
| 59 | PulseT1BMode = 0; |
||
| 60 | PulseT1ACount = 0; |
||
| 61 | PulseT1BCount = 0; |
||
| 62 | PulseT1APeriodTics = 0x8000; |
||
| 63 | PulseT1BPeriodTics = 0x8000; |
||
| 64 | |||
| 65 | // attach the pulse service routines to |
||
| 66 | // the timer 1 output compare A and B interrupts |
||
| 67 | timerAttach(TIMER1OUTCOMPAREA_INT,pulseT1AService); |
||
| 68 | timerAttach(TIMER1OUTCOMPAREB_INT,pulseT1BService); |
||
| 69 | } |
||
| 70 | |||
| 71 | void pulseT1Off(void) |
||
| 72 | { |
||
| 73 | // turns pulse outputs off immediately |
||
| 74 | |||
| 75 | // set pulse counters to zero (finished) |
||
| 76 | PulseT1ACount = 0; |
||
| 77 | PulseT1BCount = 0; |
||
| 78 | // disconnect OutputCompare action from OC1A pin |
||
| 79 | cbi(TCCR1A,COM1A1); |
||
| 80 | cbi(TCCR1A,COM1A0); |
||
| 81 | // disconnect OutputCompare action from OC1B pin |
||
| 82 | cbi(TCCR1A,COM1B1); |
||
| 83 | cbi(TCCR1A,COM1B0); |
||
| 84 | // detach the pulse service routines |
||
| 85 | timerDetach(TIMER1OUTCOMPAREA_INT); |
||
| 86 | timerDetach(TIMER1OUTCOMPAREB_INT); |
||
| 87 | } |
||
| 88 | |||
| 89 | void pulseT1ASetFreq(u16 freqHz) |
||
| 90 | { |
||
| 91 | // set the frequency of the pulse output |
||
| 92 | // we need to find the requested period/2 (in timer tics) |
||
| 93 | // from the frequency (in hertz) |
||
| 94 | |||
| 95 | // calculate how many tics in period/2 |
||
| 96 | // this is the (timer tic rate)/(2*requested freq) |
||
| 97 | PulseT1APeriodTics = ((u32)F_CPU/((u32)timer1GetPrescaler()*2*freqHz)); |
||
| 98 | } |
||
| 99 | |||
| 100 | void pulseT1BSetFreq(u16 freqHz) |
||
| 101 | { |
||
| 102 | // set the frequency of the pulse output |
||
| 103 | // we need to find the requested period/2 (in timer tics) |
||
| 104 | // from the frequency (in hertz) |
||
| 105 | |||
| 106 | // calculate how many tics in period/2 |
||
| 107 | // this is the (timer tic rate)/(2*requested freq) |
||
| 108 | PulseT1BPeriodTics = ((u32)F_CPU/((u32)timer1GetPrescaler()*2*freqHz)); |
||
| 109 | } |
||
| 110 | |||
| 111 | void pulseT1ARun(u16 nPulses) |
||
| 112 | { |
||
| 113 | // set the number of pulses we want and the mode |
||
| 114 | if(nPulses) |
||
| 115 | { |
||
| 116 | // if the nPulses is non-zero, use "counted" mode |
||
| 117 | PulseT1AMode |= PULSE_MODE_COUNTED; |
||
| 118 | PulseT1ACount = nPulses<<1; |
||
| 119 | } |
||
| 120 | else |
||
| 121 | { |
||
| 122 | // if nPulses is zero, run forever |
||
| 123 | PulseT1AMode &= ~PULSE_MODE_COUNTED; |
||
| 124 | PulseT1ACount = 1<<1; |
||
| 125 | } |
||
| 126 | // set OutputCompare action to toggle OC1A pin |
||
| 127 | cbi(TCCR1A,COM1A1); |
||
| 128 | sbi(TCCR1A,COM1A0); |
||
| 129 | |||
| 130 | // now the "enabling" stuff |
||
| 131 | |||
| 132 | // set the output compare one pulse cycle ahead of current timer position |
||
| 133 | // to make sure we don't have to wait until the timer overflows and comes |
||
| 134 | // back to the current value |
||
| 135 | // set future output compare time to TCNT1 + PulseT1APeriodTics |
||
| 136 | //outw(OCR1A, inw(TCNT1) + PulseT1APeriodTics); |
||
| 137 | OCR1A += PulseT1APeriodTics; |
||
| 138 | |||
| 139 | // enable OutputCompare interrupt |
||
| 140 | sbi(TIMSK, OCIE1A); |
||
| 141 | } |
||
| 142 | |||
| 143 | void pulseT1BRun(u16 nPulses) |
||
| 144 | { |
||
| 145 | // set the number of pulses we want and the mode |
||
| 146 | if(nPulses) |
||
| 147 | { |
||
| 148 | // if the nPulses is non-zero, use "counted" mode |
||
| 149 | PulseT1BMode |= PULSE_MODE_COUNTED; |
||
| 150 | PulseT1BCount = nPulses<<1; |
||
| 151 | } |
||
| 152 | else |
||
| 153 | { |
||
| 154 | // if nPulses is zero, run forever |
||
| 155 | PulseT1BMode &= ~PULSE_MODE_COUNTED; |
||
| 156 | PulseT1BCount = 1<<1; |
||
| 157 | } |
||
| 158 | // set OutputCompare action to toggle OC1B pin |
||
| 159 | // (note: with all the A's and B's flying around, TCCR1A is not a bug) |
||
| 160 | cbi(TCCR1A,COM1B1); |
||
| 161 | sbi(TCCR1A,COM1B0); |
||
| 162 | |||
| 163 | // now the "enabling" stuff |
||
| 164 | |||
| 165 | // set the output compare one pulse cycle ahead of current timer position |
||
| 166 | // to make sure we don't have to wait until the timer overflows and comes |
||
| 167 | // back to the current value |
||
| 168 | // set future output compare time to TCNT1 + PulseT1APeriodTics |
||
| 169 | //outw(OCR1B, inw(TCNT1) + PulseT1BPeriodTics); |
||
| 170 | OCR1B += PulseT1BPeriodTics; |
||
| 171 | |||
| 172 | // enable OutputCompare interrupt |
||
| 173 | sbi(TIMSK, OCIE1B); |
||
| 174 | } |
||
| 175 | |||
| 176 | void pulseT1AStop(void) |
||
| 177 | { |
||
| 178 | // stop output regardless of remaining pulses or mode |
||
| 179 | // go to "counted" mode |
||
| 180 | PulseT1AMode |= PULSE_MODE_COUNTED; |
||
| 181 | // set pulses to zero |
||
| 182 | PulseT1ACount = 0; |
||
| 183 | } |
||
| 184 | |||
| 185 | void pulseT1BStop(void) |
||
| 186 | { |
||
| 187 | // stop output regardless of remaining pulses or mode |
||
| 188 | // go to "counted" mode |
||
| 189 | PulseT1BMode |= PULSE_MODE_COUNTED; |
||
| 190 | // set pulses to zero |
||
| 191 | PulseT1BCount = 0; |
||
| 192 | } |
||
| 193 | |||
| 194 | u16 pulseT1ARemaining(void) |
||
| 195 | { |
||
| 196 | // return the number of pulses remaining for channel A |
||
| 197 | // add 1 to make sure we round up, >>1 equivalent to /2 |
||
| 198 | return (PulseT1ACount+1)>>1; |
||
| 199 | } |
||
| 200 | |||
| 201 | u16 pulseT1BRemaining(void) |
||
| 202 | { |
||
| 203 | // return the number of pulses remaining for channel A |
||
| 204 | // add 1 to make sure we round up, >>1 equivalent to /2 |
||
| 205 | return (PulseT1BCount+1)>>1; |
||
| 206 | } |
||
| 207 | |||
| 208 | void pulseT1AService(void) |
||
| 209 | { |
||
| 210 | // check if TimerPulseACount is non-zero |
||
| 211 | // (i.e. pulses are still requested) |
||
| 212 | if(PulseT1ACount) |
||
| 213 | { |
||
| 214 | //u16 OCValue; |
||
| 215 | // read in current value of output compare register OCR1A |
||
| 216 | //OCValue = inp(OCR1AL); // read low byte of OCR1A |
||
| 217 | //OCValue += inp(OCR1AH)<<8; // read high byte of OCR1A |
||
| 218 | // increment OCR1A value by PulseT1APeriodTics |
||
| 219 | //OCValue += PulseT1APeriodTics; |
||
| 220 | // set future output compare time to this new value |
||
| 221 | //outp((OCValue>>8), OCR1AH); // write high byte |
||
| 222 | //outp((OCValue & 0x00FF),OCR1AL); // write low byte |
||
| 223 | |||
| 224 | // the following line should be identical in operation |
||
| 225 | // to the lines above, but for the moment, I'm not convinced |
||
| 226 | // this method is bug-free. At least it's simpler! |
||
| 227 | //outw(OCR1A, inw(OCR1A) + PulseT1APeriodTics); |
||
| 228 | // change again |
||
| 229 | OCR1A += PulseT1APeriodTics; |
||
| 230 | |||
| 231 | // decrement the number of pulses executed |
||
| 232 | if(PulseT1AMode & PULSE_MODE_COUNTED) |
||
| 233 | PulseT1ACount--; |
||
| 234 | } |
||
| 235 | else |
||
| 236 | { |
||
| 237 | // pulse count has reached zero |
||
| 238 | // disable the output compare's action on OC1A pin |
||
| 239 | cbi(TCCR1A,COM1A1); |
||
| 240 | cbi(TCCR1A,COM1A0); |
||
| 241 | // and disable the output compare's interrupt to stop pulsing |
||
| 242 | cbi(TIMSK, OCIE1A); |
||
| 243 | } |
||
| 244 | } |
||
| 245 | |||
| 246 | void pulseT1BService(void) |
||
| 247 | { |
||
| 248 | // check if TimerPulseACount is non-zero |
||
| 249 | // (i.e. pulses are still requested) |
||
| 250 | if(PulseT1BCount) |
||
| 251 | { |
||
| 252 | //u16 OCValue; |
||
| 253 | // read in current value of output compare register OCR1B |
||
| 254 | //OCValue = inp(OCR1BL); // read low byte of OCR1B |
||
| 255 | //OCValue += inp(OCR1BH)<<8; // read high byte of OCR1B |
||
| 256 | // increment OCR1B value by PulseT1BPeriodTics |
||
| 257 | //OCValue += PulseT1BPeriodTics; |
||
| 258 | // set future output compare time to this new value |
||
| 259 | //outp((OCValue>>8), OCR1BH); // write high byte |
||
| 260 | //outp((OCValue & 0x00FF),OCR1BL); // write low byte |
||
| 261 | |||
| 262 | // the following line should be identical in operation |
||
| 263 | // to the lines above, but for the moment, I'm not convinced |
||
| 264 | // this method is bug-free. At least it's simpler! |
||
| 265 | //outw(OCR1B, inw(OCR1B) + PulseT1BPeriodTics); |
||
| 266 | // change again |
||
| 267 | OCR1B += PulseT1BPeriodTics; |
||
| 268 | |||
| 269 | |||
| 270 | // decrement the number of pulses executed |
||
| 271 | if(PulseT1BMode & PULSE_MODE_COUNTED) |
||
| 272 | PulseT1BCount--; |
||
| 273 | } |
||
| 274 | else |
||
| 275 | { |
||
| 276 | // pulse count has reached zero |
||
| 277 | // disable the output compare's action on OC1B pin |
||
| 278 | cbi(TCCR1A,COM1B1); |
||
| 279 | cbi(TCCR1A,COM1B0); |
||
| 280 | // and disable the output compare's interrupt to stop pulsing |
||
| 281 | cbi(TIMSK, OCIE1B); |
||
| 282 | } |
||
| 283 | } |
Powered by WebSVN v2.8.3