MHVLib  20111011
An efficiency oriented runtime library for AVR microcontrollers
A:/eclipse/mhvlib/MHV_Shifter.h
Go to the documentation of this file.
00001 /* Copyright (c) 2011, Make, Hack, Void Inc
00002  * All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions are met:
00006  *  * Redistributions of source code must retain the above copyright
00007  *    notice, this list of conditions and the following disclaimer.
00008  *  * Redistributions in binary form must reproduce the above copyright
00009  *    notice, this list of conditions and the following disclaimer in the
00010  *    documentation and/or other materials provided with the distribution.
00011  *  * Neither the name of the Make, Hack, Void nor the
00012  *    names of its contributors may be used to endorse or promote products
00013  *    derived from this software without specific prior written permission.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00016  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00018  * DISCLAIMED. IN NO EVENT SHALL MAKE, HACK, VOID BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00020  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00021  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00022  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00023  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00024  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00025  */
00026 
00027 #ifndef MHV_SHIFTER_H_
00028 #define MHV_SHIFTER_H_
00029 
00030 #include <MHV_io.h>
00031 
00032 #ifndef MHV_CORE
00033 #ifndef MHV_SHIFT_WRITECLOCK
00034 #warning MHV_SHIFT_WRITECLOCK not defined - do not expect MHV_SHIFTOUT_* macros to work!
00035 #endif
00036 
00037 #ifndef MHV_SHIFT_WRITEDATA
00038 #warning MHV_SHIFT_WRITEDATA not defined - do not expect MHV_SHIFTOUT_* macros to work!
00039 #endif
00040 #endif
00041 
00042 #ifdef MHV_SHIFT_ORDER_MSB
00043 #define SHIFTOUT_BYTE_LOOP (mhv_shift_i = 7; mhv_shift_i >= 0; mhv_shift_i--)
00044 #define MHV_BIT_1 _BV(7)
00045 #define MHV_BIT_2 _BV(6)
00046 #define MHV_BIT_3 _BV(5)
00047 #define MHV_BIT_4 _BV(4)
00048 #define MHV_BIT_5 _BV(3)
00049 #define MHV_BIT_6 _BV(2)
00050 #define MHV_BIT_7 _BV(1)
00051 #define MHV_BIT_8 _BV(0)
00052 #else
00053 #define SHIFTOUT_BYTE_LOOP (mhv_shift_i = 0; mhv_shift_i < 8; mhv_shift_i++)
00054 #define MHV_BIT_1 _BV(0)
00055 #define MHV_BIT_2 _BV(1)
00056 #define MHV_BIT_3 _BV(2)
00057 #define MHV_BIT_4 _BV(3)
00058 #define MHV_BIT_5 _BV(4)
00059 #define MHV_BIT_6 _BV(5)
00060 #define MHV_BIT_7 _BV(6)
00061 #define MHV_BIT_8 _BV(7)
00062 #endif
00063 
00064 /* Shift a byte out, works both for devices that read on rising clock
00065  * & falling clock
00066  */
00067 #define MHV_SHIFTOUT_BYTE(mhv_data) \
00068 do { \
00069         int8_t          mhv_shift_i; \
00070 \
00071 for SHIFTOUT_BYTE_LOOP { \
00072                 if ((mhv_data >> mhv_shift_i) & 0x01) { \
00073                         mhv_pinOn(MHV_SHIFT_WRITEDATA); \
00074                 } else { \
00075                         mhv_pinOff(MHV_SHIFT_WRITEDATA); \
00076                 } \
00077                 mhv_pinOn(MHV_SHIFT_WRITECLOCK); \
00078                 mhv_pinOff(MHV_SHIFT_WRITECLOCK); \
00079         } \
00080 } while (0)
00081 
00082 /* Write an array of data as clocked serial, where the reading device
00083  * reads data when the clock rises
00084  * Clock and data must be on the same port.
00085  * Other pins on this port should not be manipulated by interrupts or
00086  * this macro will corrupt them.
00087  * data & dataLength are sacrificial, upon completion, data will point to the
00088  * end of the array, and dataLength will be 0
00089  * mhv_dataCopy is used to avoid pointer indirection on each bit test
00090  *
00091  * param        data            a pointer to the data to write
00092  * param        dataLength      the length of the data (must be a variable)
00093  */
00094 #define MHV_SHIFTOUT_ARRAY_CLOCKED_RISING(mhv_data, mhv_dataLength) \
00095 do { \
00096         uint8_t dataOffClockOff = *mhv_out(MHV_SHIFT_WRITEDATA) & \
00097                 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA))) & ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK))); \
00098         uint8_t dataOffClockOn = (*mhv_out(MHV_SHIFT_WRITEDATA) & \
00099                 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA)))) | _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)); \
00100         uint8_t dataOnClockOff = (*mhv_out(MHV_SHIFT_WRITEDATA) & \
00101                         ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK)))) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA)); \
00102         uint8_t dataOnClockOn = *mhv_out(MHV_SHIFT_WRITEDATA) | \
00103                 _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA)); \
00104         uint8_t mhv_dataCopy; \
00105 \
00106         while (mhv_dataLength--) { \
00107                 mhv_dataCopy = *data++; \
00108                 if ((mhv_dataCopy & MHV_BIT_1)) { \
00109                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00110                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00111                 } else { \
00112                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00113                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00114                 } \
00115                 if ((mhv_dataCopy & MHV_BIT_2)) { \
00116                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00117                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00118                 } else { \
00119                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00120                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00121                 } \
00122                 if ((mhv_dataCopy & MHV_BIT_3)) { \
00123                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00124                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00125                 } else { \
00126                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00127                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00128                 } \
00129                 if ((mhv_dataCopy & MHV_BIT_4)) { \
00130                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00131                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00132                 } else { \
00133                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00134                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00135                 } \
00136                 if ((mhv_dataCopy & MHV_BIT_5)) { \
00137                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00138                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00139                 } else { \
00140                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00141                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00142                 } \
00143                 if ((mhv_dataCopy & MHV_BIT_6)) { \
00144                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00145                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00146                 } else { \
00147                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00148                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00149                 } \
00150                 if ((mhv_dataCopy & MHV_BIT_7)) { \
00151                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00152                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00153                 } else { \
00154                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00155                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00156                 } \
00157                 if ((mhv_dataCopy & MHV_BIT_8)) { \
00158                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00159                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00160                 } else { \
00161                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00162                         *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00163                 } \
00164         } \
00165 } while (0)
00166 
00167 /* Write an array of data as clocked serial, where the reading device
00168  * reads data when the clock falls
00169  * Clock and data must be on the same port.
00170  * Other pins on this port should not be manipulated by interrupts or
00171  * this macro will corrupt them.
00172  * data & dataLength are sacrificial, upon completion, data will point to the
00173  * end of the array, and dataLength will be 0
00174  * mhv_dataCopy is used to avoid pointer indirection on each bit test
00175  *
00176  * param        data            a pointer to the data to write
00177  * param        dataLength      the length of the data (must be a variable)
00178  *
00179  */
00180 #define MHV_SHIFTOUT_ARRAY_CLOCKED_FALLING(mhv_data, mhv_dataLength) \
00181 do { \
00182         uint8_t dataOffClockOff = *mhv_out(MHV_SHIFT_WRITEDATA) & \
00183                 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA))) & ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK))); \
00184         uint8_t dataOffClockOn = (*mhv_out(MHV_SHIFT_WRITEDATA) & \
00185                 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA)))) | _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)); \
00186         uint8_t dataOnClockOff = (*mhv_out(MHV_SHIFT_WRITEDATA) & \
00187                         ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK)))) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA)); \
00188         uint8_t dataOnClockOn = *mhv_out(MHV_SHIFT_WRITEDATA) | \
00189                 _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA)); \
00190         uint8_t mhv_dataCopy; \
00191 \
00192         while (!dataLength--) { \
00193                 mhv_dataCopy = *data++; \
00194                 if ((mhv_dataCopy & MHV_BIT_1)) { \
00195                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00196                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00197                 } else { \
00198                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00199                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00200                 } \
00201                 if ((mhv_dataCopy & MHV_BIT_2)) { \
00202                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00203                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00204                 } else { \
00205                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00206                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00207                 } \
00208                 if ((mhv_dataCopy & MHV_BIT_3)) { \
00209                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00210                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00211                 } else { \
00212                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00213                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00214                 } \
00215                 if ((mhv_dataCopy & MHV_BIT_4)) { \
00216                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00217                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00218                 } else { \
00219                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00220                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00221                 } \
00222                 if ((mhv_dataCopy & MHV_BIT_5)) { \
00223                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00224                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00225                 } else { \
00226                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00227                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00228                 } \
00229                 if ((mhv_dataCopy & MHV_BIT_6)) { \
00230                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00231                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00232                 } else { \
00233                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00234                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00235                 } \
00236                 if ((mhv_dataCopy & MHV_BIT_7)) { \
00237                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00238                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00239                 } else { \
00240                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00241                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00242                 } \
00243                 if ((mhv_dataCopy & MHV_BIT_8)) { \
00244                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \
00245                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \
00246                 } else { \
00247                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \
00248                         mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \
00249                 } \
00250         } \
00251 } while (0)
00252 
00253 
00254 /* Function variants of the above macros
00255  */
00256 void mhv_shiftout_byte_lsb(MHV_PIN *data, MHV_PIN *clock, uint8_t byte);
00257 void mhv_shiftout_byte_msb(MHV_PIN *data, MHV_PIN *clock, uint8_t byte);
00258 
00259 #endif /* MHV_SHIFTER_H_ */