timer.c

Go to the documentation of this file.
00001 /* This file has been prepared for Doxygen automatic documentation generation.*/
00025 //#include "iom406_320.h"
00026 #include <iom406.h>     // IAR headerfile for Mega406 (EW 410)
00027 
00028 #define MODULE_TIMER
00029 #include "timer.h"
00030 
00031 #include "main.h"       //for action_flags
00032 #include "smbus.h"
00033 #include "inavr.h"
00034 #include "pwrmgmt.h"    //for sleep mode definitions
00035 #include "analog.h"     //for access to RunningAcc
00036 #include "pack.h"
00037 
00038 
00039 /* *****************************************************
00040  *
00041  * Timer Usage:
00042  *
00043  * T0: serves several functions...
00044  *     1. basic tick rate for generic timers
00045  *     2. T0CMPA is optional LED PWM function
00046  *     3. T0CMPB is Charge FET PWM
00047  *   The clock src for T0 is main clk, 1MHz.
00048  *   Therefore, base period is 1MHz/256 = 3.9KHz = 256uS
00049  *   if prescaler = 1.
00050  *   For normal operation, we need both the LEDs on CMPA
00051  *   and the overflow as a timer tick. We will therefore
00052  *   use prescale = 8. This yields a 2.048mS tick, and
00053  *   a 100Hz update rate across all 5 LEDs.  The PWM for
00054  *   the FETs is available in this design, although it is
00055  *   not used.
00056  *
00057  * T1: not used in this design.
00058  *
00059  *
00060  * *****************************************************/
00061 
00062 void T0init(void)
00063 {
00064   DDRB |= (1<<6);       //set up PB6 output as OC0A
00065   TCCR0A = (1<<COM0A1) | (0<<COM0A0) | (1<<WGM01) | (1<<WGM00);
00066   TCCR0B = 2;           //prescale = 8
00067   OCR0A = 192;          //use 75% brightness level so we can see the waveform for testing
00068   OCR0B = 0;            //available for PWM use by FETs
00069 
00070   TIFR0 = 7;            //force all timer interrupt flags to be cleared.
00071   TIMSK0 = (1<<OCIE0A) | (1<<TOIE0);            //enable interrupts as needed.
00072 }
00073 
00074 
00075 void SetLEDbrightness(unsigned char value)
00076 {
00077   //Don't let the LED brightness go higher than 250, just so that
00078   // we don't collide with the overflow interrupt.
00079   if(value <= 250)
00080     OCR0A = value;
00081   else
00082     OCR0A = 250;
00083 }
00084 
00085 void SetLEDs(unsigned char LEDflags)
00086 {
00087   LEDs = LEDflags;
00088 
00089   //Each time the user updates the LED settings,
00090   // refresh the directional state of the I/O pins.
00091   DDRB |= (1<<4) | (1<<5) | (1<<7);
00092   DDRD |= (1<<0) | (1<<1);
00093 
00094 }
00095 
00096 
00097 
00098 // This ISR rotates between the five LEDs in this design, assuming the user jumpered
00099 // the option on the SB100 PCB properly. The PWM function is used along with tripping
00100 // this interrupt.  Active High output on the PWM pin is what drives the LEDs.  We rotate
00101 // the LED outputs when the match occurs, which turns OFF the output at the same time;
00102 // thus, we switch while the LEDs are off. (unless the user asserts maximum brightness,
00103 // in which case there is no OFF time.
00104 
00108 
00109 //extern unsigned char LEDflags;
00110 
00111 #pragma vector = TIMER0_COMPA_vect
00112 __interrupt void T0CMPA_ISR(void)
00113 {
00114   static unsigned char select = 0;
00115   unsigned char temp = select;
00116 
00117   if(PINA & (1<<7))    //PA7 high?
00118   {
00119     DDRB &= ~(1<<6);  //shut off the DRIVE to the LEDs
00120     PORTB &= ~(1<<6);
00121     return;
00122   }
00123   else
00124     DDRB |= (1<<6);   //enable PB6 output drive
00125 
00126   temp++;
00127   if(6 == temp)
00128     temp = 1;
00129   select = temp;
00130 
00131   //First set ALL led ports High.
00132   PORTB |= (1<<4) | (1<<5) | (1<<7);
00133   PORTD |= (1<<0) | (1<<1);
00134 
00135   //Next, only set ONE low, based on the SELECT value and the LED bit.
00136   if((temp == 1) && (LEDs & (1<<0)))
00137       PORTB &= ~(1<<4);
00138   else
00139   if((temp == 2) && (LEDs & (1<<1)))
00140       PORTB &= ~(1<<5);
00141   else
00142   if((temp == 3) && (LEDs & (1<<2)))
00143       PORTB &= ~(1<<7);
00144   else
00145   if((temp == 4) && (LEDs & (1<<3)))
00146       PORTD &= ~(1<<0);
00147   else
00148   if((temp == 5) && (LEDs & (1<<4)))
00149       PORTD &= ~(1<<1);
00150 
00151   return;
00152 }
00153 
00154 
00155 //Since this drives the Charge and Precharge FET PWM in this design, there is no need
00156 // to use this interrupt.  Its interrupt is not normally enabled, but this code shell
00157 // is here just in case...
00158 #pragma vector = TIMER0_COMPB_vect
00159 __interrupt void T0_COMPB_ISR(void)
00160 {
00161   return;       
00162 }
00163 
00164 
00165 
00166 
00167 //NOTE:  all of these fire from within the ISR, so keep them short!!
00168 
00169 void generictimer0expired(void)
00170 {
00171   SMB_RestoreBus();
00172   return;
00173 }
00174 
00175 void generictimer1expired(void)
00176 {
00177   SetQtrSec;
00178   return;
00179 }
00180 
00181 void generictimer2expired(void)
00182 {
00183                 //open for your use
00184   return;
00185 }
00186 
00187 void generictimer3expired(void)
00188 {
00189                 //open for your use
00190   return;
00191 }
00192 
00193 void generictimer4expired(void)
00194 {
00195                 //open for your use
00196   return;
00197 }
00198 
00199 void generictimer5expired(void)
00200 {
00201                 //open for your use
00202   return;
00203 }
00204 
00205 void generictimer6expired(void)
00206 {
00207                 //open for your use
00208   return;
00209 }
00210 
00211 void generictimer7expired(void)
00212 {
00213                 //open for your use
00214   return;
00215 }
00216 
00217 
00218 
00219 
00220 //Delay is given in 1mS intervals, but timed in 2mS intervals.
00221 void SetGenericTimer(unsigned char index, unsigned int delay)
00222 {
00223   ++delay;
00224   delay >>= 1;  //convert from 1mS interval to 2mS resolution
00225   generictimer[index] = (unsigned char) delay;
00226 }
00227 
00228 unsigned char GetGenericTimer(unsigned char index)
00229 {
00230   return generictimer[index];
00231 }
00232 
00233 
00234 typedef void (*ptr2funcV_V)(void);
00235 
00236 //Table of pointers to functions, indexed from the received SMBus Command byte.
00237 ptr2funcV_V GenericExpire[8] =
00238 {
00239   generictimer0expired,
00240   generictimer1expired,
00241   generictimer2expired,
00242   generictimer3expired,
00243   generictimer4expired,
00244   generictimer5expired,
00245   generictimer6expired,
00246   generictimer7expired
00247 };
00248 
00249 
00250 
00251 //This interrupt functions as the main timer tick for the code.  Each time, a list
00252 // of generic timers is decremented.  Whenever one reaches zero, its expiration function
00253 // is called.  As the prescaler for T0 is initialized to 8, this fires every 2.048mS.
00254 #pragma vector = TIMER0_OVF_vect
00255 __interrupt void T0OVF_ISR(void)
00256 {
00257   unsigned int temp;
00258   unsigned char i;
00259 
00260   for(i=0; i<8; i++)
00261   {
00262     temp = generictimer[i];
00263     if(0 != temp)
00264     {
00265       temp--;
00266       generictimer[i] = temp;
00267       if(temp == 0)     //when it hits 0, flag it!
00268         (GenericExpire[i])();
00269     }
00270   }
00271 
00272   return;
00273 }
00274 
00275 
00276 
00277 
00278 
00279 
00280 
00281 
00282 
00283 
00284 
00285 //Timer 1 is not used in this design.
00286 
00287 void T1init(void)
00288 {
00289   return;
00290 }
00291 
00292 #pragma vector = TIMER1_COMP_vect
00293 __interrupt void T1CMP_ISR(void)
00294 {
00295   return;
00296 }
00297 
00298 #pragma vector = TIMER1_OVF_vect
00299 __interrupt void T1OVF_ISR(void)
00300 {
00301   return;
00302 }
00303 
00304 
00305 
00306 
00307 
00308 
00309 /* *****************************************************
00310  *
00311  *
00312  *
00313  *
00314  * *****************************************************/
00315 
00316 
00317 
00318 void Wdog_init(unsigned char mode, unsigned char rate)
00319 {
00320   unsigned char temp;
00321   unsigned char flags;
00322 
00323   if(mode == WDOG_MODE_DISABLED)
00324   {
00325     MCUSR &= ~(1<<WDRF);
00326     flags = SREG;
00327     __disable_interrupt();
00328     __watchdog_reset();
00329     WDTCSR = (1<<WDCE);
00330     WDTCSR = 0;
00331     if(flags & (1<<7))          //Were interrupts enabled before?
00332       __enable_interrupt();     // Then re-enable them.
00333     return;
00334   }
00335 
00336   // Clear all other bits from WDT tining setting.
00337   temp  = rate & ( (1 << WDP2) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0) );
00338 
00339 
00340 
00341   if(mode & WDOG_MODE_INTERRUPT)
00342   {
00343     temp |= 1<<WDIE;
00344   }
00345 
00346 //  if(mode & WDOG_MODE_RESET)  //no special code required for this mode...
00347 //  {
00348 //    ;
00349 //  }
00350 
00351   temp |= (1<<WDIF) | (1<<WDE); //always try to clear the Int flag.
00352 
00353 
00354   flags = SREG;
00355     __disable_interrupt();
00356     __watchdog_reset();
00357   WDTCSR |= (1<<WDCE) | (1<<WDE);
00358   WDTCSR = temp;
00359   if(flags & (1<<7))            //Were interrupts enabled before?
00360       __enable_interrupt();     // Then re-enable them.
00361 }
00362 
00363 
00364 
00365 #pragma vector = WDT_vect
00366 __interrupt void WDT_ISR(void)
00367 {
00368   return;       
00369 }
00370 
00371 
00372 
00373 /* *****************************************************
00374  *
00375  * Set up and start the Wakeup timer, pushing into Sleep
00376  * mode as well.  If it's already running, this will not
00377  * reset the timer, allowing it to continue at the rate
00378  * previously defined.
00379  *
00380  * To prevent 4-second delays if you change the wakeup
00381  * interval after this is already running, a local static
00382  * copy of the current setting is kept and compared.
00383  * Whenever the rate is changed, the counter will be
00384  * forcibly reset.
00385  *
00386  * Return: 0 if OK, 1 if bad delay value or sleep mode requested.
00387  *
00388  * *****************************************************/
00389 char setWakeup(unsigned char delay, unsigned char sleepmode)
00390 {
00391   static unsigned char LastDelay = 0;
00392   unsigned char temp;
00393 
00394   if(delay > WU4sec)
00395     return 1;
00396 
00397   if(WUoff == delay)
00398   {
00399     WUTCSR = (WUTIF | WUTR);
00400     LastDelay = delay;
00401     return 0;
00402   }
00403   else
00404   if(LastDelay != delay)
00405     WUTCSR = ((delay-1) | WUTE | WUTIE | WUTR);
00406   else
00407     WUTCSR = ((delay-1) | WUTE | WUTIE);
00408   LastDelay = delay;
00409 
00410   //Assert sleep mode here, but only if it was requested.
00411   if(SLEEP_NONE == sleepmode)
00412     return 0;
00413   if(SLEEP_POWEROFF < sleepmode)
00414     return 1;
00415   temp = sleepmode & ~(1<<SE);
00416   SMCR = sleepmode | (1<<SE);
00417   __sleep();
00418 
00419   //After waking up, the datasheet indicates you should clear the SE bit.
00420   SMCR = temp;
00421   return 0;
00422 }
00423 
00424 
00425 
00426 
00427 #pragma vector = WAKE_UP_vect
00428 __interrupt void WakeUp_ISR(void)
00429 {
00430   RunningAcc -= PACK_HIBERNATEAMOUNT;
00431   return;
00432 }
00433 

Generated on Mon Nov 12 15:59:58 2007 for AVR453 Smart Battery Reference Design by  doxygen 1.5.3