|
MHVLib
20111227
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 #ifndef MHV_SHIFT_DELAY 00043 #define MHV_SHIFT_DELAY 00044 #endif 00045 00046 #ifdef MHV_SHIFT_ORDER_MSB 00047 #define SHIFTOUT_BYTE_LOOP (mhv_shift_i = 7; mhv_shift_i >= 0; mhv_shift_i--) 00048 #define MHV_BIT_1 _BV(7) 00049 #define MHV_BIT_2 _BV(6) 00050 #define MHV_BIT_3 _BV(5) 00051 #define MHV_BIT_4 _BV(4) 00052 #define MHV_BIT_5 _BV(3) 00053 #define MHV_BIT_6 _BV(2) 00054 #define MHV_BIT_7 _BV(1) 00055 #define MHV_BIT_8 _BV(0) 00056 #else 00057 #define SHIFTOUT_BYTE_LOOP (mhv_shift_i = 0; mhv_shift_i < 8; mhv_shift_i++) 00058 #define MHV_BIT_1 _BV(0) 00059 #define MHV_BIT_2 _BV(1) 00060 #define MHV_BIT_3 _BV(2) 00061 #define MHV_BIT_4 _BV(3) 00062 #define MHV_BIT_5 _BV(4) 00063 #define MHV_BIT_6 _BV(5) 00064 #define MHV_BIT_7 _BV(6) 00065 #define MHV_BIT_8 _BV(7) 00066 #endif 00067 00068 #if defined(MHV_SHIFT_WRITECLOCK) && defined(MHV_SHIFT_WRITEDATA) 00069 /* Shift a byte out, works both for devices that read on rising clock 00070 * & falling clock 00071 */ 00072 00073 #define MHV_SHIFTOUT_BYTE(data) \ 00074 do { \ 00075 int8_t mhv_shift_i; \ 00076 for SHIFTOUT_BYTE_LOOP { \ 00077 if ((data >> mhv_shift_i) & 0x01) { \ 00078 mhv_pinOn(MHV_SHIFT_WRITEDATA); \ 00079 } else { \ 00080 mhv_pinOff(MHV_SHIFT_WRITEDATA); \ 00081 } \ 00082 mhv_pinOn(MHV_SHIFT_WRITECLOCK); \ 00083 mhv_pinOff(MHV_SHIFT_WRITECLOCK); \ 00084 } \ 00085 } while (0); 00086 00087 /* Write an array of data as clocked serial, where the reading device 00088 * reads data when the clock rises 00089 * Clock and data must be on the same port. 00090 * Other pins on this port should not be manipulated by interrupts or 00091 * this macro will corrupt them. 00092 * data & dataLength are sacrificial, upon completion, data will point to the 00093 * end of the array, and dataLength will be 0 00094 * mhv_dataCopy is used to avoid pointer indirection on each bit test 00095 * 00096 * @param data a pointer to the data to write 00097 * @param dataLength the length of the data (must be a variable) 00098 */ 00099 #define MHV_SHIFTOUT_ARRAY_CLOCKED_RISING(data,len) \ 00100 do { \ 00101 uint8_t dataOffClockOff = *mhv_out(MHV_SHIFT_WRITEDATA) & \ 00102 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA))) & ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK))); \ 00103 uint8_t dataOffClockOn = (*mhv_out(MHV_SHIFT_WRITEDATA) & \ 00104 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA)))) | _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)); \ 00105 uint8_t dataOnClockOff = (*mhv_out(MHV_SHIFT_WRITEDATA) & \ 00106 ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK)))) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA)); \ 00107 uint8_t dataOnClockOn = *mhv_out(MHV_SHIFT_WRITEDATA) | \ 00108 _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA)); \ 00109 uint8_t mhv_dataCopy; \ 00110 \ 00111 while (len--) { \ 00112 mhv_dataCopy = *data++; \ 00113 if ((mhv_dataCopy & MHV_BIT_1)) { \ 00114 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00115 MHV_SHIFT_DELAY; \ 00116 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00117 MHV_SHIFT_DELAY; \ 00118 } else { \ 00119 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00120 MHV_SHIFT_DELAY; \ 00121 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00122 MHV_SHIFT_DELAY; \ 00123 } \ 00124 if ((mhv_dataCopy & MHV_BIT_2)) { \ 00125 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00126 MHV_SHIFT_DELAY; \ 00127 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00128 MHV_SHIFT_DELAY; \ 00129 } else { \ 00130 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00131 MHV_SHIFT_DELAY; \ 00132 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00133 MHV_SHIFT_DELAY; \ 00134 } \ 00135 if ((mhv_dataCopy & MHV_BIT_3)) { \ 00136 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00137 MHV_SHIFT_DELAY; \ 00138 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00139 MHV_SHIFT_DELAY; \ 00140 } else { \ 00141 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00142 MHV_SHIFT_DELAY; \ 00143 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00144 MHV_SHIFT_DELAY; \ 00145 } \ 00146 if ((mhv_dataCopy & MHV_BIT_4)) { \ 00147 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00148 MHV_SHIFT_DELAY; \ 00149 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00150 MHV_SHIFT_DELAY; \ 00151 } else { \ 00152 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00153 MHV_SHIFT_DELAY; \ 00154 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00155 MHV_SHIFT_DELAY; \ 00156 } \ 00157 if ((mhv_dataCopy & MHV_BIT_5)) { \ 00158 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00159 MHV_SHIFT_DELAY; \ 00160 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00161 MHV_SHIFT_DELAY; \ 00162 } else { \ 00163 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00164 MHV_SHIFT_DELAY; \ 00165 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00166 MHV_SHIFT_DELAY; \ 00167 } \ 00168 if ((mhv_dataCopy & MHV_BIT_6)) { \ 00169 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00170 MHV_SHIFT_DELAY; \ 00171 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00172 MHV_SHIFT_DELAY; \ 00173 } else { \ 00174 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00175 MHV_SHIFT_DELAY; \ 00176 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00177 MHV_SHIFT_DELAY; \ 00178 } \ 00179 if ((mhv_dataCopy & MHV_BIT_7)) { \ 00180 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00181 MHV_SHIFT_DELAY; \ 00182 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00183 MHV_SHIFT_DELAY; \ 00184 } else { \ 00185 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00186 MHV_SHIFT_DELAY; \ 00187 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00188 MHV_SHIFT_DELAY; \ 00189 } \ 00190 if ((mhv_dataCopy & MHV_BIT_8)) { \ 00191 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00192 MHV_SHIFT_DELAY; \ 00193 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00194 MHV_SHIFT_DELAY; \ 00195 } else { \ 00196 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00197 MHV_SHIFT_DELAY; \ 00198 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00199 MHV_SHIFT_DELAY; \ 00200 } \ 00201 } \ 00202 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00203 } while (0); 00204 00205 /* Write an array of data as clocked serial, where the reading device 00206 * reads data when the clock rises 00207 * Clock and data must be on the same port. 00208 * Other pins on this port should not be manipulated by interrupts or 00209 * this macro will corrupt them. 00210 * data & dataLength are sacrificial, upon completion, data will point to the 00211 * end of the array, and dataLength will be 0 00212 * mhv_dataCopy is used to avoid pointer indirection on each bit test 00213 * 00214 * @param data a pointer to the data to write 00215 * @param dataLength the length of a element of data 00216 * @param elements the number of elements 00217 */ 00218 #define MHV_SHIFTOUT_ELEMENTS_CLOCKED_RISING(data,len,elements) \ 00219 do { \ 00220 uint8_t dataOffClockOff = *mhv_out(MHV_SHIFT_WRITEDATA) & \ 00221 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA))) & ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK))); \ 00222 uint8_t dataOffClockOn = (*mhv_out(MHV_SHIFT_WRITEDATA) & \ 00223 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA)))) | _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)); \ 00224 uint8_t dataOnClockOff = (*mhv_out(MHV_SHIFT_WRITEDATA) & \ 00225 ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK)))) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA)); \ 00226 uint8_t dataOnClockOn = *mhv_out(MHV_SHIFT_WRITEDATA) | \ 00227 _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA)); \ 00228 uint8_t mhv_dataCopy; \ 00229 uint8_t lenCopy; \ 00230 while (elements--) { \ 00231 for (lenCopy = len; --lenCopy;) { \ 00232 mhv_dataCopy = *data++; \ 00233 if ((mhv_dataCopy & MHV_BIT_1)) { \ 00234 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00235 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00236 } else { \ 00237 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00238 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00239 } \ 00240 if ((mhv_dataCopy & MHV_BIT_2)) { \ 00241 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00242 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00243 } else { \ 00244 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00245 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00246 } \ 00247 if ((mhv_dataCopy & MHV_BIT_3)) { \ 00248 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00249 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00250 } else { \ 00251 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00252 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00253 } \ 00254 if ((mhv_dataCopy & MHV_BIT_4)) { \ 00255 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00256 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00257 } else { \ 00258 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00259 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00260 } \ 00261 if ((mhv_dataCopy & MHV_BIT_5)) { \ 00262 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00263 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00264 } else { \ 00265 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00266 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00267 } \ 00268 if ((mhv_dataCopy & MHV_BIT_6)) { \ 00269 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00270 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00271 } else { \ 00272 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00273 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00274 } \ 00275 if ((mhv_dataCopy & MHV_BIT_7)) { \ 00276 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00277 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00278 } else { \ 00279 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00280 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00281 } \ 00282 if ((mhv_dataCopy & MHV_BIT_8)) { \ 00283 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00284 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00285 } else { \ 00286 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00287 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00288 } \ 00289 } \ 00290 } \ 00291 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00292 } while (0); 00293 00294 00295 /* Write an array of data as clocked serial, where the reading device 00296 * reads data when the clock falls 00297 * Clock and data must be on the same port. 00298 * Other pins on this port should not be manipulated by interrupts or 00299 * this macro will corrupt them. 00300 * data & dataLength are sacrificial, upon completion, data will point to the 00301 * end of the array, and dataLength will be 0 00302 * mhv_dataCopy is used to avoid pointer indirection on each bit test 00303 * 00304 * @param data a pointer to the data to write 00305 * @param dataLength the length of a element of data 00306 * @param elements the number of elements 00307 * 00308 */ 00309 #define MHV_SHIFTOUT_ELEMENTS_CLOCKED_FALLING(data,len,elements) \ 00310 do { \ 00311 uint8_t dataOffClockOff = *mhv_out(MHV_SHIFT_WRITEDATA) & \ 00312 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA))) & ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK))); \ 00313 uint8_t dataOffClockOn = (*mhv_out(MHV_SHIFT_WRITEDATA) & \ 00314 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA)))) | _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)); \ 00315 uint8_t dataOnClockOff = (*mhv_out(MHV_SHIFT_WRITEDATA) & \ 00316 ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK)))) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA)); \ 00317 uint8_t dataOnClockOn = *mhv_out(MHV_SHIFT_WRITEDATA) | \ 00318 _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA));\ 00319 uint8_t mhv_dataCopy; \ 00320 uint8_t lenCopy; \ 00321 while (elements--) { \ 00322 for (lenCopy = len; --lenCopy;) { \ 00323 mhv_dataCopy = *data++;\ 00324 if ((mhv_dataCopy & MHV_BIT_1)) {\ 00325 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00326 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00327 } else { \ 00328 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00329 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00330 } \ 00331 if ((mhv_dataCopy & MHV_BIT_2)) { \ 00332 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00333 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00334 } else { \ 00335 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00336 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00337 } \ 00338 if ((mhv_dataCopy & MHV_BIT_3)) { \ 00339 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00340 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00341 } else { \ 00342 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00343 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00344 } \ 00345 if ((mhv_dataCopy & MHV_BIT_4)) { \ 00346 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00347 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00348 } else { \ 00349 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00350 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00351 } \ 00352 if ((mhv_dataCopy & MHV_BIT_5)) { \ 00353 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00354 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00355 } else { \ 00356 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00357 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00358 } \ 00359 if ((mhv_dataCopy & MHV_BIT_6)) { \ 00360 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00361 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00362 } else { \ 00363 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00364 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00365 } \ 00366 if ((mhv_dataCopy & MHV_BIT_7)) { \ 00367 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00368 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00369 } else { \ 00370 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00371 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00372 } \ 00373 if ((mhv_dataCopy & MHV_BIT_8)) { \ 00374 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00375 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00376 } else { \ 00377 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00378 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00379 } \ 00380 } \ 00381 } \ 00382 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00383 } while (0); 00384 00385 00386 /* Write an array of data as clocked serial, where the reading device 00387 * reads data when the clock falls 00388 * Clock and data must be on the same port. 00389 * Other pins on this port should not be manipulated by interrupts or 00390 * this macro will corrupt them. 00391 * data & dataLength are sacrificial, upon completion, data will point to the 00392 * end of the array, and dataLength will be 0 00393 * mhv_dataCopy is used to avoid pointer indirection on each bit test 00394 * 00395 * param data a pointer to the data to write 00396 * param dataLength the length of the data (must be a variable) 00397 * 00398 */ 00399 #define MHV_SHIFTOUT_ARRAY_CLOCKED_FALLING(data,len) \ 00400 do { \ 00401 uint8_t dataOffClockOff = *mhv_out(MHV_SHIFT_WRITEDATA) & \ 00402 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA))) & ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK))); \ 00403 uint8_t dataOffClockOn = (*mhv_out(MHV_SHIFT_WRITEDATA) & \ 00404 ~(_BV(mhv_bit(MHV_SHIFT_WRITEDATA)))) | _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)); \ 00405 uint8_t dataOnClockOff = (*mhv_out(MHV_SHIFT_WRITEDATA) & \ 00406 ~(_BV(mhv_bit(MHV_SHIFT_WRITECLOCK)))) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA)); \ 00407 uint8_t dataOnClockOn = *mhv_out(MHV_SHIFT_WRITEDATA) | \ 00408 _BV(mhv_bit(MHV_SHIFT_WRITECLOCK)) | _BV(mhv_bit(MHV_SHIFT_WRITEDATA));\ 00409 uint8_t mhv_dataCopy; \ 00410 \ 00411 while (!dataLength--) { \ 00412 mhv_dataCopy = *data++;\ 00413 if ((mhv_dataCopy & MHV_BIT_1)) {\ 00414 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00415 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00416 } else { \ 00417 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00418 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00419 } \ 00420 if ((mhv_dataCopy & MHV_BIT_2)) { \ 00421 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00422 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00423 } else { \ 00424 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00425 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00426 } \ 00427 if ((mhv_dataCopy & MHV_BIT_3)) { \ 00428 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00429 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00430 } else { \ 00431 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00432 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00433 } \ 00434 if ((mhv_dataCopy & MHV_BIT_4)) { \ 00435 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00436 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00437 } else { \ 00438 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00439 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00440 } \ 00441 if ((mhv_dataCopy & MHV_BIT_5)) { \ 00442 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00443 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00444 } else { \ 00445 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00446 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00447 } \ 00448 if ((mhv_dataCopy & MHV_BIT_6)) { \ 00449 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00450 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00451 } else { \ 00452 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00453 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00454 } \ 00455 if ((mhv_dataCopy & MHV_BIT_7)) { \ 00456 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00457 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00458 } else { \ 00459 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00460 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00461 } \ 00462 if ((mhv_dataCopy & MHV_BIT_8)) { \ 00463 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOn; \ 00464 mhv_out(MHV_SHIFT_WRITEDATA) = dataOnClockOff; \ 00465 } else { \ 00466 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00467 mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOff; \ 00468 } \ 00469 } \ 00470 *mhv_out(MHV_SHIFT_WRITEDATA) = dataOffClockOn; \ 00471 } while (0); 00472 00473 00474 #endif 00475 00476 /* Function variants of the above macros 00477 */ 00478 void mhv_shiftout_byte_lsb(MHV_PIN *data, MHV_PIN *clock, uint8_t byte); 00479 void mhv_shiftout_byte_msb(MHV_PIN *data, MHV_PIN *clock, uint8_t byte); 00480 00481 00487 #define MHV_SHIFTER_CLOCKED_RISING_CREATE(name) \ 00488 class MHV_Shifter_ ## name : public MHV_Shifter { \ 00489 public: \ 00490 void shiftOut(uint8_t *shiftData, uint8_t shiftLength); \ 00491 void shiftOut(uint8_t *shiftData, uint16_t shiftLength); \ 00492 void shiftOut(uint8_t *shiftData, uint8_t dataLength, uint16_t elements); \ 00493 }; \ 00494 void MHV_Shifter_ ## name::shiftOut(uint8_t *shiftData, uint8_t shiftLength) { \ 00495 MHV_SHIFTOUT_ARRAY_CLOCKED_RISING(shiftData, shiftLength); \ 00496 } \ 00497 void MHV_Shifter_ ## name::shiftOut(uint8_t *shiftData, uint16_t shiftLength) { \ 00498 MHV_SHIFTOUT_ARRAY_CLOCKED_RISING(shiftData, shiftLength); \ 00499 } \ 00500 void MHV_Shifter_ ## name::shiftOut(uint8_t *shiftData, uint8_t dataLength, uint16_t elements) { \ 00501 MHV_SHIFTOUT_ELEMENTS_CLOCKED_RISING(shiftData, dataLength, elements); \ 00502 } \ 00503 MHV_Shifter_ ## name name; 00504 00510 #define MHV_SHIFTER_CLOCKED_FALLING_CREATE(name) \ 00511 class MHV_Shifter_ ## name : public MHV_Shifter { \ 00512 public: \ 00513 void shiftOut(uint8_t *shiftData, uint8_t shiftLength); \ 00514 void shiftOut(uint8_t *shiftData, uint16_t shiftLength); \ 00515 void shiftOut(uint8_t *shiftData, uint8_t dataLength, uint16_t elements); \ 00516 }; \ 00517 void MHV_Shifter_ ## name::shiftOut(uint8_t *shiftData, uint8_t shiftLength) { \ 00518 MHV_SHIFTOUT_ARRAY_CLOCKED_FALLING(shiftData, shiftLength); \ 00519 } \ 00520 void MHV_Shifter_ ## name::shiftOut(uint8_t *shiftData, uint16_t shiftLength) { \ 00521 MHV_SHIFTOUT_ARRAY_CLOCKED_FALLING(shiftData, shiftLength); \ 00522 } \ 00523 void MHV_Shifter_ ## name::shiftOut(uint8_t *shiftData, uint8_t dataLength, uint16_t elements) { \ 00524 MHV_SHIFTOUT_ELEMENTS_CLOCKED_FALLING(shiftData, dataLength, elements); \ 00525 } \ 00526 MHV_Shifter_ ## name name; 00527 00528 00529 class MHV_Shifter { 00530 public: 00531 virtual void shiftOut(uint8_t *data, uint8_t length); 00532 virtual void shiftOut(uint8_t *data, uint16_t length); 00533 virtual void shiftOut(uint8_t *data, uint8_t length, uint16_t elements); 00534 }; 00535 00536 #endif /* MHV_SHIFTER_H_ */