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

# timer.c

Go to the documentation of this file.

    00001 /*! \file timer.c \brief System Timer function library. */
    00002 //*****************************************************************************
    00003 //
    00004 // File Name    : 'timer.c'
    00005 // Title        : System Timer function library
    00006 // Author       : Pascal Stang - Copyright (C) 2000-2002
    00007 // Created      : 11/22/2000
    00008 // Revised      : 07/09/2003
    00009 // Version      : 1.1
    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 #include <avr/sleep.h>
    00022
    00023 #include "global.h"
    00024 #include "timer.h"
    00025
    00026 #include "rprintf.h"
    00027
    00028 // Program ROM constants
    00029 // the prescale division values stored in order of timer control register index
    00030 // STOP, CLK, CLK/8, CLK/64, CLK/256, CLK/1024
    00031 unsigned short __attribute__ ((progmem)) TimerPrescaleFactor[] = {0,1,8,64,256,1024};
    00032 // the prescale division values stored in order of timer control register index
    00033 // STOP, CLK, CLK/8, CLK/32, CLK/64, CLK/128, CLK/256, CLK/1024
    00034 unsigned short __attribute__ ((progmem)) TimerRTCPrescaleFactor[] = {0,1,8,32,64,128,256,1024};
    00035
    00036 // Global variables
    00037 // time registers
    00038 volatile unsigned long TimerPauseReg;
    00039 volatile unsigned long Timer0Reg0;
    00040 volatile unsigned long Timer2Reg0;
    00041
    00042 typedef void (*voidFuncPtr)(void);
    00043 volatile static voidFuncPtr TimerIntFunc[TIMER_NUM_INTERRUPTS];
    00044
    00045 // delay for a minimum of <us> microseconds
    00046 // the time resolution is dependent on the time the loop takes
    00047 // e.g. with 4Mhz and 5 cycles per loop, the resolution is 1.25 us
    00048 void delay_us(unsigned short time_us)
    00049 {
    00050     unsigned short delay_loops;
    00051     register unsigned short i;
    00052
    00053     delay_loops = (time_us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty)
    00054
    00055     // one loop takes 5 cpu cycles
    00056     for (i=0; i < delay_loops; i++) {};
    00057 }
    00058 /*
    00059 void delay_ms(unsigned char time_ms)
    00060 {
    00061     unsigned short delay_count = F_CPU / 4000;
    00062
    00063     unsigned short cnt;
    00064     asm volatile ("\n"
    00065                   "L_dl1%=:\n\t"
    00066                   "mov %A0, %A2\n\t"
    00067                   "mov %B0, %B2\n"
    00068                   "L_dl2%=:\n\t"
    00069                   "sbiw %A0, 1\n\t"
    00070                   "brne L_dl2%=\n\t"
    00071                   "dec %1\n\t" "brne L_dl1%=\n\t":"=&w" (cnt)
    00072                   :"r"(time_ms), "r"((unsigned short) (delay_count))
    00073     );
    00074 }
    00075 */
    00076 void timerInit(void)
    00077 {
    00078     u08 intNum;
    00079     // detach all user functions from interrupts
    00080     for(intNum=0; intNum<TIMER_NUM_INTERRUPTS; intNum++)
    00081         timerDetach(intNum);
    00082
    00083     // initialize all timers
    00084     timer0Init();
    00085     timer1Init();
    00086     #ifdef TCNT2    // support timer2 only if it exists
    00087     timer2Init();
    00088     #endif
    00089     // enable interrupts
    00090     sei();
    00091 }
    00092
    00093 void timer0Init()
    00094 {
    00095     // initialize timer 0
    00096     timer0SetPrescaler( TIMER0PRESCALE );   // set prescaler
    00097     outb(TCNT0, 0);                         // reset TCNT0
    00098     sbi(TIMSK, TOIE0);                      // enable TCNT0 overflow interrupt
    00099
    00100     timer0ClearOverflowCount();             // initialize time registers
    00101 }
    00102
    00103 void timer1Init(void)
    00104 {
    00105     // initialize timer 1
    00106     timer1SetPrescaler( TIMER1PRESCALE );   // set prescaler
    00107     outb(TCNT1H, 0);                        // reset TCNT1
    00108     outb(TCNT1L, 0);
    00109     sbi(TIMSK, TOIE1);                      // enable TCNT1 overflow
    00110 }
    00111
    00112 #ifdef TCNT2    // support timer2 only if it exists
    00113 void timer2Init(void)
    00114 {
    00115     // initialize timer 2
    00116     timer2SetPrescaler( TIMER2PRESCALE );   // set prescaler
    00117     outb(TCNT2, 0);                         // reset TCNT2
    00118     sbi(TIMSK, TOIE2);                      // enable TCNT2 overflow
    00119
    00120     timer2ClearOverflowCount();             // initialize time registers
    00121 }
    00122 #endif
    00123
    00124 void timer0SetPrescaler(u08 prescale)
    00125 {
    00126     // set prescaler on timer 0
    00127     outb(TCCR0, (inb(TCCR0) & ~TIMER_PRESCALE_MASK) | prescale);
    00128 }
    00129
    00130 void timer1SetPrescaler(u08 prescale)
    00131 {
    00132     // set prescaler on timer 1
    00133     outb(TCCR1B, (inb(TCCR1B) & ~TIMER_PRESCALE_MASK) | prescale);
    00134 }
    00135
    00136 #ifdef TCNT2    // support timer2 only if it exists
    00137 void timer2SetPrescaler(u08 prescale)
    00138 {
    00139     // set prescaler on timer 2
    00140     outb(TCCR2, (inb(TCCR2) & ~TIMER_PRESCALE_MASK) | prescale);
    00141 }
    00142 #endif
    00143
    00144 u16 timer0GetPrescaler(void)
    00145 {
    00146     // get the current prescaler setting
    00147     return (pgm_read_word(TimerPrescaleFactor+(inb(TCCR0) & TIMER_PRESCALE_MASK)));
    00148 }
    00149
    00150 u16 timer1GetPrescaler(void)
    00151 {
    00152     // get the current prescaler setting
    00153     return (pgm_read_word(TimerPrescaleFactor+(inb(TCCR1B) & TIMER_PRESCALE_MASK)));
    00154 }
    00155
    00156 #ifdef TCNT2    // support timer2 only if it exists
    00157 u16 timer2GetPrescaler(void)
    00158 {
    00159     //TODO: can we assume for all 3-timer AVR processors,
    00160     // that timer2 is the RTC timer?
    00161
    00162     // get the current prescaler setting
    00163     return (pgm_read_word(TimerRTCPrescaleFactor+(inb(TCCR2) & TIMER_PRESCALE_MASK)));
    00164 }
    00165 #endif
    00166
    00167 void timerAttach(u08 interruptNum, void (*userFunc)(void) )
    00168 {
    00169     // make sure the interrupt number is within bounds
    00170     if(interruptNum < TIMER_NUM_INTERRUPTS)
    00171     {
    00172         // set the interrupt function to run
    00173         // the supplied user's function
    00174         TimerIntFunc[interruptNum] = userFunc;
    00175     }
    00176 }
    00177
    00178 void timerDetach(u08 interruptNum)
    00179 {
    00180     // make sure the interrupt number is within bounds
    00181     if(interruptNum < TIMER_NUM_INTERRUPTS)
    00182     {
    00183         // set the interrupt function to run nothing
    00184         TimerIntFunc[interruptNum] = 0;
    00185     }
    00186 }
    00187 /*
    00188 u32 timerMsToTics(u16 ms)
    00189 {
    00190     // calculate the prescaler division rate
    00191     u16 prescaleDiv = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0)));
    00192     // calculate the number of timer tics in x milliseconds
    00193     return (ms*(F_CPU/(prescaleDiv*256)))/1000;
    00194 }
    00195
    00196 u16 timerTicsToMs(u32 tics)
    00197 {
    00198     // calculate the prescaler division rate
    00199     u16 prescaleDiv = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0)));
    00200     // calculate the number of milliseconds in x timer tics
    00201     return (tics*1000*(prescaleDiv*256))/F_CPU;
    00202 }
    00203 */
    00204 void timerPause(unsigned short pause_ms)
    00205 {
    00206     // pauses for exactly <pause_ms> number of milliseconds
    00207     u08 timerThres;
    00208     u32 ticRateHz;
    00209     u32 pause;
    00210
    00211     // capture current pause timer value
    00212     timerThres = inb(TCNT0);
    00213     // reset pause timer overflow count
    00214     TimerPauseReg = 0;
    00215     // calculate delay for [pause_ms] milliseconds
    00216     // prescaler division = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0)))
    00217     ticRateHz = F_CPU/timer0GetPrescaler();
    00218     // precision management
    00219     // prevent overflow and precision underflow
    00220     //  -could add more conditions to improve accuracy
    00221     if( ((ticRateHz < 429497) && (pause_ms <= 10000)) )
    00222         pause = (pause_ms*ticRateHz)/1000;
    00223     else
    00224         pause = pause_ms*(ticRateHz/1000);
    00225
    00226     // loop until time expires
    00227     while( ((TimerPauseReg<<8) | inb(TCNT0)) < (pause+timerThres) )
    00228     {
    00229         if( TimerPauseReg < (pause>>8));
    00230         {
    00231             // save power by idling the processor
    00232             set_sleep_mode(SLEEP_MODE_IDLE);
    00233             sleep_mode();
    00234         }
    00235     }
    00236
    00237     /* old inaccurate code, for reference
    00238
    00239     // calculate delay for [pause_ms] milliseconds
    00240     u16 prescaleDiv = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0)));
    00241     u32 pause = (pause_ms*(F_CPU/(prescaleDiv*256)))/1000;
    00242
    00243     TimerPauseReg = 0;
    00244     while(TimerPauseReg < pause);
    00245
    00246     */
    00247 }
    00248
    00249 void timer0ClearOverflowCount(void)
    00250 {
    00251     // clear the timer overflow counter registers
    00252     Timer0Reg0 = 0; // initialize time registers
    00253 }
    00254
    00255 long timer0GetOverflowCount(void)
    00256 {
    00257     // return the current timer overflow count
    00258     // (this is since the last timer0ClearOverflowCount() command was called)
    00259     return Timer0Reg0;
    00260 }
    00261
    00262 #ifdef TCNT2    // support timer2 only if it exists
    00263 void timer2ClearOverflowCount(void)
    00264 {
    00265     // clear the timer overflow counter registers
    00266     Timer2Reg0 = 0; // initialize time registers
    00267 }
    00268
    00269 long timer2GetOverflowCount(void)
    00270 {
    00271     // return the current timer overflow count
    00272     // (this is since the last timer2ClearOverflowCount() command was called)
    00273     return Timer2Reg0;
    00274 }
    00275 #endif
    00276
    00277 void timer1PWMInit(u08 bitRes)
    00278 {
    00279     // configures timer1 for use with PWM output
    00280     // on OC1A and OC1B pins
    00281
    00282     // enable timer1 as 8,9,10bit PWM
    00283     if(bitRes == 9)
    00284     {   // 9bit mode
    00285         sbi(TCCR1A,PWM11);
    00286         cbi(TCCR1A,PWM10);
    00287     }
    00288     else if( bitRes == 10 )
    00289     {   // 10bit mode
    00290         sbi(TCCR1A,PWM11);
    00291         sbi(TCCR1A,PWM10);
    00292     }
    00293     else
    00294     {   // default 8bit mode
    00295         cbi(TCCR1A,PWM11);
    00296         sbi(TCCR1A,PWM10);
    00297     }
    00298
    00299     // clear output compare value A
    00300     outb(OCR1AH, 0);
    00301     outb(OCR1AL, 0);
    00302     // clear output compare value B
    00303     outb(OCR1BH, 0);
    00304     outb(OCR1BL, 0);
    00305 }
    00306
    00307 #ifdef WGM10
    00308 // include support for arbitrary top-count PWM
    00309 // on new AVR processors that support it
    00310 void timer1PWMInitICR(u16 topcount)
    00311 {
    00312     // set PWM mode with ICR top-count
    00313     cbi(TCCR1A,WGM10);
    00314     sbi(TCCR1A,WGM11);
    00315     sbi(TCCR1B,WGM12);
    00316     sbi(TCCR1B,WGM13);
    00317
    00318     // set top count value
    00319     ICR1 = topcount;
    00320
    00321     // clear output compare value A
    00322     OCR1A = 0;
    00323     // clear output compare value B
    00324     OCR1B = 0;
    00325
    00326 }
    00327 #endif
    00328
    00329 void timer1PWMOff(void)
    00330 {
    00331     // turn off timer1 PWM mode
    00332     cbi(TCCR1A,PWM11);
    00333     cbi(TCCR1A,PWM10);
    00334     // set PWM1A/B (OutputCompare action) to none
    00335     timer1PWMAOff();
    00336     timer1PWMBOff();
    00337 }
    00338
    00339 void timer1PWMAOn(void)
    00340 {
    00341     // turn on channel A (OC1A) PWM output
    00342     // set OC1A as non-inverted PWM
    00343     sbi(TCCR1A,COM1A1);
    00344     cbi(TCCR1A,COM1A0);
    00345 }
    00346
    00347 void timer1PWMBOn(void)
    00348 {
    00349     // turn on channel B (OC1B) PWM output
    00350     // set OC1B as non-inverted PWM
    00351     sbi(TCCR1A,COM1B1);
    00352     cbi(TCCR1A,COM1B0);
    00353 }
    00354
    00355 void timer1PWMAOff(void)
    00356 {
    00357     // turn off channel A (OC1A) PWM output
    00358     // set OC1A (OutputCompare action) to none
    00359     cbi(TCCR1A,COM1A1);
    00360     cbi(TCCR1A,COM1A0);
    00361 }
    00362
    00363 void timer1PWMBOff(void)
    00364 {
    00365     // turn off channel B (OC1B) PWM output
    00366     // set OC1B (OutputCompare action) to none
    00367     cbi(TCCR1A,COM1B1);
    00368     cbi(TCCR1A,COM1B0);
    00369 }
    00370
    00371 void timer1PWMASet(u16 pwmDuty)
    00372 {
    00373     // set PWM (output compare) duty for channel A
    00374     // this PWM output is generated on OC1A pin
    00375     // NOTE:    pwmDuty should be in the range 0-255 for 8bit PWM
    00376     //          pwmDuty should be in the range 0-511 for 9bit PWM
    00377     //          pwmDuty should be in the range 0-1023 for 10bit PWM
    00378     //outp( (pwmDuty>>8), OCR1AH);      // set the high 8bits of OCR1A
    00379     //outp( (pwmDuty&0x00FF), OCR1AL);  // set the low 8bits of OCR1A
    00380     OCR1A = pwmDuty;
    00381 }
    00382
    00383 void timer1PWMBSet(u16 pwmDuty)
    00384 {
    00385     // set PWM (output compare) duty for channel B
    00386     // this PWM output is generated on OC1B pin
    00387     // NOTE:    pwmDuty should be in the range 0-255 for 8bit PWM
    00388     //          pwmDuty should be in the range 0-511 for 9bit PWM
    00389     //          pwmDuty should be in the range 0-1023 for 10bit PWM
    00390     //outp( (pwmDuty>>8), OCR1BH);      // set the high 8bits of OCR1B
    00391     //outp( (pwmDuty&0x00FF), OCR1BL);  // set the low 8bits of OCR1B
    00392     OCR1B = pwmDuty;
    00393 }
    00394
    00395 //! Interrupt handler for tcnt0 overflow interrupt
    00396 TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW0)
    00397 {
    00398     Timer0Reg0++;           // increment low-order counter
    00399
    00400     // increment pause counter
    00401     TimerPauseReg++;
    00402
    00403     // if a user function is defined, execute it too
    00404     if(TimerIntFunc[TIMER0OVERFLOW_INT])
    00405         TimerIntFunc[TIMER0OVERFLOW_INT]();
    00406 }
    00407
    00408 //! Interrupt handler for tcnt1 overflow interrupt
    00409 TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW1)
    00410 {
    00411     // if a user function is defined, execute it
    00412     if(TimerIntFunc[TIMER1OVERFLOW_INT])
    00413         TimerIntFunc[TIMER1OVERFLOW_INT]();
    00414 }
    00415
    00416 #ifdef TCNT2    // support timer2 only if it exists
    00417 //! Interrupt handler for tcnt2 overflow interrupt
    00418 TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW2)
    00419 {
    00420     Timer2Reg0++;           // increment low-order counter
    00421
    00422     // if a user function is defined, execute it
    00423     if(TimerIntFunc[TIMER2OVERFLOW_INT])
    00424         TimerIntFunc[TIMER2OVERFLOW_INT]();
    00425 }
    00426 #endif
    00427
    00428 #ifdef OCR0
    00429 // include support for Output Compare 0 for new AVR processors that support it
    00430 //! Interrupt handler for OutputCompare0 match (OC0) interrupt
    00431 TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE0)
    00432 {
    00433     // if a user function is defined, execute it
    00434     if(TimerIntFunc[TIMER0OUTCOMPARE_INT])
    00435         TimerIntFunc[TIMER0OUTCOMPARE_INT]();
    00436 }
    00437 #endif
    00438
    00439 //! Interrupt handler for CutputCompare1A match (OC1A) interrupt
    00440 TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE1A)
    00441 {
    00442     // if a user function is defined, execute it
    00443     if(TimerIntFunc[TIMER1OUTCOMPAREA_INT])
    00444         TimerIntFunc[TIMER1OUTCOMPAREA_INT]();
    00445 }
    00446
    00447 //! Interrupt handler for OutputCompare1B match (OC1B) interrupt
    00448 TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE1B)
    00449 {
    00450     // if a user function is defined, execute it
    00451     if(TimerIntFunc[TIMER1OUTCOMPAREB_INT])
    00452         TimerIntFunc[TIMER1OUTCOMPAREB_INT]();
    00453 }
    00454
    00455 //! Interrupt handler for InputCapture1 (IC1) interrupt
    00456 TIMER_INTERRUPT_HANDLER(SIG_INPUT_CAPTURE1)
    00457 {
    00458     // if a user function is defined, execute it
    00459     if(TimerIntFunc[TIMER1INPUTCAPTURE_INT])
    00460         TimerIntFunc[TIMER1INPUTCAPTURE_INT]();
    00461 }
    00462
    00463 //! Interrupt handler for OutputCompare2 match (OC2) interrupt
    00464 TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE2)
    00465 {
    00466     // if a user function is defined, execute it
    00467     if(TimerIntFunc[TIMER2OUTCOMPARE_INT])
    00468         TimerIntFunc[TIMER2OUTCOMPARE_INT]();
    00469 }