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 00029 #ifdef MHVLIB_NEED_PURE_VIRTUAL 00030 #ifndef MHVLIB_PURE_VIRTUAL_DECLARED 00031 #ifndef MHVLIB_CORE 00032 #define MHVLIB_PURE_VIRTUAL_DECLARED 00033 #include <avr/interrupt.h> 00034 extern "C" void __cxa_pure_virtual() { 00035 cli(); 00036 for (;;); 00037 } 00038 #endif 00039 #endif 00040 #endif 00041 00042 00043 #ifndef MHV_IO_H_ 00044 #define MHV_IO_H_ 00045 00046 #include <avr/io.h> 00047 #include <inttypes.h> 00048 #include <stddef.h> 00049 #include <util/atomic.h> 00050 00051 // Some useful attributes 00052 00053 // A function that does not return 00054 #define NORETURN __attribute__ ((noreturn)) 00055 00056 // A function that has no effect other than its return value 00057 #define PURE __attribute__ ((pure)) 00058 00059 #if defined(__AVR_ATtiny2313__) 00060 #include <MHV_io_ATtiny2313.h> 00061 #elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 00062 #include <MHV_io_ATtiny85.h> 00063 #elif defined(__AVR_ATmega1280__) 00064 #include <MHV_io_ATmega1280.h> 00065 #include <MHV_io_ArduinoMega.h> 00066 #elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega48A__) || defined(__AVR_ATmega88__) || \ 00067 defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168__) || \ 00068 defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328__) || \ 00069 defined(__AVR_ATmega328P__) 00070 #include <MHV_io_ATmega168.h> 00071 #include <MHV_io_ArduinoDiecimilla.h> 00072 #endif 00073 00074 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 00075 00076 struct mhv_pin { 00077 volatile uint8_t *dir; 00078 volatile uint8_t *input; 00079 volatile uint8_t *output; 00080 // Contains a mask of the pin 00081 uint8_t bit; 00082 int8_t pcInt; 00083 }; 00084 typedef struct mhv_pin MHV_PIN; 00085 00091 #define mhv_make_pin(_mhv_port, _mhv_bit) \ 00092 _mhv_make_pin(_mhv_port, _mhv_bit) 00093 00094 #define _mhv_make_pin(_mhv_port, _mhv_bit) \ 00095 MHV_PIN_ ## _mhv_port ## _mhv_bit 00096 00101 #define mhv_pin(mhvParms) \ 00102 _mhv_pin(mhvParms) 00103 00104 #define _mhv_pin(mhvDir,mhvOutput,mhvInput,mhvBit,mhvPCInt) \ 00105 {mhvDir, mhvOutput, mhvInput, _BV(mhvBit), mhvPCInt} 00106 00111 inline void mhv_pinOn(MHV_PIN *pin) { 00112 *(pin->output) |= pin->bit; 00113 } 00114 00119 inline void mhv_pinOnAtomic(MHV_PIN *pin) { 00120 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00121 *(pin->output) |= pin->bit; 00122 } 00123 } 00124 00125 00134 inline void mhv_pinOn(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00135 uint8_t bit, int8_t pcInt) { 00136 *out |= _BV(bit); 00137 } 00138 00147 inline void mhv_pinOnAtomic(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00148 uint8_t bit, int8_t pcInt) { 00149 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00150 *out |= _BV(bit); 00151 } 00152 } 00153 00154 00159 inline void mhv_pinOff(MHV_PIN *pin) { 00160 *(pin->output) &= ~(pin->bit); 00161 } 00162 00167 inline void mhv_pinOffAtomic(MHV_PIN *pin) { 00168 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00169 *(pin->output) &= ~(pin->bit); 00170 } 00171 } 00172 00173 00182 inline void mhv_pinOff(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00183 uint8_t bit, int8_t pcInt) { 00184 *out &= ~_BV(bit); 00185 } 00186 00195 inline void mhv_pinOffAtomic(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00196 uint8_t bit, int8_t pcInt) { 00197 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00198 *out &= ~_BV(bit); 00199 } 00200 } 00201 00202 00212 inline void mhv_pinSet(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00213 uint8_t bit, int8_t pcInt, bool state) { 00214 if (state) { 00215 mhv_pinOn(dir, out, in, bit, pcInt); 00216 } else { 00217 mhv_pinOff(dir, out, in, bit, pcInt); 00218 } 00219 } 00220 00231 inline void mhv_pinSetAtomic(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00232 uint8_t bit, int8_t pcInt, bool state) { 00233 if (state) { 00234 mhv_pinOnAtomic(dir, out, in, bit, pcInt); 00235 } else { 00236 mhv_pinOffAtomic(dir, out, in, bit, pcInt); 00237 } 00238 } 00239 00240 00245 inline void mhv_setOutput(MHV_PIN *pin) { 00246 *(pin->dir) |= pin->bit; 00247 } 00248 00253 inline void mhv_setOutputAtomic(MHV_PIN *pin) { 00254 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00255 *(pin->dir) |= pin->bit; 00256 } 00257 } 00258 00259 00268 inline void mhv_setOutput(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00269 uint8_t bit, int8_t pcInt) { 00270 *dir |= _BV(bit); 00271 } 00272 00281 inline void mhv_setOutputAtomic(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00282 uint8_t bit, int8_t pcInt) { 00283 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00284 *dir |= _BV(bit); 00285 } 00286 } 00287 00292 inline void mhv_setInput(MHV_PIN *pin) { 00293 *(pin->dir) &= ~(pin->bit); 00294 *(pin->output) &= ~(pin->bit); 00295 } 00296 00301 inline void mhv_setInputAtomic(MHV_PIN *pin) { 00302 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00303 *(pin->dir) &= ~(pin->bit); 00304 *(pin->output) &= ~(pin->bit); 00305 } 00306 } 00307 00316 inline void mhv_setInput(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00317 uint8_t bit, int8_t pcInt) { 00318 *dir &= ~_BV(bit); 00319 *out &= ~_BV(bit); 00320 } 00321 00330 inline void mhv_setInputAtomic(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00331 uint8_t bit, int8_t pcInt) { 00332 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00333 *dir &= ~_BV(bit); 00334 *out &= ~_BV(bit); 00335 } 00336 } 00337 00338 00343 inline void mhv_setInputPullup(MHV_PIN *pin) { 00344 *(pin->dir) &= ~(pin->bit); 00345 *(pin->output) |= pin->bit; 00346 } 00347 00352 inline void mhv_setInputPullupAtomic(MHV_PIN *pin) { 00353 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00354 *(pin->dir) &= ~(pin->bit); 00355 *(pin->output) |= pin->bit; 00356 } 00357 } 00358 00359 00368 inline void mhv_setInputPullup(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00369 uint8_t bit, int8_t pcInt) { 00370 *dir &= ~_BV(bit); 00371 *out |= _BV(bit); 00372 } 00373 00382 inline void mhv_setInputPullupAtomic(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00383 uint8_t bit, int8_t pcInt) { 00384 *dir &= ~_BV(bit); 00385 *out |= _BV(bit); 00386 } 00387 00388 00393 inline void mhv_pinToggle(MHV_PIN *pin) { 00394 *(pin->input) |= pin->bit; 00395 } 00396 00401 inline void mhv_pinToggleAtomic(MHV_PIN *pin) { 00402 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00403 *(pin->input) |= pin->bit; 00404 } 00405 } 00406 00407 00416 inline void mhv_pinToggle(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00417 uint8_t bit, int8_t pcInt) { 00418 *in |= _BV(bit); 00419 } 00420 00429 inline void mhv_pinToggleAtomic(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00430 uint8_t bit, int8_t pcInt) { 00431 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 00432 *in |= _BV(bit); 00433 } 00434 } 00435 00436 00441 inline bool mhv_pinRead(MHV_PIN *pin) { 00442 return *(pin->input) & pin->bit; 00443 } 00444 00445 00454 inline bool mhv_pinRead(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in, 00455 uint8_t bit, int8_t pcInt) { 00456 return *in & _BV(bit); 00457 } 00458 00459 00466 inline void mhv_memClear(void *bufIn, uint8_t len, uint8_t count) { 00467 char *buf = (char *)bufIn; 00468 00469 for (uint8_t i = 0; i < count; i++) { 00470 for (uint8_t j = 0; j < len; j++, buf++) { 00471 *buf = 0; 00472 } 00473 } 00474 } 00475 00481 inline void mhv_memClear(void *bufIn, uint8_t len) { 00482 char *buf = (char *)bufIn; 00483 00484 for (uint8_t i = 0; i < len; i++, buf++) { 00485 *buf = 0; 00486 } 00487 } 00488 00489 00490 00491 /* We have to shadow all the macros below as the precedence of macro expansion means that 00492 * the multi-parmeter macros will only see a single argument if one of our MHV_PIN macros 00493 * is used 00494 */ 00495 00496 /* See http://gcc.gnu.org/onlinedocs/gcc-3.3.6/cpp/Swallowing-the-Semicolon.html 00497 * to understand why we have do...while(0) on our macros 00498 */ 00499 00504 #define mhv_out(mhvParms) \ 00505 _mhv_out(mhvParms) 00506 00507 #define _mhv_out(mhvDir,mhvOutput,mhvInput,mhvBit,mhvPCInt) \ 00508 mhvOutput 00509 00514 #define mhv_in(mhvParms) \ 00515 _mhv_in(mhvParms) 00516 00517 #define _mhv_in(mhvDir,mhvOutput,mhvInput,mhvBit,mhvPCInt) \ 00518 mhvInput 00519 00524 #define mhv_bit(mhvParms) \ 00525 _mhv_bit(mhvParms) 00526 00527 #define _mhv_bit(mhvDir,mhvOutput,mhvInput,mhvBit,mhvPCInt) \ 00528 mhvBit 00529 00534 #define mhv_dir(mhvParms) \ 00535 _mhv_dir(mhvParms) 00536 00537 #define _mhv_dir(mhvDir,mhvOutput,mhvInput,mhvBit,mhvPCInt) \ 00538 mhvDir 00539 00544 #define mhv_pcint(mhvParms) \ 00545 _mhv_pcint(mhvParms) 00546 00547 #define _mhv_PCInt(mhvDir,mhvOutput,mhvInput,mhvBit,mhvPCInt) \ 00548 mhvPCInt 00549 00550 00556 #define mhv_declareExternalInterrupt(mhvInterruptParms,mhvFunction) \ 00557 _mhv_declareExternalInterrupt(mhvInterruptParms, mhvFunction) 00558 00559 #define _mhv_declareExternalInterrupt(mhvInterruptHandler,mhvModeRegister,mhvModeBitshift,mhvFunction) \ 00560 ISR(mhvInterruptHandler) mhvFunction 00561 00565 enum mhv_interruptMode { 00566 MHV_INTERRUPT_LOW, 00567 MHV_INTERRUPT_CHANGE, 00568 MHV_INTERRUPT_FALLING, 00569 MHV_INTERRUPT_RISING 00570 }; 00571 typedef enum mhv_interruptMode MHV_INTERRUPTMODE; 00572 00573 00579 #define mhv_enableExternalInterrupt(mhvInterruptParms,mhvInterruptMode) \ 00580 do { \ 00581 _mhv_enableExternalInterrupt(mhvInterruptParms,mhvInterruptMode); \ 00582 } while (0) 00583 00584 #define _mhv_enableExternalInterrupt(mhvInterruptHandler,mhvModeRegister,mhvModeBitshift,mhvInterruptMode) \ 00585 *mhvModeRegister = (*mhvModeRegister & ~(0x03 << mhvModeBitshift)) | (mhvInterruptMode << mhvModeBitshift) 00586 00587 #endif /* MHV_IO_H_ */