From da2e9fe07724af4830a434d39c9dea31eb79c8db Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Tue, 23 Jul 2024 13:33:00 +0200 Subject: [PATCH] 0.3.3 FastShiftOut --- libraries/FastShiftOut/CHANGELOG.md | 8 +- .../FastShiftOut_test/FastShiftOut_test.ino | 9 +- libraries/FastShiftOut/FastShiftOut.cpp | 120 +++++++++++++----- libraries/FastShiftOut/FastShiftOut.h | 15 ++- libraries/FastShiftOut/README.md | 100 +++++++++++---- libraries/FastShiftOut/keywords.txt | 3 + libraries/FastShiftOut/library.json | 2 +- libraries/FastShiftOut/library.properties | 2 +- 8 files changed, 192 insertions(+), 67 deletions(-) diff --git a/libraries/FastShiftOut/CHANGELOG.md b/libraries/FastShiftOut/CHANGELOG.md index 64a3863e..643d3b01 100644 --- a/libraries/FastShiftOut/CHANGELOG.md +++ b/libraries/FastShiftOut/CHANGELOG.md @@ -6,10 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.3.3] - 2024-07-23 +- Fix #13, add wrapper functions + - write16/24/32, write(array, size) +- improved timing measurement in FastShiftOut_test.ino +- update readme.md +- minor edits + ## [0.3.2] - 2023-10-31 - update readme.md - ## [0.3.1] - 2023-02-20 - update readme.md - update GitHub actions diff --git a/libraries/FastShiftOut/Examples/FastShiftOut_test/FastShiftOut_test.ino b/libraries/FastShiftOut/Examples/FastShiftOut_test/FastShiftOut_test.ino index f5d16584..66949008 100644 --- a/libraries/FastShiftOut/Examples/FastShiftOut_test/FastShiftOut_test.ino +++ b/libraries/FastShiftOut/Examples/FastShiftOut_test/FastShiftOut_test.ino @@ -39,6 +39,7 @@ void test1() duration1 = micros() - start; Serial.print(" write: "); Serial.println(duration1 * 0.001); + delay(100); start = micros(); for (int i = 0; i < 1000; i++) @@ -66,6 +67,7 @@ void test2() duration1 = micros() - start; Serial.print("writeLSBFIRST: "); Serial.println(duration1 * 0.001); + delay(100); start = micros(); for (int i = 0; i < 1000; i++) @@ -93,6 +95,7 @@ void test3() duration1 = micros() - start; Serial.print("writeMSBFIRST: "); Serial.println(duration1 * 0.001); + delay(100); start = micros(); for (int i = 0; i < 1000; i++) @@ -120,6 +123,7 @@ void test4() duration1 = micros() - start; Serial.print("Standard shiftOut1: "); Serial.println(duration1 * 0.001); + delay(100); start = micros(); for (int i = 0; i < 1000; i++) @@ -148,6 +152,7 @@ void test5() duration1 = micros() - start; Serial.print("println(\"Hello world\"): \t"); Serial.println(duration1 * 0.01); + delay(100); start = micros(); for (int i = 0; i < 100; i++) @@ -157,7 +162,7 @@ void test5() duration1 = micros() - start; Serial.print("println(1357): \t\t\t"); Serial.println(duration1 * 0.01); - + delay(100); start = micros(); for (int i = 0; i < 100; i++) @@ -176,4 +181,4 @@ void loop() } -// -- END OF FILE -- \ No newline at end of file +// -- END OF FILE -- diff --git a/libraries/FastShiftOut/FastShiftOut.cpp b/libraries/FastShiftOut/FastShiftOut.cpp index 48af253e..e4a2ee07 100644 --- a/libraries/FastShiftOut/FastShiftOut.cpp +++ b/libraries/FastShiftOut/FastShiftOut.cpp @@ -47,8 +47,70 @@ size_t FastShiftOut::write(uint8_t data) } -/* experimental -size_t write(const uint8_t \*buffer, size_t size) +// EXPERIMENTAL 0.3.3 +size_t FastShiftOut::write16(uint16_t data) +{ + if (_bitOrder == LSBFIRST) + { + writeLSBFIRST(data & 0xFF); + writeLSBFIRST(data >> 8); + } + else + { + writeMSBFIRST(data >> 8); + writeMSBFIRST(data & 0xFF); + } + return 2; +} + + +// EXPERIMENTAL 0.3.3 +size_t FastShiftOut::write24(uint32_t data) +{ + if (_bitOrder == LSBFIRST) + { + writeLSBFIRST(data & 0xFF); + data >>= 8; + writeLSBFIRST(data & 0xFF); + data >>= 8; + writeLSBFIRST(data & 0xFF); + } + else + { + writeMSBFIRST((data >> 16) & 0xFF); + writeMSBFIRST((data >> 8) & 0xFF); + writeMSBFIRST(data & 0xFF); + } + return 3; +} + + +// EXPERIMENTAL 0.3.3 +size_t FastShiftOut::write32(uint32_t data) +{ + if (_bitOrder == LSBFIRST) + { + writeLSBFIRST(data & 0xFF); + data >>= 8; + writeLSBFIRST(data & 0xFF); + data >>= 8; + writeLSBFIRST(data & 0xFF); + data >>= 8; + writeLSBFIRST(data & 0xFF); + } + else + { + writeMSBFIRST((data >> 24) & 0xFF); + writeMSBFIRST((data >> 16) & 0xFF); + writeMSBFIRST((data >> 8) & 0xFF); + writeMSBFIRST(data & 0xFF); + } + return 4; +} + + +// EXPERIMENTAL 0.3.3 +size_t FastShiftOut::write(uint8_t * array, size_t size) { size_t n = 0; if (_bitOrder == LSBFIRST) @@ -56,19 +118,42 @@ size_t write(const uint8_t \*buffer, size_t size) for (size_t i = size; i > 0; ) // from end to begin ???? { i--; - n += writeLSBFIRST(buffer[i]); + writeLSBFIRST(array[i]); } } else { for (size_t i = 0; i < size; i++) // from begin to end.. { - n += writeMSBFIRST(buffer[i]); + writeMSBFIRST(array[i]); } } - return n; + return size; } -*/ + + +uint8_t FastShiftOut::lastWritten(void) +{ + return _lastValue; +} + + +bool FastShiftOut::setBitOrder(const uint8_t bitOrder) +{ + if ((bitOrder == LSBFIRST) || (bitOrder == MSBFIRST)) + { + _bitOrder = bitOrder; + return true; + }; + return false; +} + + +uint8_t FastShiftOut::getBitOrder(void) +{ + return _bitOrder; +} + size_t FastShiftOut::writeLSBFIRST(uint8_t data) @@ -137,28 +222,5 @@ size_t FastShiftOut::writeMSBFIRST(uint8_t data) } -uint8_t FastShiftOut::lastWritten(void) -{ - return _lastValue; -} - - -bool FastShiftOut::setBitOrder(const uint8_t bitOrder) -{ - if ((bitOrder == LSBFIRST) || (bitOrder == MSBFIRST)) - { - _bitOrder = bitOrder; - return true; - }; - return false; -} - - -uint8_t FastShiftOut::getBitOrder(void) -{ - return _bitOrder; -} - - // -- END OF FILE -- diff --git a/libraries/FastShiftOut/FastShiftOut.h b/libraries/FastShiftOut/FastShiftOut.h index dc97e84c..255c2d15 100644 --- a/libraries/FastShiftOut/FastShiftOut.h +++ b/libraries/FastShiftOut/FastShiftOut.h @@ -2,7 +2,7 @@ // // FILE: FastShiftOut.h // AUTHOR: Rob Tillaart -// VERSION: 0.3.2 +// VERSION: 0.3.3 // PURPOSE: shiftOut class that implements the Print interface // DATE: 2013-08-22 // URL: https://github.com/RobTillaart/FastShiftOut @@ -11,7 +11,7 @@ #include "Arduino.h" #include "Print.h" -#define FASTSHIFTOUT_LIB_VERSION (F("0.3.2")) +#define FASTSHIFTOUT_LIB_VERSION (F("0.3.3")) class FastShiftOut : public Print @@ -21,14 +21,19 @@ public: FastShiftOut(uint8_t dataOut, uint8_t clockPin, uint8_t bitOrder = LSBFIRST); size_t write(uint8_t data); - // experimental - // size_t write(const uint8_t \*buffer, size_t size); uint8_t lastWritten(void); + // EXPERIMENTAL (wrappers) + size_t write16(uint16_t data); + size_t write24(uint32_t data); + size_t write32(uint32_t data); + size_t write(uint8_t * array, size_t size); + + // META bool setBitOrder(uint8_t bitOrder); uint8_t getBitOrder(void); - // overrule bitOrder (most optimized). + // overrule bitOrder, most optimized. size_t writeLSBFIRST(uint8_t data); size_t writeMSBFIRST(uint8_t data); diff --git a/libraries/FastShiftOut/README.md b/libraries/FastShiftOut/README.md index cdfe6fb4..68237acc 100644 --- a/libraries/FastShiftOut/README.md +++ b/libraries/FastShiftOut/README.md @@ -13,16 +13,10 @@ Arduino library for **AVR** optimized shiftOut - e.g. 74HC595. -Related libraries -- https://github.com/RobTillaart/FastShiftIn -- https://github.com/RobTillaart/FastShiftInOut -- https://github.com/RobTillaart/ShiftInSlow -- https://github.com/RobTillaart/ShiftOutSlow - ## Description -FastShiftOut is a class that has optimized code for AVR to shift out data faster +FastShiftOut is a class that has optimized code (AVR only) to shift out data faster than the normal **shiftOut()** function. It speeds up the shift using low level ports and masks. These are predetermined in the constructor of the FastShiftOut object. @@ -30,25 +24,45 @@ in the constructor of the FastShiftOut object. If not an **ARDUINO_ARCH_AVR** or **ARDUINO_ARCH_MEGAAVR** the class falls back to the default shiftOut() implementation. +The library allows to set (and get) the bitOrder and apply this to multiple write() +calls. It also provide access to **writeLSBFIRST()** and **writeMSBFIRST()** which +are the low level workers and most optimized code (so far). -## Performance +The library provides wrapper functions to write multi-byte variables. +These are write16(), write24(), write32() and write(array, size). +The latter is used to shift out any size object. -The performance of **write()** is substantially faster than the default Arduino -**shiftOut()**, but not as fast as HW SPI. -Exact how big the performance gain is can be seen with the example sketch. + +### Performance + +The performance of **write()** is substantially faster for **AVR** than the default +Arduino **shiftOut()**, but not as fast as HW SPI. +Exact how large the performance gain is can be seen with the example sketch. It does a comparison and shows how the class is to be used. Time in microseconds, Arduino UNO -| function | 0.2.4 | 0.3.1 | -|:-------------------------|--------:|---------:| -| write() | 21.66 | 22.48 | -| writeLSBFIRST() | 22.94 | 23.37 | -| writeMSBFIRST() | 20.30 | 21.86 | -| reference shiftOut() | 89.74 | 89.74 | -| println("Hello world") | | 328.92 | -| println(1357) | | 313.56 | -| println(3.14159265, 4) | | 717.36 | +| function | 0.2.4 | 0.3.1 | 0.3.3 | +|:-------------------------|--------:|---------:|---------:| +| write() | 21.66 | 22.48 | 22.37 | +| writeLSBFIRST() | 22.94 | 23.37 | 23.26 | +| writeMSBFIRST() | 20.30 | 21.86 | 21.75 | +| reference shiftOut() | 89.74 | 89.74 | 89.60 | +| println("Hello world") | | 328.92 | 328.92 | +| println(1357) | | 313.56 | 311.68 | +| println(3.14159265, 4) | | 717.36 | 716.04 | + + +Note: 0.3.3 has improved the measurement, not the code sec. + + +### Related + +- https://github.com/RobTillaart/FastShiftIn +- https://github.com/RobTillaart/FastShiftInOut +- https://github.com/RobTillaart/FastShiftOut +- https://github.com/RobTillaart/ShiftInSlow +- https://github.com/RobTillaart/ShiftOutSlow ## Interface @@ -57,27 +71,53 @@ Time in microseconds, Arduino UNO #include "FastShiftOut.h" ``` -#### Functions +### Constructor - **FastShiftOut(uint8_t dataOut, uint8_t clockPin, uint8_t bitOrder = LSBFIRST)** Constructor. -- **size_t write(const uint8_t data)** send a byte, also the workhorse of the **Print** interface. + +### Functions + +- **size_t write(uint8_t data)** send a byte, also the workhorse of the **Print** interface. +- **size_t write16(uint16_t data)** send 2 bytes. +- **size_t write24(uint32_t data)** send 3 bytes. +- **size_t write32(uint32_t data)** send 4 bytes. +- **size_t write(uint8_t \*array, size_t size)** send size bytes. - **uint8_t lastWritten()** returns last byte written. + +### Meta + - **bool setBitOrder(uint8_t bitOrder)** set LSBFIRST or MSBFIRST. Returns false for other values. - **uint8_t getBitOrder(void)** returns LSBFIRST or MSBFIRST. -- **size_t writeLSBFIRST(const uint8_t data);** most optimized. -- **size_t writeMSBFIRST(const uint8_t data);** most optimized. +- **size_t writeLSBFIRST(uint8_t data)** most optimized. +- **size_t writeMSBFIRST(uint8_t data)** most optimized. As a FastShiftOut object implements the Print interface, one can also call -- **FSO.print(any type);** or -- **FSO.println(any type);** +- **FSO.print(any type)** or +- **FSO.println(any type)** to send e.g. a float with 4 digits over the line, or some text string. Note: **FSO.print()** returns the number of characters printed, including an optional \\r or \\n. +### Byte order + +The functions **write16()**, **write24()** and **write32()** of this library assume +that the BIT-order is also the BYTE-order. +This is not always the case as an n-byte element can have n! == factorial(n) +distinct byte orders. + +So **write16()** can have two, **write24()** can have six and **write32()** can even have +(in theory) 24 distinct byte orders. Although LSB and MSB are the most common, +other byte orders exist, and sometimes one explicitly wants to reorder the bytes. + +If the BIT-order is not the BYTE-order, the user has two options +- call **write()** multiple times and merge the bytes in the order needed. +- call **write32()** (a.o) and reorder the bytes in a separate function. + + ## Notes - The optimizations are AVR only for now, other platforms may follow. @@ -90,15 +130,19 @@ pull up resistors, especially if wires are exceeding 10 cm (4"). #### Must +- keep in sync with FastShiftIn() + #### Should - extend unit tests #### Could +- investigate separate **BYTE**-order, + - only MSBFirst and LSBFirst + - **void setByteOrder()** + **uint8_t getByteOrder()** +- investigate ESP32 optimization readLSBFIRST readMSBFIRST - performance ESP32 -- check optimized ESP32 -- add **size_t write(const uint8_t \*buffer, size_t size)** - example schema #### Wont diff --git a/libraries/FastShiftOut/keywords.txt b/libraries/FastShiftOut/keywords.txt index f77937af..dd613848 100644 --- a/libraries/FastShiftOut/keywords.txt +++ b/libraries/FastShiftOut/keywords.txt @@ -6,6 +6,9 @@ FastShiftOut KEYWORD1 # Methods and Functions (KEYWORD2) write KEYWORD2 +write16 KEYWORD2 +write24 KEYWORD2 +write32 KEYWORD2 lastWritten KEYWORD2 diff --git a/libraries/FastShiftOut/library.json b/libraries/FastShiftOut/library.json index 5e478e07..f6fa9375 100644 --- a/libraries/FastShiftOut/library.json +++ b/libraries/FastShiftOut/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/FastShiftOut.git" }, - "version": "0.3.2", + "version": "0.3.3", "license": "MIT", "frameworks": "*", "platforms": "*", diff --git a/libraries/FastShiftOut/library.properties b/libraries/FastShiftOut/library.properties index 7eff64f9..cb70a83d 100644 --- a/libraries/FastShiftOut/library.properties +++ b/libraries/FastShiftOut/library.properties @@ -1,5 +1,5 @@ name=FastShiftOut -version=0.3.2 +version=0.3.3 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for (AVR) optimized shiftOut - e.g. 74HC595