MHVLib  20111011
An efficiency oriented runtime library for AVR microcontrollers
A:/eclipse/mhvlib/MHV_Timer16.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 
00029 #include <MHV_Timer16.h>
00030 #include <avr/interrupt.h>
00031 #include <util/atomic.h>
00032 
00033 #ifdef MHV_TIMER16_1
00034 
00035 /* Create a new timer
00036  * param: time the time in microseconds
00037  */
00038 MHV_Timer16::MHV_Timer16(volatile uint8_t *controlRegA, volatile uint8_t *controlRegB, volatile uint8_t *controlRegC,
00039                 volatile uint16_t *outputCompare1, volatile uint16_t *outputCompare2, volatile uint16_t *outputCompare3,
00040                 volatile uint16_t *counter,     volatile uint8_t *interrupt, volatile uint16_t *inputCapture1) {
00041         _controlRegA = controlRegA;
00042         _controlRegB = controlRegB;
00043         _controlRegC = controlRegC;
00044         _outputCompare1 = outputCompare1;
00045         _outputCompare2 = outputCompare2;
00046         _outputCompare3 = outputCompare3;
00047         _counter = counter;
00048         _interrupt = interrupt;
00049         _inputCapture1 = inputCapture1;
00050         _counterSize = 16;
00051         _mode = MHV_TIMER_REPETITIVE;
00052         _type = MHV_TIMER_TYPE_5_PRESCALERS;
00053 
00054         _haveTime3 = false;
00055         _triggerData3 = NULL;
00056         _triggerFunction3 = NULL;
00057 
00058 }
00059 
00060 uint16_t MHV_Timer16::current(void) {
00061         uint16_t ret;
00062 
00063         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00064                 ret = *_counter;
00065         }
00066         return ret;
00067 }
00068 
00069 /* Set the generation mode
00070  * param        mode    the mode to run the timer in
00071  */
00072 void MHV_Timer16::setGenerationMode(void) {
00073         switch (_mode) {
00074         case MHV_TIMER_ONE_SHOT:
00075         case MHV_TIMER_REPETITIVE:
00076                 *_controlRegA = (*_controlRegA & 0xfc);
00077                 *_controlRegB = (*_controlRegB & 0xe7) | _BV(WGM12);
00078                 break;
00079         case MHV_TIMER_16_PWM_PHASE_CORRECT:
00080                 *_controlRegA = (*_controlRegA & 0xfc);
00081                 *_controlRegB = (*_controlRegB & 0xe7) | _BV(WGM13);
00082                 break;
00083         case MHV_TIMER_16_PWM_FAST:
00084                 *_controlRegA = (*_controlRegA & 0xfc) | _BV(WGM11);
00085                 *_controlRegB = (*_controlRegB & 0xe7) | _BV(WGM13) | _BV(WGM12);
00086                 break;
00087         case MHV_TIMER_16_PWM_PHASE_FREQ_CORRECT: // Always use ICR for top
00088                 *_controlRegA = (*_controlRegA & 0xfc);
00089                 *_controlRegB = (*_controlRegB & 0xe7) | _BV(WGM13);
00090                 break;
00091         default:
00092                 break;
00093         }
00094 }
00095 
00096 /* Get the number of timer cycles available
00097  */
00098 uint16_t MHV_Timer16::getTop(void) {
00099         switch (_mode) {
00100         case MHV_TIMER_ONE_SHOT:
00101         case MHV_TIMER_REPETITIVE:
00102                 return *_outputCompare1;
00103         case MHV_TIMER_16_PWM_PHASE_CORRECT:
00104         case MHV_TIMER_16_PWM_FAST:
00105         case MHV_TIMER_16_PWM_PHASE_FREQ_CORRECT:
00106                 return *_inputCapture1;
00107         default:
00108                 return 0;
00109         }
00110 }
00111 
00112 /* Set the number of timer cycles available
00113 */
00114 void MHV_Timer16::setTop(uint16_t value) {
00115         switch (_mode) {
00116         case MHV_TIMER_ONE_SHOT:
00117         case MHV_TIMER_REPETITIVE:
00118                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00119                         *_outputCompare1 = value;
00120                 }
00121                 break;
00122         case MHV_TIMER_16_PWM_PHASE_CORRECT:
00123         case MHV_TIMER_16_PWM_FAST:
00124         case MHV_TIMER_16_PWM_PHASE_FREQ_CORRECT:
00125                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00126                         *_inputCapture1 = value;
00127                 }
00128         default:
00129                 break;
00130         }
00131 }
00132 
00133 void MHV_Timer16::setOutput(uint8_t channel, uint16_t value) {
00134         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00135                 switch (channel) {
00136                 case 1:
00137                         *_outputCompare1 = value;
00138                         break;
00139                 case 2:
00140                         *_outputCompare2 = value;
00141                         break;
00142                 case 3:
00143                         *_outputCompare3 = value;
00144                         break;
00145                 }
00146         }
00147 }
00148 
00149 
00150 void MHV_Timer16::setOutput1(uint16_t value) {
00151         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00152                 *_outputCompare1 = value;
00153         }
00154 }
00155 
00156 void MHV_Timer16::setOutput2(uint16_t value) {
00157         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00158                 *_outputCompare2 = value;
00159         }
00160 }
00161 
00162 void MHV_Timer16::setOutput3(uint16_t value) {
00163         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00164                 *_outputCompare3 = value;
00165         }
00166 }
00167 
00168 uint16_t MHV_Timer16::getOutput(uint8_t channel) {
00169         uint16_t ret = 0;
00170 
00171         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00172                 switch (channel) {
00173                 case 1:
00174                         ret =  *_outputCompare1;
00175                         break;
00176                 case 2:
00177                         ret =  *_outputCompare2;
00178                         break;
00179                 case 3:
00180                         ret =  *_outputCompare3;
00181                         break;
00182                 }
00183         }
00184 
00185         return ret;
00186 }
00187 
00188 uint16_t MHV_Timer16::getOutput1(void) {
00189         uint16_t ret;
00190         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00191                 ret =  *_outputCompare1;
00192         }
00193         return ret;
00194 }
00195 
00196 uint16_t MHV_Timer16::getOutput2(void) {
00197         uint16_t ret;
00198         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00199                 ret =  *_outputCompare2;
00200         }
00201         return ret;
00202 }
00203 
00204 uint16_t MHV_Timer16::getOutput3(void) {
00205         uint16_t ret;
00206         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00207                 ret =  *_outputCompare3;
00208         }
00209         return ret;
00210 }
00211 
00212 void MHV_Timer16::connectOutput(uint8_t channel, MHV_TIMER_CONNECT_TYPE type) {
00213         switch (channel) {
00214         case 1:
00215                 *_controlRegA = (*_controlRegA & 0x3F) | (type << 6);
00216                 break;
00217         case 2:
00218                 *_controlRegA = (*_controlRegA & 0xCF) | (type << 4);
00219                 break;
00220         case 3:
00221                 *_controlRegA = (*_controlRegA & 0xF3) | (type << 2);
00222                 break;
00223         }
00224 }
00225 
00226 void MHV_Timer16::connectOutput1(MHV_TIMER_CONNECT_TYPE type) {
00227         *_controlRegA = (*_controlRegA & 0x3F) | (type << 6);
00228 }
00229 
00230 void MHV_Timer16::connectOutput2(MHV_TIMER_CONNECT_TYPE type) {
00231         *_controlRegA = (*_controlRegA & 0xCF) | (type << 4);
00232 }
00233 
00234 void MHV_Timer16::connectOutput3(MHV_TIMER_CONNECT_TYPE type) {
00235         *_controlRegA = (*_controlRegA & 0xF3) | (type << 2);
00236 }
00237 
00238 void MHV_Timer16::disable(void) {
00239         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00240                 _setPrescaler(MHV_TIMER_PRESCALER_DISABLED);
00241                 *_interrupt &= ~_BV(OCIE1A);
00242 
00243                 if (_haveTime2) {
00244                         *_interrupt &= ~_BV(OCIE1B);
00245                 }
00246 
00247 #ifdef OCIE1C
00248                 if (_haveTime3) {
00249                         *_interrupt &= ~_BV(OCIE1C);
00250                 }
00251 #endif
00252         }
00253 }
00254 
00255 void MHV_Timer16::enable(void) {
00256         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00257                 *_counter = 0;
00258                 _setPrescaler(_prescaler);
00259                 setGenerationMode();
00260                 if (_triggerFunction1) {
00261                         *_interrupt |= _BV(OCIE1A);
00262                 }
00263                 if (*_outputCompare2 && _triggerFunction2) {
00264                         *_interrupt |= _BV(OCIE1B);
00265                         _haveTime2 = true;
00266                 } else {
00267                         _haveTime2 = false;
00268                 }
00269 
00270 #ifdef OCIE1C
00271                 if (*_outputCompare3 && _triggerFunction3) {
00272                         *_interrupt |= _BV(OCIE1C);
00273                         _haveTime3 = true;
00274                 } else {
00275                         _haveTime3 = false;
00276                 }
00277 #endif
00278         }
00279 }
00280 
00281 void MHV_Timer16::setPeriods(MHV_TIMER_PRESCALER prescaler, uint16_t time1, uint16_t time2, uint16_t time3) {
00282         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00283                 _prescaler = prescaler;
00284                 _setPrescaler(prescaler);
00285 
00286                 *_counter = 0;
00287                 *_outputCompare1 = time1;
00288                 *_outputCompare2 = time2;
00289                 *_outputCompare3 = time3;
00290         }
00291 }
00292 
00293 /* Times are in microseconds
00294  */
00295 void MHV_Timer16::setPeriods(uint32_t usec1, uint32_t usec2, uint32_t usec3) {
00296         MHV_TIMER_PRESCALER prescaler;
00297         uint16_t factor = 0;
00298         uint32_t maxTime;
00299 
00300         usec1 *= F_CPU / (1000000 * 2); // time is now in clocks
00301         usec2 *= F_CPU / (1000000 * 2); // time is now in clocks
00302         usec3 *= F_CPU / (1000000 * 2); // time is now in clocks
00303 
00304         if (usec1 > usec2) {
00305                 maxTime = usec1;
00306         } else {
00307                 maxTime = usec2;
00308         }
00309         if (usec3 > maxTime) {
00310                 maxTime = usec3;
00311         }
00312 
00313         calculatePrescaler(maxTime, &prescaler, &factor);
00314         if (usec1) {
00315                 calculateTop(&usec1, factor);
00316         }
00317         if (usec2) {
00318                 calculateTop(&usec2, factor);
00319         }
00320         if (usec3) {
00321                 calculateTop(&usec3, factor);
00322         }
00323         setPeriods(prescaler, usec1, usec2, usec3);
00324 }
00325 
00326 void MHV_Timer16::setTriggers(void (*triggerFunction1)(void *triggerData), void *triggerData1,
00327                 void (*triggerFunction2)(void *triggerData), void *triggerData2,
00328                 void (*triggerFunction3)(void *triggerData), void *triggerData3) {
00329         _triggerFunction1 = triggerFunction1;
00330         _triggerData1 = triggerData1;
00331         _triggerFunction2 = triggerFunction2;
00332         _triggerData2 = triggerData2;
00333         _triggerFunction3 = triggerFunction3;
00334         _triggerData3 = triggerData3;
00335 }
00336 
00337 
00338 void MHV_Timer16::trigger3() {
00339         if (_triggerFunction3) {
00340                 _triggerFunction3(_triggerData3);
00341         }
00342 }
00343 
00344 #endif // MHV_TIMER16_1