MHVLib
20111011
An efficiency oriented runtime library for AVR microcontrollers
|
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 }