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