MHVLib  20111011
An efficiency oriented runtime library for AVR microcontrollers
A:/eclipse/mhvlib/MHV_Timer8.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011, Make, Hack, Void Inc
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *  * Redistributions of source code must retain the above copyright
00008  *    notice, this list of conditions and the following disclaimer.
00009  *  * Redistributions in binary form must reproduce the above copyright
00010  *    notice, this list of conditions and the following disclaimer in the
00011  *    documentation and/or other materials provided with the distribution.
00012  *  * Neither the name of the Make, Hack, Void nor the
00013  *    names of its contributors may be used to endorse or promote products
00014  *    derived from this software without specific prior written permission.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019  * DISCLAIMED. IN NO EVENT SHALL MAKE, HACK, VOID BE LIABLE FOR ANY
00020  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 
00028 #include "MHV_Timer8.h"
00029 #include "MHV_io.h"
00030 #include <avr/io.h>
00031 #include <avr/interrupt.h>
00032 
00033 /* Create a new timer
00034  * @param: time the time in microseconds
00035  */
00036 MHV_Timer8::MHV_Timer8(MHV_TIMER_TYPE type, volatile uint8_t *controlRegA, volatile uint8_t *controlRegB,
00037                 volatile uint8_t *overflowReg1, volatile uint8_t *overflowReg2, volatile uint8_t *counter,
00038                 volatile uint8_t *interrupt, uint8_t interruptEnableA) {
00039         _controlRegA = controlRegA;
00040         _controlRegB = controlRegB;
00041         _outputCompare1 = overflowReg1;
00042         _outputCompare2 = overflowReg2;
00043         _counter = counter;
00044         _interrupt = interrupt;
00045         _interruptEnableA = interruptEnableA;
00046         _mode = MHV_TIMER_REPETITIVE;
00047         _type = type;
00048         _counterSize = 8;
00049         _prescaler = MHV_TIMER_PRESCALER_DISABLED;
00050 
00051         _haveTime2 = false;
00052         _triggerData1 = NULL;
00053         _triggerData2 = NULL;
00054         _triggerFunction1 = NULL;
00055         _triggerFunction2 = NULL;
00056 }
00057 
00058 MHV_Timer8::MHV_Timer8() {};
00059 
00060 uint8_t MHV_Timer8::current(void) {
00061         uint8_t ret;
00062         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00063                 ret = *_counter;
00064         }
00065         return ret;
00066 }
00067 
00068 
00069 /* Set the prescaler
00070  * @param       time            the time in timer ticks
00071  * @param       prescaler       the prescaler to set
00072  * @param       factor          the prescale factor
00073  * return 0 on success
00074  */
00075 uint8_t MHV_Timer8::calculatePrescaler(uint32_t time, MHV_TIMER_PRESCALER *prescaler, uint16_t *factor) {
00076         uint32_t limit = 0;
00077         if (8 == _counterSize) {
00078                 limit = 256L;
00079         } else if (16 == _counterSize) {
00080                 limit = 65536L;
00081         }
00082 
00083         switch (_type) {
00084         case MHV_TIMER_TYPE_5_PRESCALERS:
00085                 if (time <= limit) {
00086                         *prescaler = MHV_TIMER_PRESCALER_5_1;
00087                         *factor = 1;
00088                 } else if (time <= limit * 8) {
00089                         *prescaler = MHV_TIMER_PRESCALER_5_8;
00090                         *factor = 8;
00091                 } else if (time <= limit * 64) {
00092                         *prescaler = MHV_TIMER_PRESCALER_5_64;
00093                         *factor = 64;
00094                 } else if (time <= limit * 256) {
00095                         *prescaler = MHV_TIMER_PRESCALER_5_256;
00096                         *factor = 256;
00097                 } else if (time <= limit * 1024) {
00098                         *prescaler = MHV_TIMER_PRESCALER_5_1024;
00099                         *factor = 1024;
00100                 } else {
00101                         return 1;
00102                 }
00103                 break;
00104 
00105         case MHV_TIMER_TYPE_7_PRESCALERS:
00106                 if (time <= limit) {
00107                         *prescaler = MHV_TIMER_PRESCALER_7_1;
00108                         *factor = 1;
00109                 } else if (time <= limit * 8) {
00110                         *prescaler = MHV_TIMER_PRESCALER_7_8;
00111                         *factor = 8;
00112                 } else if (time <= limit * 32) {
00113                         *prescaler = MHV_TIMER_PRESCALER_7_32;
00114                         *factor = 32;
00115                 } else if (time <= limit * 64) {
00116                         *prescaler = MHV_TIMER_PRESCALER_7_64;
00117                         *factor = 64;
00118                 } else if (time <= limit * 128) {
00119                         *prescaler = MHV_TIMER_PRESCALER_7_128;
00120                         *factor = 128;
00121                 } else if (time <= limit * 256) {
00122                         *prescaler = MHV_TIMER_PRESCALER_7_256;
00123                         *factor = 256;
00124                 } else if (time <= limit * 1024) {
00125                         *prescaler = MHV_TIMER_PRESCALER_7_1024;
00126                         *factor = 1024;
00127                 } else {
00128                         return 1;
00129                 }
00130                 break;
00131         }
00132 
00133         return 0;
00134 }
00135 
00136 /* Calculate the top register
00137  * @param       time            input: the time in timer ticks, output: the scaled timer ticks
00138  * @param       factor          the prescaler factor
00139  */
00140 void MHV_Timer8::calculateTop(uint32_t *time, uint16_t factor) {
00141         *time = *time / factor - 1;
00142         return;
00143 }
00144 
00145 /* Set the periods for channels 1 and 2
00146  * Times are in microseconds
00147  * @param       usec1   the period for channel 1
00148  * @param       usec2   the period for channel 2
00149  * @return false on success
00150  */
00151 bool MHV_Timer8::setPeriods(uint32_t usec1, uint32_t usec2) {
00152         MHV_TIMER_PRESCALER prescaler;
00153         uint16_t factor;
00154         uint32_t maxTime;
00155 
00156         usec1 *= F_CPU / (1000000 * 2); // time is now in timer ticks
00157         usec2 *= F_CPU / (1000000 * 2); // time is now in timer ticks
00158 
00159         if (usec1 > usec2) {
00160                 maxTime = usec1;
00161         } else {
00162                 maxTime = usec2;
00163         }
00164 
00165         if (calculatePrescaler(maxTime, &prescaler, &factor)) {
00166                 return true;
00167         }
00168         calculateTop(&usec1, factor);
00169         calculateTop(&usec2, factor);
00170 
00171         setPeriods(prescaler, usec1, usec2);
00172 
00173         return false;
00174 }
00175 
00176 
00177 
00178 
00179 /* Set the prescaler (internal use only)
00180  * @param       prescaler       the prescaler value (only the lowest 3 bits may be set)
00181  */
00182 void MHV_Timer8::_setPrescaler(MHV_TIMER_PRESCALER prescaler) {
00183         *_controlRegB = (*_controlRegB & 0xf8) | prescaler;
00184 }
00185 
00186 /* Get the prescaler
00187  * @return the prescaler value
00188  */
00189 MHV_TIMER_PRESCALER MHV_Timer8::getPrescaler(void) {
00190         return (MHV_TIMER_PRESCALER)(*_controlRegB & 0x07);
00191 }
00192 
00193 /* Get the prescaler multiplier
00194  */
00195 uint16_t MHV_Timer8::getPrescalerMultiplier(void) {
00196         switch (_type) {
00197         case MHV_TIMER_TYPE_5_PRESCALERS:
00198                 switch (getPrescaler()) {
00199                 case MHV_TIMER_PRESCALER_5_1:
00200                         return 1;
00201                 case MHV_TIMER_PRESCALER_5_8:
00202                         return 8;
00203                 case MHV_TIMER_PRESCALER_5_64:
00204                         return 64;
00205                 case MHV_TIMER_PRESCALER_5_256:
00206                         return 256;
00207                 case MHV_TIMER_PRESCALER_5_1024:
00208                         return 1024;
00209                 default:
00210                         break;
00211                 }
00212                 break;
00213         case MHV_TIMER_TYPE_7_PRESCALERS:
00214                 switch (getPrescaler()) {
00215                 case MHV_TIMER_PRESCALER_7_1:
00216                         return 1;
00217                 case MHV_TIMER_PRESCALER_7_8:
00218                         return 8;
00219                 case MHV_TIMER_PRESCALER_7_32:
00220                         return 32;
00221                 case MHV_TIMER_PRESCALER_7_64:
00222                         return 64;
00223                 case MHV_TIMER_PRESCALER_7_128:
00224                         return 128;
00225                 case MHV_TIMER_PRESCALER_7_256:
00226                         return 256;
00227                 case MHV_TIMER_PRESCALER_7_1024:
00228                         return 1024;
00229                 default:
00230                         break;
00231                 }
00232                 break;
00233         }
00234 
00235         return 0;
00236 }
00237 
00238 /* set the prescaler
00239  * @param       prescaler       the prescaler value
00240  */
00241 void MHV_Timer8::setPrescaler(MHV_TIMER_PRESCALER prescaler) {
00242         _prescaler = prescaler;
00243 }
00244 
00245 /* Set the generation mode
00246  */
00247 void MHV_Timer8::setGenerationMode() {
00248         switch (_mode) {
00249         case MHV_TIMER_ONE_SHOT:
00250         case MHV_TIMER_REPETITIVE:
00251                 *_controlRegA = (*_controlRegA & 0xfc) | _BV(WGM01);
00252                 *_controlRegB = (*_controlRegB & 0xf7);
00253                 break;
00254         case MHV_TIMER_8_PWM_PHASE_CORRECT_VAR_FREQ:
00255                 *_controlRegA = (*_controlRegA & 0xfc) | _BV(WGM00);
00256                 *_controlRegB = (*_controlRegB & 0xf7) | _BV(WGM02);
00257                 break;
00258         case MHV_TIMER_8_PWM_PHASE_CORRECT_2_OUTPUT:
00259                 *_controlRegA = (*_controlRegA & 0xfc) | _BV(WGM01) | _BV(WGM00);
00260                 *_controlRegB = (*_controlRegB & 0xf7);
00261                 break;
00262         case MHV_TIMER_8_PWM_FAST_VAR_FREQ:
00263                 *_controlRegA = (*_controlRegA & 0xfc) | _BV(WGM01) | _BV(WGM00);
00264                 *_controlRegB = (*_controlRegB & 0xf7) | _BV(WGM02);
00265                 break;
00266         case MHV_TIMER_8_PWM_FAST_2_OUTPUT:
00267                 *_controlRegA = (*_controlRegA & 0xfc) | _BV(WGM01) | _BV(WGM00);
00268                 *_controlRegB = (*_controlRegB & 0xf7);
00269                 break;
00270         default:
00271                 break;
00272         }
00273 }
00274 
00275 /* Set the overflow periods
00276  * @param       prescaler       the prescaler to use
00277  * @param       time1           the first time in prescaled timer ticks
00278  * @param       time2           the second time in prescaled timer ticks
00279  */
00280 void MHV_Timer8::setPeriods(MHV_TIMER_PRESCALER prescaler, uint8_t time1, uint8_t time2) {
00281         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00282                 _prescaler = prescaler;
00283                 _setPrescaler(prescaler);
00284 
00285                 *_counter = 0;
00286                 *_outputCompare1 = time1;
00287                 *_outputCompare2 = time2;
00288         }
00289 }
00290 
00291 /* Get the number of timer cycles available
00292  */
00293 uint8_t MHV_Timer8::getTop(void) {
00294         switch (_mode) {
00295         case MHV_TIMER_ONE_SHOT:
00296         case MHV_TIMER_REPETITIVE:
00297         case MHV_TIMER_8_PWM_PHASE_CORRECT_VAR_FREQ:
00298         case MHV_TIMER_8_PWM_FAST_VAR_FREQ:
00299                 return *_outputCompare1;
00300         case MHV_TIMER_8_PWM_PHASE_CORRECT_2_OUTPUT:
00301         case MHV_TIMER_8_PWM_FAST_2_OUTPUT:
00302                 return 255;
00303         default:
00304                 return 0;
00305         }
00306 }
00307 
00308 /* Set the number of timer cycles available
00309 */
00310 void MHV_Timer8::setTop(uint8_t value) {
00311         switch (_mode) {
00312         case MHV_TIMER_ONE_SHOT:
00313         case MHV_TIMER_REPETITIVE:
00314         case MHV_TIMER_8_PWM_PHASE_CORRECT_VAR_FREQ:
00315         case MHV_TIMER_8_PWM_FAST_VAR_FREQ:
00316                 *_outputCompare1 = value;
00317                 break;
00318         default:
00319                 return;
00320         }
00321 }
00322 
00323 void MHV_Timer8::setOutput(uint8_t channel, uint8_t value) {
00324         switch (channel) {
00325         case 1:
00326                 *_outputCompare1 = value;
00327                 break;
00328         case 2:
00329                 *_outputCompare2 = value;
00330                 break;
00331         }
00332 }
00333 
00334 void MHV_Timer8::setOutput1(uint8_t value) {
00335         *_outputCompare1 = value;
00336 }
00337 
00338 void MHV_Timer8::setOutput2(uint8_t value) {
00339         *_outputCompare2 = value;
00340 }
00341 
00342 uint8_t MHV_Timer8::getOutput(uint8_t channel) {
00343         switch (channel) {
00344         case 1:
00345                 return *_outputCompare1;
00346                 break;
00347         case 2:
00348                 return *_outputCompare2;
00349                 break;
00350         default:
00351                 return 0;
00352         }
00353 }
00354 
00355 
00356 uint8_t MHV_Timer8::getOutput1(void) {
00357         return *_outputCompare1;
00358 }
00359 
00360 uint8_t MHV_Timer8::getOutput2(void) {
00361         return *_outputCompare2;
00362 }
00363 
00364 void MHV_Timer8::connectOutput1(MHV_TIMER_CONNECT_TYPE type) {
00365         *_controlRegA = (*_controlRegA & 0x3F) | (type << 6);
00366 }
00367 
00368 void MHV_Timer8::connectOutput2(MHV_TIMER_CONNECT_TYPE type) {
00369         *_controlRegA = (*_controlRegA & 0xCF) | (type << 4);
00370 }
00371 
00372 
00373 /* Enable the timer module
00374  */
00375 void MHV_Timer8::enable(void) {
00376         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00377 
00378                 *_counter = 0;
00379                 _setPrescaler(_prescaler);
00380                 setGenerationMode();
00381                 if (_triggerFunction1) {
00382                         *_interrupt |= _BV(_interruptEnableA);
00383                 }
00384                 if (*_outputCompare2 && _triggerFunction2) {
00385                         *_interrupt |= _BV(_interruptEnableA + 1);
00386                         _haveTime2 = true;
00387                 } else {
00388                         _haveTime2 = false;
00389                 }
00390         }
00391 }
00392 
00393 void MHV_Timer8::disable(void) {
00394         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00395                 _setPrescaler(MHV_TIMER_PRESCALER_DISABLED);
00396                 *_interrupt &= ~_BV(_interruptEnableA);
00397                 if (_haveTime2) {
00398                         *_interrupt &= ~_BV(_interruptEnableA + 1);
00399                 }
00400         }
00401 }
00402 
00403 bool MHV_Timer8::enabled(void) {
00404         return getPrescaler();
00405 }
00406 
00407 void MHV_Timer8::trigger1() {
00408         if (MHV_TIMER_ONE_SHOT == _mode) {
00409                 disable();
00410         }
00411         _triggerFunction1(_triggerData1);
00412 }
00413 
00414 void MHV_Timer8::trigger2() {
00415         if (_triggerFunction2) {
00416                 _triggerFunction2(_triggerData2);
00417         }
00418 }
00419 
00420 void MHV_Timer8::setTriggers(void (*triggerFunction1)(void *triggerData), void *triggerData1,
00421                 void (*triggerFunction2)(void *triggerData), void *triggerData2) {
00422         _triggerFunction1 = triggerFunction1;
00423         _triggerData1 = triggerData1;
00424 
00425         _triggerFunction2 = triggerFunction2;
00426         _triggerData2 = triggerData2;
00427 }
00428 
00429 void MHV_Timer8::setMode(MHV_TIMER_MODE mode) {
00430         _mode = mode;
00431 }