MHVLib  20111011
An efficiency oriented runtime library for AVR microcontrollers
A:/eclipse/mhvlib/MHV_io.h
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 #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_ */