├── .arduino-ci.yml ├── .github ├── FUNDING.yml └── workflows │ ├── arduino-lint.yml │ ├── arduino_test_runner.yml │ └── jsoncheck.yml ├── CHANGELOG.md ├── FastShiftIn.cpp ├── FastShiftIn.h ├── LICENSE ├── README.md ├── examples ├── fastShiftIn │ └── fastShiftIn.ino ├── fastShiftIn_readLSBFIRST │ └── fastShiftIn_readLSBFIRST.ino ├── fastShiftIn_readMSBFIRST │ └── fastShiftIn_readMSBFIRST.ino ├── fastShiftIn_test │ ├── fastShiftIn_test.ino │ ├── performance_0.2.3.txt │ ├── performance_0.3.0.txt │ ├── performance_0.3.2.txt │ └── performance_0.4.0.txt └── fastShiftIn_test_read │ └── fastShiftIn_test_read.ino ├── keywords.txt ├── library.json ├── library.properties ├── performance.txt └── test └── unit_test_001.cpp /.arduino-ci.yml: -------------------------------------------------------------------------------- 1 | platforms: 2 | rpipico: 3 | board: rp2040:rp2040:rpipico 4 | package: rp2040:rp2040 5 | gcc: 6 | features: 7 | defines: 8 | - ARDUINO_ARCH_RP2040 9 | warnings: 10 | flags: 11 | 12 | packages: 13 | rp2040:rp2040: 14 | url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json 15 | 16 | compile: 17 | # Choosing to run compilation tests on 2 different Arduino platforms 18 | platforms: 19 | - uno 20 | # - due 21 | # - zero 22 | # - leonardo 23 | - m4 24 | - esp32 25 | # - esp8266 26 | # - mega2560 27 | - rpipico 28 | 29 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: RobTillaart 4 | custom: "https://www.paypal.me/robtillaart" 5 | -------------------------------------------------------------------------------- /.github/workflows/arduino-lint.yml: -------------------------------------------------------------------------------- 1 | name: Arduino-lint 2 | 3 | on: [push, pull_request] 4 | jobs: 5 | lint: 6 | runs-on: ubuntu-latest 7 | timeout-minutes: 5 8 | steps: 9 | - uses: actions/checkout@v4 10 | - uses: arduino/arduino-lint-action@v1 11 | with: 12 | library-manager: update 13 | compliance: strict -------------------------------------------------------------------------------- /.github/workflows/arduino_test_runner.yml: -------------------------------------------------------------------------------- 1 | name: Arduino CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | runTest: 7 | runs-on: ubuntu-latest 8 | timeout-minutes: 20 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: ruby/setup-ruby@v1 13 | with: 14 | ruby-version: 2.6 15 | - run: | 16 | gem install arduino_ci 17 | arduino_ci.rb 18 | -------------------------------------------------------------------------------- /.github/workflows/jsoncheck.yml: -------------------------------------------------------------------------------- 1 | name: JSON check 2 | 3 | on: 4 | push: 5 | paths: 6 | - '**.json' 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | timeout-minutes: 5 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: json-syntax-check 16 | uses: limitusus/json-syntax-check@v2 17 | with: 18 | pattern: "\\.json$" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log FastShiftIn 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/). 7 | 8 | 9 | ## [0.4.0] - 2024-09-10 10 | - fix #17, loop unroll option, improving performance, kudos to nt314p 11 | - added flag to select LOOP UNROLL (is optional as it gives larger code size) 12 | - update readme.md 13 | - minor edits 14 | 15 | ---- 16 | 17 | ## [0.3.4] - 2024-07-22 18 | - add **void read(uint8_t \*array, uint8_t size)** (experimental) 19 | - update readme.md 20 | - reorder functions in .cpp 21 | - minor edits 22 | 23 | ## [0.3.3] - 2023-10-31 24 | - update readme.md 25 | 26 | ## [0.3.2] - 2023-02-20 27 | - add (experimental) read16(), read24(), read32() functions. 28 | - changed return types of some functions. 29 | - update keywords.txt 30 | - update readme.md 31 | - update GitHub actions 32 | - update license 2023 33 | - minor edits 34 | 35 | ## [0.3.1] - 2022-11-06 36 | - redo clock pulse 37 | 38 | ## [0.3.0] - 2022-11-05 39 | - fix inputRegister bug 40 | - refactor for code size 41 | 42 | ---- 43 | 44 | ## [0.2.4] - 2022-11-05 45 | - add changelog.md 46 | - add rp2040 to build-CI 47 | - update readme.md 48 | 49 | ## [0.2.3] - 2021-17-12 50 | - update license 51 | - update readme - some badges 52 | - clean up unit test 53 | 54 | ## [0.2.2] - 2020-12-22 55 | 56 | ---- 57 | 58 | ## No history ... 59 | 60 | ## [0.1.0 - 2013-09-29 61 | - initial version 62 | 63 | -------------------------------------------------------------------------------- /FastShiftIn.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: FastShiftIn.cpp 3 | // AUTHOR: Rob Tillaart 4 | // VERSION: 0.4.0 5 | // PURPOSE: Fast ShiftIn for 74HC165 register, AVR optimized 6 | // DATE: 2013-09-29 7 | // URL: https://github.com/RobTillaart/FastShiftIn 8 | 9 | 10 | #include "FastShiftIn.h" 11 | 12 | 13 | FastShiftIn::FastShiftIn(uint8_t dataIn, uint8_t clockPin, uint8_t bitOrder) 14 | { 15 | _bitOrder = bitOrder; 16 | _lastValue = 0; 17 | pinMode(dataIn, INPUT); 18 | pinMode(clockPin, OUTPUT); 19 | // https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftin/ 20 | digitalWrite(clockPin, LOW); // assume rising pulses from clock 21 | 22 | #if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) 23 | 24 | uint8_t _port = digitalPinToPort(dataIn); 25 | _dataInRegister = portInputRegister(_port); 26 | _dataInBit = digitalPinToBitMask(dataIn); 27 | 28 | _port = digitalPinToPort(clockPin); 29 | _clockRegister = portOutputRegister(_port); 30 | _clockBit = digitalPinToBitMask(clockPin); 31 | 32 | #else 33 | 34 | _dataPinIn = dataIn; 35 | _clockPin = clockPin; 36 | 37 | #endif 38 | 39 | } 40 | 41 | 42 | uint16_t FastShiftIn::read() 43 | { 44 | if (_bitOrder == LSBFIRST) 45 | { 46 | return readLSBFIRST(); 47 | } 48 | return readMSBFIRST(); 49 | } 50 | 51 | 52 | uint16_t FastShiftIn::read16() 53 | { 54 | if (_bitOrder == LSBFIRST) 55 | { 56 | uint16_t rv = readLSBFIRST(); 57 | rv += uint16_t(readLSBFIRST()) << 8; 58 | return rv; 59 | } 60 | uint16_t rv = readMSBFIRST(); 61 | rv <<= 8; 62 | rv += readMSBFIRST(); 63 | return rv; 64 | } 65 | 66 | 67 | uint32_t FastShiftIn::read24() 68 | { 69 | if (_bitOrder == LSBFIRST) 70 | { 71 | uint32_t rv = readLSBFIRST(); 72 | rv += uint32_t(readLSBFIRST()) << 8; 73 | rv += uint32_t(readLSBFIRST()) << 16; 74 | return rv; 75 | } 76 | uint32_t rv = readMSBFIRST(); 77 | rv <<= 8; 78 | rv += readMSBFIRST(); 79 | rv <<= 8; 80 | rv += readMSBFIRST(); 81 | return rv; 82 | } 83 | 84 | 85 | uint32_t FastShiftIn::read32() 86 | { 87 | if (_bitOrder == LSBFIRST) 88 | { 89 | uint32_t rv = readLSBFIRST(); 90 | rv += uint32_t(readLSBFIRST()) << 8; 91 | rv += uint32_t(readLSBFIRST()) << 16; 92 | rv += uint32_t(readLSBFIRST()) << 24; 93 | return rv; 94 | } 95 | uint32_t rv = readMSBFIRST(); 96 | rv <<= 8; 97 | rv += readMSBFIRST(); 98 | rv <<= 8; 99 | rv += readMSBFIRST(); 100 | rv <<= 8; 101 | rv += readMSBFIRST(); 102 | return rv; 103 | } 104 | 105 | 106 | uint32_t FastShiftIn::lastRead(void) 107 | { 108 | return _lastValue; 109 | } 110 | 111 | 112 | void FastShiftIn::read(uint8_t * array, uint8_t size) 113 | { 114 | if (_bitOrder == LSBFIRST) 115 | { 116 | for (uint8_t i = 0; i < size; i++) 117 | { 118 | array[size - i - 1] = readLSBFIRST(); 119 | } 120 | return; 121 | } 122 | for (uint8_t i = 0; i < size; i++) 123 | { 124 | array[i] = readMSBFIRST(); 125 | } 126 | return; 127 | } 128 | 129 | 130 | bool FastShiftIn::setBitOrder(const uint8_t bitOrder) 131 | { 132 | if ((bitOrder == LSBFIRST) || (bitOrder == MSBFIRST)) 133 | { 134 | _bitOrder = bitOrder; 135 | return true; 136 | }; 137 | return false; 138 | } 139 | 140 | 141 | uint8_t FastShiftIn::getBitOrder(void) 142 | { 143 | return _bitOrder; 144 | } 145 | 146 | 147 | uint8_t FastShiftIn::readLSBFIRST() 148 | { 149 | #if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) 150 | 151 | #if defined(FASTSHIFTIN_AVR_LOOP_UNROLLED) // AVR SPEED OPTIMIZED #17 152 | 153 | uint8_t rv = 0; 154 | uint8_t cbmask1 = _clockBit; 155 | uint8_t inmask1 = _dataInBit; 156 | 157 | volatile uint8_t* localDataInRegister = _dataInRegister; 158 | volatile uint8_t* localClockRegister = _clockRegister; 159 | 160 | // disable interrupts (for all bits) 161 | uint8_t oldSREG = SREG; 162 | noInterrupts(); 163 | 164 | uint8_t r = *localClockRegister; 165 | *localClockRegister |= cbmask1; // clock pulse HIGH 166 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x01; // read one bit 167 | *localClockRegister = r; // clock pulse LOW 168 | 169 | *localClockRegister |= cbmask1; // clock pulse HIGH 170 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x02; // read one bit 171 | *localClockRegister = r; // clock pulse LOW 172 | 173 | *localClockRegister |= cbmask1; // clock pulse HIGH 174 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x04; // read one bit 175 | *localClockRegister = r; // clock pulse LOW 176 | 177 | *localClockRegister |= cbmask1; // clock pulse HIGH 178 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x08; // read one bit 179 | *localClockRegister = r; // clock pulse LOW 180 | 181 | *localClockRegister |= cbmask1; // clock pulse HIGH 182 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x10; // read one bit 183 | *localClockRegister = r; // clock pulse LOW 184 | 185 | *localClockRegister |= cbmask1; // clock pulse HIGH 186 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x20; // read one bit 187 | *localClockRegister = r; // clock pulse LOW 188 | 189 | *localClockRegister |= cbmask1; // clock pulse HIGH 190 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x40; // read one bit 191 | *localClockRegister = r; // clock pulse LOW 192 | 193 | *localClockRegister |= cbmask1; // clock pulse HIGH 194 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x80; // read one bit 195 | *localClockRegister = r; // clock pulse LOW 196 | 197 | // restore interrupt state 198 | SREG = oldSREG; 199 | 200 | _lastValue = rv; 201 | 202 | #else // AVR SIZE OPTIMIZED 203 | 204 | uint8_t rv = 0; 205 | uint8_t cbmask1 = _clockBit; 206 | uint8_t inmask1 = _dataInBit; 207 | 208 | volatile uint8_t* localDataInRegister = _dataInRegister; 209 | volatile uint8_t* localClockRegister = _clockRegister; 210 | 211 | // disable interrupts (for all bits) 212 | uint8_t oldSREG = SREG; 213 | noInterrupts(); 214 | 215 | uint8_t r = *localClockRegister; 216 | 217 | for (uint8_t m = 0x01; m > 0; m <<= 1) 218 | { 219 | // clock pulse HIGH 220 | *localClockRegister |= cbmask1; 221 | // read one bit 222 | if ((*localDataInRegister & inmask1) > 0) rv |= m; 223 | // clock pulse LOW 224 | *localClockRegister = r; 225 | } 226 | 227 | // reset interrupts flag to previous state 228 | SREG = oldSREG; 229 | 230 | _lastValue = rv; 231 | 232 | #endif // if (AVR) 233 | 234 | #else // other platforms reference shiftOut() 235 | 236 | // reference implementation 237 | _lastValue = shiftIn(_dataPinIn, _clockPin, LSBFIRST); 238 | 239 | #endif 240 | 241 | // all paths will return _lastValue. 242 | return _lastValue; 243 | } 244 | 245 | 246 | uint8_t FastShiftIn::readMSBFIRST() 247 | { 248 | #if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) 249 | 250 | #if defined(FASTSHIFTIN_AVR_LOOP_UNROLLED) // AVR SPEED OPTIMIZED 251 | 252 | uint8_t rv = 0; 253 | uint8_t cbmask1 = _clockBit; 254 | uint8_t inmask1 = _dataInBit; 255 | 256 | volatile uint8_t* localDataInRegister = _dataInRegister; 257 | volatile uint8_t* localClockRegister = _clockRegister; 258 | 259 | // disable interrupts (for all bits) 260 | uint8_t oldSREG = SREG; 261 | noInterrupts(); 262 | 263 | uint8_t r = *localClockRegister; 264 | *localClockRegister |= cbmask1; // clock pulse HIGH 265 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x80; // read one bit 266 | *localClockRegister = r; // clock pulse LOW 267 | 268 | *localClockRegister |= cbmask1; // clock pulse HIGH 269 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x40; // read one bit 270 | *localClockRegister = r; // clock pulse LOW 271 | 272 | *localClockRegister |= cbmask1; // clock pulse HIGH 273 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x20; // read one bit 274 | *localClockRegister = r; // clock pulse LOW 275 | 276 | *localClockRegister |= cbmask1; // clock pulse HIGH 277 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x10; // read one bit 278 | *localClockRegister = r; // clock pulse LOW 279 | 280 | *localClockRegister |= cbmask1; // clock pulse HIGH 281 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x08; // read one bit 282 | *localClockRegister = r; // clock pulse LOW 283 | 284 | *localClockRegister |= cbmask1; // clock pulse HIGH 285 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x04; // read one bit 286 | *localClockRegister = r; // clock pulse LOW 287 | 288 | *localClockRegister |= cbmask1; // clock pulse HIGH 289 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x02; // read one bit 290 | *localClockRegister = r; // clock pulse LOW 291 | 292 | *localClockRegister |= cbmask1; // clock pulse HIGH 293 | if ((*localDataInRegister & inmask1) > 0) rv |= 0x01; // read one bit 294 | *localClockRegister = r; // clock pulse LOW 295 | 296 | // restore interrupt state 297 | SREG = oldSREG; 298 | 299 | _lastValue = rv; 300 | 301 | #else // AVR SIZE OPTIMIZED 302 | 303 | uint8_t rv = 0; 304 | uint8_t cbmask1 = _clockBit; 305 | uint8_t inmask1 = _dataInBit; 306 | 307 | volatile uint8_t* localDataInRegister = _dataInRegister; 308 | volatile uint8_t* localClockRegister = _clockRegister; 309 | 310 | // disable interrupts (for all bits) 311 | uint8_t oldSREG = SREG; 312 | noInterrupts(); 313 | 314 | uint8_t r = *localClockRegister; 315 | for (uint8_t m = 0x80; m > 0; m >>= 1) 316 | { 317 | // clock pulse HIGH 318 | *localClockRegister |= cbmask1; 319 | // read one bit 320 | if ((*localDataInRegister & inmask1) > 0) rv |= m; 321 | // clock pulse LOW 322 | *localClockRegister = r; 323 | } 324 | 325 | // reset interrupts flag to previous state 326 | SREG = oldSREG; 327 | 328 | _lastValue = rv; 329 | 330 | #endif // if (AVR) 331 | 332 | #else // other platforms reference shiftOut() 333 | 334 | // reference implementation 335 | _lastValue = shiftIn(_dataPinIn, _clockPin, MSBFIRST); 336 | 337 | #endif 338 | 339 | // all paths will return _lastValue. 340 | return _lastValue; 341 | } 342 | 343 | 344 | // -- END OF FILE -- 345 | 346 | -------------------------------------------------------------------------------- /FastShiftIn.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // 3 | // FILE: FastShiftIn.h 4 | // AUTHOR: Rob Tillaart 5 | // VERSION: 0.4.0 6 | // PURPOSE: Fast ShiftIn for 74HC165 register, AVR optimized 7 | // DATE: 2013-09-29 8 | // URL: https://github.com/RobTillaart/FastShiftIn 9 | 10 | 11 | #include "Arduino.h" 12 | 13 | 14 | #define FASTSHIFTIN_LIB_VERSION (F("0.4.0")) 15 | 16 | // uncomment next line to get SPEED OPTIMIZED CODE 17 | // #define FASTSHIFTIN_AVR_LOOP_UNROLLED 1 18 | 19 | class FastShiftIn 20 | { 21 | public: 22 | // bitOrder = { LSBFIRST, MSBFIRST }; 23 | FastShiftIn(uint8_t dataIn, uint8_t clockPin, uint8_t bitOrder = LSBFIRST); 24 | 25 | uint16_t read(void); 26 | uint16_t read16(void); 27 | uint32_t read24(void); 28 | uint32_t read32(void); 29 | uint32_t lastRead(void); 30 | 31 | // Experimental 0.3.4 32 | void read(uint8_t * array, uint8_t size); 33 | 34 | // returns false if bitOrder out of range. 35 | bool setBitOrder(uint8_t bitOrder); 36 | uint8_t getBitOrder(void); 37 | 38 | // overrule bitOrder (most optimized). 39 | uint8_t readLSBFIRST(void); 40 | uint8_t readMSBFIRST(void); 41 | 42 | private: 43 | uint8_t _bitOrder; 44 | uint32_t _lastValue; 45 | 46 | #if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) 47 | 48 | volatile uint8_t *_dataInRegister; 49 | uint8_t _dataInBit; 50 | 51 | volatile uint8_t *_clockRegister; 52 | uint8_t _clockBit; 53 | 54 | #else 55 | 56 | uint8_t _dataPinIn; 57 | uint8_t _clockPin; 58 | 59 | #endif 60 | }; 61 | 62 | 63 | // -- END OF FILE -- 64 | 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-2024 Rob Tillaart 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Arduino CI](https://github.com/RobTillaart/FastShiftIn/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci) 3 | [![Arduino-lint](https://github.com/RobTillaart/FastShiftIn/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/FastShiftIn/actions/workflows/arduino-lint.yml) 4 | [![JSON check](https://github.com/RobTillaart/FastShiftIn/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/FastShiftIn/actions/workflows/jsoncheck.yml) 5 | [![GitHub issues](https://img.shields.io/github/issues/RobTillaart/FastShiftIn.svg)](https://github.com/RobTillaart/FastShiftIn/issues) 6 | 7 | [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/FastShiftIn/blob/master/LICENSE) 8 | [![GitHub release](https://img.shields.io/github/release/RobTillaart/FastShiftIn.svg?maxAge=3600)](https://github.com/RobTillaart/FastShiftIn/releases) 9 | [![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/FastShiftIn.svg)](https://registry.platformio.org/libraries/robtillaart/FastShiftIn) 10 | 11 | 12 | # FastShiftIn 13 | 14 | Arduino library for **AVR** optimized shiftIn - e.g. for 74HC165. 15 | 16 | 17 | ## Description 18 | 19 | FastShiftIn is a class that has optimized code (AVR only) to shift in data faster 20 | than the default provided **shiftIn()** function. 21 | It speeds up the shift using low level ports and masks. These are predetermined 22 | in the constructor of the FastShiftIn object. 23 | 24 | If not an **ARDUINO_ARCH_AVR** or **ARDUINO_ARCH_MEGAAVR** the class falls back 25 | to the default **shiftIn()** implementation. 26 | 27 | The library allows to set (and get) the bitOrder and apply this to multiple read() 28 | calls. It also provide access to **readLSBFIRST()** and **readMSBFIRST()** which 29 | are the low level workers and most optimized code (so far). 30 | 31 | The library provides wrapper functions to read multi-byte variables. 32 | These are read16(), read24(), read32() and read(array, size). 33 | The latter is used to shift in any size object. 34 | 35 | 36 | ### 0.4.0 breaking changes 37 | 38 | The 0.4.0 version has a flag to unroll the inner loop in **readLSBFIRST()** 39 | and **readMSBFIRST()**. The AVR optimized code blocks the interrupts per byte. 40 | 41 | Note: this optimization is new and thus experimental. 42 | Feedback, including improvements, is welcome. 43 | 44 | 45 | ### Performance 46 | 47 | The performance of **read()** is substantially faster for **AVR** than the default 48 | Arduino **shiftIn()**, but not as fast as HW SPI. 49 | Exact how large the performance gain is can be seen with the example sketch. 50 | It does a comparison and shows how the class is to be used. 51 | 52 | 53 | #### Measurements 54 | 55 | Numbers may vary depending on bit-order flag. 56 | 57 | Indicative time in microseconds, Arduino UNO, IDE 1.8.19, measured over 1000 calls. 58 | 59 | | function | 0.2.3 | 0.3.2 | 0.4.0 | 0.4.0L | 60 | |:---------------------|---------:|---------:|---------:|---------:| 61 | | read() | 19.30 | 20.49 | 12.71 | 9.51 | 62 | | read16() | | 41.04 | 25.39 | 18.98 | 63 | | read24() | | 62.91 | 39.10 | 29.48 | 64 | | read32() | | 83.95 | 51.42 | 38.60 | 65 | | readLSBFIRST() | 19.04 | 19.92 | 11.96 | 8.81 | 66 | | readMSBFIRST() | 19.04 | 19.92 | 11.94 | 8.75 | 67 | | reference shiftIn() | 107.82 | 108.20 | 108.05 | 108.05 | 68 | 69 | 70 | - Note: 0.3.2 is a bit slower (incl. reference) than 0.2.3 but still much 71 | faster than the reference. (Older IDE?) 72 | - Note: 0.4.0 improved test sketch, 73 | - Note: 0.4.0 measured with loop unroll flag disabled. 74 | - Note: 0.4.0L measured with loop unrolled flag enabled. 75 | 76 | 77 | ### Related libraries 78 | 79 | - https://github.com/RobTillaart/FastShiftIn 80 | - https://github.com/RobTillaart/FastShiftInOut 81 | - https://github.com/RobTillaart/FastShiftOut 82 | - https://github.com/RobTillaart/ShiftInSlow 83 | - https://github.com/RobTillaart/ShiftOutSlow 84 | 85 | 86 | ## Interface 87 | 88 | ```cpp 89 | #include "FastShiftIn.h" 90 | ``` 91 | 92 | ### Constructor 93 | 94 | bitOrder = { LSBFIRST, MSBFIRST }; 95 | 96 | - **FastShiftIn(uint8_t dataIn, uint8_t clockPin, uint8_t bitOrder = LSBFIRST)** Constructor 97 | 98 | ### Functions 99 | 100 | - **uint16_t read(void)** reads a new value, 8 bit. 101 | - **uint16_t read16(void)** reads a new value, 16 bit. 102 | - **uint32_t read24(void)** reads a new value, 24 bit. 103 | - **uint32_t read32(void)** reads a new value, 32 bit. 104 | - **uint32_t lastRead()** returns last value read. 105 | - **uint16_t readLSBFIRST(void)** optimized LSB read(), 8 bit. 106 | - **uint16_t readMSBFIRST(void)** optimized MSB read(), 8 bit. 107 | 108 | 109 | ### BitOrder 110 | 111 | - **bool setBitOrder(uint8_t bitOrder)** set LSBFIRST or MSBFIRST. 112 | Returns false for other values ==> no change. 113 | - **uint8_t getBitOrder(void)** returns LSBFIRST or MSBFIRST as set in the constructor 114 | or latest set from **setBitOrder()**. 115 | 116 | 117 | ### Experimental 118 | 119 | - **void read(uint8_t \*array, uint8_t size)** read an array of values. 120 | The order in the array follows as BYTE order MSB / LSB, that is why this function 121 | is made experimental. This might change in the future, and fill the array 122 | in arrival order. 123 | 124 | 125 | ### Byte order 126 | 127 | The functions **read16()**, **read24()** and **read32()** of this library assume 128 | that the BIT-order is also the BYTE-order. 129 | This is not always the case as an n-byte element can have n! == factorial(n) 130 | distinct byte orders. 131 | 132 | So **read16()** can have two, **read24()** can have six and **read32()** can even have 133 | (in theory) 24 distinct byte orders. Although LSB and MSB are the most common, 134 | other byte orders exist, and sometimes one explicitly wants to reorder the bytes. 135 | 136 | If the BIT-order is not the BYTE-order, the user has two options 137 | - call **read()** multiple times and merge the bytes in the order needed. 138 | - call **read32()** (a.o) and reorder the bytes in a separate function. 139 | 140 | The library will not support such functionality. 141 | 142 | 143 | ## Notes 144 | 145 | - The optimizations are AVR only for now, other platforms may follow. 146 | - The 74HC165 needs 0.1uF caps and the data and clock lines may need 147 | pull up resistors, especially if wires are exceeding 10 cm (4"). 148 | 149 | 150 | ## Future 151 | 152 | #### Must 153 | 154 | - keep in sync with FastShiftOut() 155 | 156 | #### Should 157 | 158 | - extend unit tests 159 | 160 | #### Could 161 | 162 | - investigate ESP32 optimization readLSBFIRST readMSBFIRST 163 | - performance ESP32 164 | - example schema 165 | - add invert flag? 166 | - would it be interesting to make a fastShiftIn16() etc? 167 | - squeeze performance but more maintenance.? 168 | 169 | #### Wont 170 | 171 | - investigate separate **BYTE**-order, 172 | - only MSBFirst and LSBFirst 173 | - **void setByteOrder()** + **uint8_t getByteOrder()** 174 | - other option is add parameters / overload to make byte order explicit 175 | - **read32(1,0,3,2)** performance penalty + invalid combination. 176 | 177 | ## Support 178 | 179 | If you appreciate my libraries, you can support the development and maintenance. 180 | Improve the quality of the libraries by providing issues and Pull Requests, or 181 | donate through PayPal or GitHub sponsors. 182 | 183 | Thank you, 184 | -------------------------------------------------------------------------------- /examples/fastShiftIn/fastShiftIn.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: fastShiftIn.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: test sketch 5 | // URL: https://github.com/RobTillaart/FastShiftIn 6 | 7 | 8 | #include "FastShiftIn.h" 9 | 10 | FastShiftIn FSI(12, 13, LSBFIRST); 11 | 12 | volatile int x = 0; 13 | 14 | 15 | void setup() 16 | { 17 | Serial.begin(115200); 18 | Serial.println(__FILE__); 19 | Serial.println(FASTSHIFTIN_LIB_VERSION); 20 | 21 | digitalWrite(12, HIGH); 22 | Serial.println("\n 8 bits HIGH\n"); 23 | 24 | Serial.println("\nPerformance - time in us"); 25 | uint32_t start = micros(); 26 | for (int i = 0; i < 1000; i++) 27 | { 28 | x = FSI.read(); 29 | } 30 | uint32_t duration1 = micros() - start; 31 | Serial.print("FastShiftIn1: "); 32 | Serial.println(duration1 * 0.001); 33 | 34 | start = micros(); 35 | for (int i = 0; i < 1000; i++) 36 | { 37 | x = FSI.read(); 38 | x = FSI.read(); 39 | } 40 | uint32_t duration2 = micros() - start; 41 | Serial.print("FastShiftIn2: "); 42 | Serial.println(duration2 * 0.001); 43 | Serial.print(" Delta: "); 44 | Serial.println((duration2 - duration1)* 0.001); 45 | Serial.println(); 46 | 47 | 48 | start = micros(); 49 | for (int i = 0; i < 1000; i++) 50 | { 51 | x = shiftIn(12, 13, LSBFIRST); 52 | } 53 | duration1 = micros() - start; 54 | Serial.print("Standard shiftIn1: "); 55 | Serial.println(duration1* 0.001); 56 | 57 | start = micros(); 58 | for (int i = 0; i < 1000; i++) 59 | { 60 | x = shiftIn(12, 13, LSBFIRST); 61 | x = shiftIn(12, 13, LSBFIRST); 62 | } 63 | duration2 = micros() - start; 64 | Serial.print("Standard shiftIn2: "); 65 | Serial.println(duration2 * 0.001); 66 | Serial.print(" Delta: "); 67 | Serial.println((duration2 - duration1) * 0.001); 68 | Serial.println(); 69 | 70 | Serial.println("done..."); 71 | } 72 | 73 | 74 | void loop() 75 | { 76 | } 77 | 78 | 79 | // -- END OF FILE -- 80 | 81 | -------------------------------------------------------------------------------- /examples/fastShiftIn_readLSBFIRST/fastShiftIn_readLSBFIRST.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: fastShiftIn_readLSBFIRST.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: test sketch 5 | // URL: https://github.com/RobTillaart/FastShiftIn 6 | 7 | 8 | #include "FastShiftIn.h" 9 | 10 | FastShiftIn FSI(12, 13); 11 | 12 | volatile int x = 0; 13 | 14 | 15 | void setup() 16 | { 17 | Serial.begin(115200); 18 | Serial.println(__FILE__); 19 | Serial.println(FASTSHIFTIN_LIB_VERSION); 20 | 21 | digitalWrite(12, HIGH); 22 | Serial.println("\n 8 bits HIGH - readLSBFIRST\n"); 23 | 24 | Serial.println("\nPerformance - time in us"); 25 | uint32_t start = micros(); 26 | for (int i = 0; i < 1000; i++) 27 | { 28 | x = FSI.readLSBFIRST(); 29 | } 30 | uint32_t duration1 = micros() - start; 31 | Serial.print("FastShiftIn1: "); 32 | Serial.println(duration1 * 0.001); 33 | 34 | start = micros(); 35 | for (int i = 0; i < 1000; i++) 36 | { 37 | x = FSI.readLSBFIRST(); 38 | x = FSI.readLSBFIRST(); 39 | } 40 | uint32_t duration2 = micros() - start; 41 | Serial.print("FastShiftIn2: "); 42 | Serial.println(duration2 * 0.001); 43 | Serial.print(" Delta: "); 44 | Serial.println((duration2 - duration1) * 0.001); 45 | Serial.println(); 46 | 47 | 48 | start = micros(); 49 | for (int i = 0; i < 1000; i++) 50 | { 51 | x = shiftIn(12, 13, LSBFIRST); 52 | } 53 | duration1 = micros() - start; 54 | Serial.print("Standard shiftIn1: "); 55 | Serial.println(duration1 * 0.001); 56 | 57 | start = micros(); 58 | for (int i = 0; i < 1000; i++) 59 | { 60 | x = shiftIn(12, 13, LSBFIRST); 61 | x = shiftIn(12, 13, LSBFIRST); 62 | } 63 | duration2 = micros() - start; 64 | Serial.print("Standard shiftIn2: "); 65 | Serial.println(duration2 * 0.001); 66 | Serial.print(" Delta: "); 67 | Serial.println((duration2 - duration1) * 0.001); 68 | Serial.println(); 69 | 70 | Serial.println("done..."); 71 | } 72 | 73 | 74 | void loop() 75 | { 76 | } 77 | 78 | 79 | // -- END OF FILE -- 80 | -------------------------------------------------------------------------------- /examples/fastShiftIn_readMSBFIRST/fastShiftIn_readMSBFIRST.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: fastShiftIn_readMSBFIRST.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: test sketch 5 | // URL: https://github.com/RobTillaart/FastShiftIn 6 | 7 | 8 | #include "FastShiftIn.h" 9 | 10 | FastShiftIn FSI(12, 13); 11 | 12 | volatile int x = 0; 13 | 14 | 15 | void setup() 16 | { 17 | Serial.begin(115200); 18 | Serial.print("example fastShiftIn: "); 19 | Serial.println(FASTSHIFTIN_LIB_VERSION); 20 | 21 | digitalWrite(12, HIGH); 22 | Serial.println("\n 8 bits HIGH\n"); 23 | 24 | Serial.println("\nPerformance - time in us"); 25 | uint32_t start = micros(); 26 | for (int i = 0; i < 1000; i++) 27 | { 28 | x = FSI.readMSBFIRST(); 29 | } 30 | uint32_t duration1 = micros() - start; 31 | Serial.print("FastShiftIn1: "); 32 | Serial.println(duration1 * 0.001); 33 | 34 | start = micros(); 35 | for (int i = 0; i < 1000; i++) 36 | { 37 | x = FSI.readMSBFIRST(); 38 | x = FSI.readMSBFIRST(); 39 | } 40 | uint32_t duration2 = micros() - start; 41 | Serial.print("FastShiftIn2: "); 42 | Serial.println(duration2 * 0.001); 43 | Serial.print(" Delta: "); 44 | Serial.println((duration2 - duration1) * 0.001); 45 | Serial.println(); 46 | 47 | 48 | start = micros(); 49 | for (int i = 0; i < 1000; i++) 50 | { 51 | x = shiftIn(12, 13, MSBFIRST); 52 | } 53 | duration1 = micros() - start; 54 | Serial.print("Standard shiftIn1: "); 55 | Serial.println(duration1 * 0.001); 56 | 57 | start = micros(); 58 | for (int i = 0; i < 1000; i++) 59 | { 60 | x = shiftIn(12, 13, MSBFIRST); 61 | x = shiftIn(12, 13, MSBFIRST); 62 | } 63 | duration2 = micros() - start; 64 | Serial.print("Standard shiftIn2: "); 65 | Serial.println(duration2 * 0.001); 66 | Serial.print(" Delta: "); 67 | Serial.println((duration2 - duration1) * 0.001); 68 | Serial.println(); 69 | 70 | Serial.println("done..."); 71 | } 72 | 73 | 74 | void loop() 75 | { 76 | } 77 | 78 | 79 | // -- END OF FILE -- 80 | 81 | -------------------------------------------------------------------------------- /examples/fastShiftIn_test/fastShiftIn_test.ino: -------------------------------------------------------------------------------- 1 | // FILE: fastShiftIn_test.ino 2 | // AUTHOR: Rob Tillaart 3 | // PURPOSE: test sketch 4 | // URL: https://github.com/RobTillaart/FastShiftIn 5 | 6 | 7 | #include "FastShiftIn.h" 8 | 9 | FastShiftIn FSI(12, 13); 10 | 11 | volatile uint32_t x = 0; 12 | 13 | uint32_t start, duration1, duration2; 14 | 15 | 16 | void setup() 17 | { 18 | Serial.begin(115200); 19 | Serial.println(__FILE__); 20 | Serial.println(FASTSHIFTIN_LIB_VERSION); 21 | 22 | FSI.setBitOrder(MSBFIRST); 23 | 24 | digitalWrite(12, HIGH); 25 | Serial.println("\n 8 bits HIGH\n"); 26 | 27 | Serial.println("\nPerformance - time in us : read()"); 28 | test_read(); 29 | 30 | Serial.println("\nPerformance - time in us : read16()"); 31 | test_read16(); 32 | 33 | Serial.println("\nPerformance - time in us : read24()"); 34 | test_read24(); 35 | 36 | Serial.println("\nPerformance - time in us : read32()"); 37 | test_read32(); 38 | 39 | Serial.println("\nPerformance - time in us : readLSBFIRST()"); 40 | test_readLSBFIRST(); 41 | 42 | Serial.println("\nPerformance - time in us : readMSBFIRST()"); 43 | test_readMSBFIRST(); 44 | 45 | Serial.println("\nPerformance - time in us : reference shiftIn()"); 46 | test_reference(); 47 | 48 | Serial.println("done..."); 49 | } 50 | 51 | 52 | void test_read() 53 | { 54 | start = micros(); 55 | for (int i = 0; i < 1000; i++) 56 | { 57 | x = FSI.read(); 58 | } 59 | duration1 = micros() - start; 60 | Serial.print("FastShiftIn1: "); 61 | Serial.println(duration1 * 0.001); 62 | delay(100); 63 | 64 | start = micros(); 65 | for (int i = 0; i < 1000; i++) 66 | { 67 | x = FSI.read(); 68 | x = FSI.read(); 69 | } 70 | duration2 = micros() - start; 71 | Serial.print("FastShiftIn2: "); 72 | Serial.println(duration2 * 0.001); 73 | Serial.print(" Delta: "); 74 | Serial.println((duration2 - duration1) * 0.001); 75 | Serial.println(); 76 | delay(100); 77 | } 78 | 79 | 80 | void test_read16() 81 | { 82 | start = micros(); 83 | for (int i = 0; i < 1000; i++) 84 | { 85 | x = FSI.read16(); 86 | } 87 | duration1 = micros() - start; 88 | Serial.print("FastShiftIn1: "); 89 | Serial.println(duration1 * 0.001); 90 | delay(100); 91 | 92 | start = micros(); 93 | for (int i = 0; i < 1000; i++) 94 | { 95 | x = FSI.read16(); 96 | x = FSI.read16(); 97 | } 98 | duration2 = micros() - start; 99 | Serial.print("FastShiftIn2: "); 100 | Serial.println(duration2 * 0.001); 101 | Serial.print(" Delta: "); 102 | Serial.println((duration2 - duration1) * 0.001); 103 | Serial.println(); 104 | delay(100); 105 | } 106 | 107 | 108 | void test_read24() 109 | { 110 | start = micros(); 111 | for (int i = 0; i < 1000; i++) 112 | { 113 | x = FSI.read24(); 114 | } 115 | duration1 = micros() - start; 116 | Serial.print("FastShiftIn1: "); 117 | Serial.println(duration1 * 0.001); 118 | delay(100); 119 | 120 | start = micros(); 121 | for (int i = 0; i < 1000; i++) 122 | { 123 | x = FSI.read24(); 124 | x = FSI.read24(); 125 | } 126 | duration2 = micros() - start; 127 | Serial.print("FastShiftIn2: "); 128 | Serial.println(duration2 * 0.001); 129 | Serial.print(" Delta: "); 130 | Serial.println((duration2 - duration1) * 0.001); 131 | Serial.println(); 132 | delay(100); 133 | } 134 | 135 | 136 | void test_read32() 137 | { 138 | start = micros(); 139 | for (int i = 0; i < 1000; i++) 140 | { 141 | x = FSI.read32(); 142 | } 143 | duration1 = micros() - start; 144 | Serial.print("FastShiftIn1: "); 145 | Serial.println(duration1 * 0.001); 146 | delay(100); 147 | 148 | start = micros(); 149 | for (int i = 0; i < 1000; i++) 150 | { 151 | x = FSI.read32(); 152 | x = FSI.read32(); 153 | } 154 | duration2 = micros() - start; 155 | Serial.print("FastShiftIn2: "); 156 | Serial.println(duration2 * 0.001); 157 | Serial.print(" Delta: "); 158 | Serial.println((duration2 - duration1) * 0.001); 159 | Serial.println(); 160 | delay(100); 161 | } 162 | 163 | 164 | void test_readLSBFIRST() 165 | { 166 | start = micros(); 167 | for (int i = 0; i < 1000; i++) 168 | { 169 | x = FSI.readLSBFIRST(); 170 | } 171 | duration1 = micros() - start; 172 | Serial.print("FastShiftIn1: "); 173 | Serial.println(duration1 * 0.001); 174 | delay(100); 175 | 176 | start = micros(); 177 | for (int i = 0; i < 1000; i++) 178 | { 179 | x = FSI.readLSBFIRST(); 180 | x = FSI.readLSBFIRST(); 181 | } 182 | duration2 = micros() - start; 183 | Serial.print("FastShiftIn2: "); 184 | Serial.println(duration2 * 0.001); 185 | Serial.print(" Delta: "); 186 | Serial.println((duration2 - duration1) * 0.001); 187 | Serial.println(); 188 | delay(100); 189 | } 190 | 191 | 192 | void test_readMSBFIRST() 193 | { 194 | start = micros(); 195 | for (int i = 0; i < 1000; i++) 196 | { 197 | x = FSI.readMSBFIRST(); 198 | } 199 | duration1 = micros() - start; 200 | Serial.print("FastShiftIn1: "); 201 | Serial.println(duration1 * 0.001); 202 | delay(100); 203 | 204 | start = micros(); 205 | for (int i = 0; i < 1000; i++) 206 | { 207 | x = FSI.readMSBFIRST(); 208 | x = FSI.readMSBFIRST(); 209 | } 210 | duration2 = micros() - start; 211 | Serial.print("FastShiftIn2: "); 212 | Serial.println(duration2 * 0.001); 213 | Serial.print(" Delta: "); 214 | Serial.println((duration2 - duration1) * 0.001); 215 | Serial.println(); 216 | delay(100); 217 | } 218 | 219 | 220 | void test_reference() 221 | { 222 | start = micros(); 223 | for (int i = 0; i < 1000; i++) 224 | { 225 | x = shiftIn(12, 13, LSBFIRST); 226 | } 227 | duration1 = micros() - start; 228 | Serial.print("Standard shiftIn1: "); 229 | Serial.println(duration1 * 0.001); 230 | delay(100); 231 | 232 | start = micros(); 233 | for (int i = 0; i < 1000; i++) 234 | { 235 | x = shiftIn(12, 13, LSBFIRST); 236 | x = shiftIn(12, 13, LSBFIRST); 237 | } 238 | duration2 = micros() - start; 239 | Serial.print("Standard shiftIn2: "); 240 | Serial.println(duration2 * 0.001); 241 | Serial.print(" Delta: "); 242 | Serial.println((duration2 - duration1) * 0.001); 243 | Serial.println(); 244 | delay(100); 245 | } 246 | 247 | 248 | void loop() 249 | { 250 | } 251 | 252 | 253 | // -- END OF FILE -- 254 | -------------------------------------------------------------------------------- /examples/fastShiftIn_test/performance_0.2.3.txt: -------------------------------------------------------------------------------- 1 | Arduino UNO 2 | IDE 1.8.19 3 | 4 | fastShiftIn_test.ino 5 | 0.2.3 6 | 7 | 8 bits HIGH 8 | 9 | 10 | Performance - time in us : read() 11 | FastShiftIn1: 20.42 12 | FastShiftIn2: 39.72 13 | Delta: 19.30 14 | 15 | 16 | Performance - time in us : readLSBFIRST() 17 | FastShiftIn1: 19.80 18 | FastShiftIn2: 38.84 19 | Delta: 19.04 20 | 21 | 22 | Performance - time in us : readMSBFIRST() 23 | FastShiftIn1: 19.80 24 | FastShiftIn2: 38.84 25 | Delta: 19.04 26 | 27 | 28 | Performance - time in us : reference shiftIn() 29 | Standard shiftIn1: 108.61 30 | Standard shiftIn2: 216.43 31 | Delta: 107.82 32 | 33 | done... 34 | 35 | -------------------------------------------------------------------------------- /examples/fastShiftIn_test/performance_0.3.0.txt: -------------------------------------------------------------------------------- 1 | Arduino UNO 2 | IDE 1.8.19 3 | 4 | fastShiftIn_test.ino 5 | 0.3.0 6 | 7 | 8 bits HIGH 8 | 9 | 10 | Performance - time in us : read() 11 | FastShiftIn1: 20.42 12 | FastShiftIn2: 39.72 13 | Delta: 19.30 14 | 15 | 16 | Performance - time in us : readLSBFIRST() 17 | FastShiftIn1: 19.80 18 | FastShiftIn2: 38.84 19 | Delta: 19.04 20 | 21 | 22 | Performance - time in us : readMSBFIRST() 23 | FastShiftIn1: 19.80 24 | FastShiftIn2: 38.84 25 | Delta: 19.04 26 | 27 | 28 | Performance - time in us : reference shiftIn() 29 | Standard shiftIn1: 108.61 30 | Standard shiftIn2: 216.43 31 | Delta: 107.82 32 | 33 | done... 34 | -------------------------------------------------------------------------------- /examples/fastShiftIn_test/performance_0.3.2.txt: -------------------------------------------------------------------------------- 1 | Arduino UNO 2 | IDE 1.8.19 3 | 4 | fastShiftIn_test.ino 5 | 0.3.2 6 | 7 | 8 bits HIGH 8 | 9 | 10 | Performance - time in us : read() 11 | FastShiftIn1: 21.62 12 | FastShiftIn2: 42.11 13 | Delta: 20.49 14 | 15 | 16 | Performance - time in us : read16() 17 | FastShiftIn1: 41.70 18 | FastShiftIn2: 82.73 19 | Delta: 41.04 20 | 21 | 22 | Performance - time in us : read24() 23 | FastShiftIn1: 63.58 24 | FastShiftIn2: 126.49 25 | Delta: 62.91 26 | 27 | 28 | Performance - time in us : read32() 29 | FastShiftIn1: 83.95 30 | FastShiftIn2: 167.24 31 | Delta: 83.29 32 | 33 | 34 | Performance - time in us : readLSBFIRST() 35 | FastShiftIn1: 20.68 36 | FastShiftIn2: 40.61 37 | Delta: 19.93 38 | 39 | 40 | Performance - time in us : readMSBFIRST() 41 | FastShiftIn1: 20.68 42 | FastShiftIn2: 40.60 43 | Delta: 19.92 44 | 45 | 46 | Performance - time in us : reference shiftIn() 47 | Standard shiftIn1: 108.99 48 | Standard shiftIn2: 217.19 49 | Delta: 108.20 50 | -------------------------------------------------------------------------------- /examples/fastShiftIn_test/performance_0.4.0.txt: -------------------------------------------------------------------------------- 1 | Arduino UNO 2 | IDE 1.8.19 3 | 4 | fastShiftIn_test.ino 5 | 0.4.0 6 | 7 | 8 bits HIGH 8 | 9 | 10 | Performance - time in us : read() 11 | FastShiftIn1: 12.51 12 | FastShiftIn2: 23.77 13 | Delta: 11.26 14 | 15 | 16 | Performance - time in us : read16() 17 | FastShiftIn1: 23.28 18 | FastShiftIn2: 45.78 19 | Delta: 22.50 20 | 21 | 22 | Performance - time in us : read24() 23 | FastShiftIn1: 35.54 24 | FastShiftIn2: 70.30 25 | Delta: 34.76 26 | 27 | 28 | Performance - time in us : read32() 29 | FastShiftIn1: 46.41 30 | FastShiftIn2: 92.05 31 | Delta: 45.64 32 | 33 | 34 | Performance - time in us : readLSBFIRST() 35 | FastShiftIn1: 12.83 36 | FastShiftIn2: 24.77 37 | Delta: 11.94 38 | 39 | 40 | Performance - time in us : readMSBFIRST() 41 | FastShiftIn1: 11.38 42 | FastShiftIn2: 21.88 43 | Delta: 10.50 44 | 45 | 46 | Performance - time in us : reference shiftIn() 47 | Standard shiftIn1: 108.99 48 | Standard shiftIn2: 217.04 49 | Delta: 108.05 50 | 51 | done... -------------------------------------------------------------------------------- /examples/fastShiftIn_test_read/fastShiftIn_test_read.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: fastShiftIn_test_read.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: test sketch 5 | // URL: https://github.com/RobTillaart/FastShiftIn 6 | 7 | 8 | #include "FastShiftIn.h" 9 | 10 | FastShiftIn FSI(8, 9); 11 | 12 | 13 | void setup() 14 | { 15 | Serial.begin(115200); 16 | Serial.println(__FILE__); 17 | Serial.println(FASTSHIFTIN_LIB_VERSION); 18 | 19 | uint8_t x = FSI.read(); 20 | Serial.println(x, HEX); 21 | 22 | x = FSI.readLSBFIRST(); 23 | Serial.println(x, HEX); 24 | 25 | x = FSI.readMSBFIRST(); 26 | Serial.println(x, HEX); 27 | 28 | Serial.println("done..."); 29 | } 30 | 31 | 32 | void loop() 33 | { 34 | } 35 | 36 | 37 | // -- END OF FILE -- 38 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | # Syntax Colouring Map For FastShiftIn 2 | 3 | # Data types (KEYWORD1) 4 | FastShiftIn KEYWORD1 5 | 6 | 7 | # Methods and Functions (KEYWORD2) 8 | read KEYWORD2 9 | read16 KEYWORD2 10 | read24 KEYWORD2 11 | read32 KEYWORD2 12 | 13 | lastRead KEYWORD2 14 | 15 | setBitOrder KEYWORD2 16 | getBitOrder KEYWORD2 17 | 18 | readLSBFIRST KEYWORD2 19 | readMSBFIRST KEYWORD2 20 | 21 | 22 | # Constants (LITERAL1) 23 | FASTSHIFTIN_LIB_VERSION LITERAL1 24 | 25 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FastShiftIn", 3 | "keywords": "Shift, shiftIn, in, serial, fast, 74HC165", 4 | "description": "Arduino library for (AVR) optimized shiftIn - e.g. for 74HC165", 5 | "authors": 6 | [ 7 | { 8 | "name": "Rob Tillaart", 9 | "email": "Rob.Tillaart@gmail.com", 10 | "maintainer": true 11 | } 12 | ], 13 | "repository": 14 | { 15 | "type": "git", 16 | "url": "https://github.com/RobTillaart/FastShiftIn.git" 17 | }, 18 | "version": "0.4.0", 19 | "license": "MIT", 20 | "frameworks": "*", 21 | "platforms": "*", 22 | "headers": "FastShiftIn.h" 23 | } 24 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=FastShiftIn 2 | version=0.4.0 3 | author=Rob Tillaart 4 | maintainer=Rob Tillaart 5 | sentence=Arduino library for (AVR) optimized shiftIn - e.g. for 74HC165 6 | paragraph= 7 | category=Signal Input/Output 8 | url=https://github.com/RobTillaart/FastShiftIn 9 | architectures=* 10 | includes=FastShiftIn.h 11 | depends= 12 | -------------------------------------------------------------------------------- /performance.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | ============================== 4 | 5 | 2020-04-14 - tested IDE 1.8.12 6 | factor 5+ faster 7 | ----------------------------- 8 | 9 | example fastShiftIn: 0.2.0 10 | 11 | 8 bits HIGH 12 | 13 | 14 | Performance - time in us : read() 15 | FastShiftIn1: 20.43 16 | FastShiftIn2: 39.72 17 | Delta: 19.29 18 | 19 | 20 | Performance - time in us : readLSBFIRST() 21 | FastShiftIn1: 19.80 22 | FastShiftIn2: 38.84 23 | Delta: 19.04 24 | 25 | 26 | Performance - time in us : readMSBFIRST() 27 | FastShiftIn1: 19.80 28 | FastShiftIn2: 38.84 29 | Delta: 19.04 30 | 31 | 32 | Performance - time in us : reference shiftIn() 33 | Standard shiftIn1: 108.61 34 | Standard shiftIn2: 216.43 35 | Delta: 107.82 36 | 37 | done... 38 | 39 | ============================== 40 | 41 | tested IDE 1.8.12 42 | 43 | 2020-04-14 44 | 45 | example fastShiftIn: 0.1.5 46 | 47 | 8 bits HIGH 48 | 49 | 50 | Performance - time in us 51 | FastShiftIn1: 25.15 52 | FastShiftIn2: 49.15 53 | Delta: 24.00 54 | 55 | Standard shiftIn1: 108.51 56 | Standard shiftIn2: 216.43 57 | Delta: 107.92 58 | 59 | done... 60 | 61 | ============================== 62 | 63 | tested IDE 1.8.1 64 | 65 | 20-08-2017 66 | example fastShiftIn: 0.1.4 67 | 68 | 8 bits HIGH 69 | 70 | 71 | Performance - time in us 72 | FastShiftIn1: 25.64 73 | FastShiftIn2: 50.16 74 | Delta: 24.52 75 | 76 | Standard shiftIn1: 110.53 77 | Standard shiftIn2: 220.48 78 | Delta: 109.95 79 | 80 | done... 81 | 82 | ============================== 83 | 84 | 2017-4-27 85 | example fastShiftIn: 0.1.3 86 | 87 | 8 bits HIGH 88 | 89 | 90 | Performance - time in us 91 | FastShiftIn1: 31.31 92 | FastShiftIn2: 61.48 93 | Delta: 30.18 94 | 95 | Standard shiftIn1: 110.54 96 | Standard shiftIn2: 220.48 97 | Delta: 109.94 98 | 99 | done... 100 | 101 | ============================== 102 | 103 | example fastShiftIn: 0.1.01 104 | 105 | 8 bits HIGH 106 | 107 | 108 | Performance - time in us 109 | FastShiftIn1: 44.83 110 | FastShiftIn2: 88.52 111 | Delta: 43.70 112 | 113 | Standard shiftIn1: 110.54 114 | Standard shiftIn2: 220.49 115 | Delta: 109.95 116 | 117 | done... 118 | 119 | 120 | -------------------------------------------------------------------------------- /test/unit_test_001.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: unit_test_001.cpp 3 | // AUTHOR: Rob Tillaart 4 | // DATE: 2020-12-03 5 | // PURPOSE: unit tests for the FastShiftIn library 6 | // https://github.com/RobTillaart/FastShiftIn 7 | // https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md 8 | // 9 | 10 | // supported assertions 11 | // https://github.com/Arduino-CI/arduino_ci/blob/master/cpp/unittest/Assertion.h#L33-L42 12 | // ---------------------------- 13 | // assertEqual(expected, actual) 14 | // assertNotEqual(expected, actual) 15 | // assertLess(expected, actual) 16 | // assertMore(expected, actual) 17 | // assertLessOrEqual(expected, actual) 18 | // assertMoreOrEqual(expected, actual) 19 | // assertTrue(actual) 20 | // assertFalse(actual) 21 | // assertNull(actual) 22 | // assertNotNull(actual) 23 | 24 | #include 25 | 26 | 27 | #include "Arduino.h" 28 | #include "FastShiftIn.h" 29 | 30 | 31 | // PATCH FOR DUE & ZERO FOR UNIT TEST - https://github.com/Arduino-CI/arduino_ci/issues/252 32 | #if defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) 33 | // - due # ARDUINO_ARCH_SAM does not support shiftIn apparently 34 | // - zero # ARDUINO_ARCH_SAMD 35 | #endif 36 | 37 | 38 | unittest_setup() 39 | { 40 | fprintf(stderr, "FASTSHIFTIN_LIB_VERSION: %s\n", (char *) FASTSHIFTIN_LIB_VERSION); 41 | } 42 | 43 | 44 | unittest_teardown() 45 | { 46 | } 47 | 48 | 49 | unittest(test_constructor) 50 | { 51 | FastShiftIn FSI(12, 13); 52 | 53 | assertEqual(0, FSI.lastRead()); 54 | assertEqual(LSBFIRST, FSI.getBitOrder()); 55 | 56 | FSI.setBitOrder(MSBFIRST); 57 | assertEqual(MSBFIRST, FSI.getBitOrder()); 58 | } 59 | 60 | 61 | unittest(test_constructor_LSB) 62 | { 63 | FastShiftIn FSI(12, 13, LSBFIRST); 64 | 65 | assertEqual(0, FSI.lastRead()); 66 | assertEqual(LSBFIRST, FSI.getBitOrder()); 67 | 68 | FSI.setBitOrder(MSBFIRST); 69 | assertEqual(MSBFIRST, FSI.getBitOrder()); 70 | } 71 | 72 | 73 | unittest(test_constructor_MSB) 74 | { 75 | FastShiftIn FSI(12, 13, MSBFIRST); 76 | 77 | assertEqual(0, FSI.lastRead()); 78 | assertEqual(MSBFIRST, FSI.getBitOrder()); 79 | 80 | FSI.setBitOrder(LSBFIRST); 81 | assertEqual(LSBFIRST, FSI.getBitOrder()); 82 | } 83 | 84 | 85 | unittest(test_read) 86 | { 87 | FastShiftIn FSI(12, 13); 88 | 89 | // apparently needed... To be investigated someday ... 90 | #if defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) 91 | 92 | assertEqual(0, FSI.read()); 93 | assertEqual(0, FSI.readLSBFIRST()); 94 | assertEqual(0, FSI.readMSBFIRST()); 95 | 96 | #else // AVR 97 | 98 | assertEqual(255, FSI.read()); 99 | assertEqual(255, FSI.readLSBFIRST()); 100 | assertEqual(255, FSI.readMSBFIRST()); 101 | 102 | #endif 103 | } 104 | 105 | 106 | unittest_main() 107 | 108 | 109 | // -- END OF FILE -- 110 | 111 | --------------------------------------------------------------------------------