Skip to content

Commit 9ac57a7

Browse files
authored
Fix #13, add wrapper functions (#14)
- Fix #13, add wrapper functions - write16/24/32, write(array, size) - improved timing measurement in FastShiftOut_test.ino - update readme.md - minor edits
1 parent 8b73e15 commit 9ac57a7

File tree

8 files changed

+192
-67
lines changed

8 files changed

+192
-67
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

88

9-
## [0.3.2] - 2023-10-31
9+
## [0.3.3] - 2024-07-23
10+
- Fix #13, add wrapper functions
11+
- write16/24/32, write(array, size)
12+
- improved timing measurement in FastShiftOut_test.ino
1013
- update readme.md
14+
- minor edits
1115

16+
## [0.3.2] - 2023-10-31
17+
- update readme.md
1218

1319
## [0.3.1] - 2023-02-20
1420
- update readme.md

FastShiftOut.cpp

Lines changed: 91 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -47,28 +47,113 @@ size_t FastShiftOut::write(uint8_t data)
4747
}
4848

4949

50-
/* experimental
51-
size_t write(const uint8_t \*buffer, size_t size)
50+
// EXPERIMENTAL 0.3.3
51+
size_t FastShiftOut::write16(uint16_t data)
52+
{
53+
if (_bitOrder == LSBFIRST)
54+
{
55+
writeLSBFIRST(data & 0xFF);
56+
writeLSBFIRST(data >> 8);
57+
}
58+
else
59+
{
60+
writeMSBFIRST(data >> 8);
61+
writeMSBFIRST(data & 0xFF);
62+
}
63+
return 2;
64+
}
65+
66+
67+
// EXPERIMENTAL 0.3.3
68+
size_t FastShiftOut::write24(uint32_t data)
69+
{
70+
if (_bitOrder == LSBFIRST)
71+
{
72+
writeLSBFIRST(data & 0xFF);
73+
data >>= 8;
74+
writeLSBFIRST(data & 0xFF);
75+
data >>= 8;
76+
writeLSBFIRST(data & 0xFF);
77+
}
78+
else
79+
{
80+
writeMSBFIRST((data >> 16) & 0xFF);
81+
writeMSBFIRST((data >> 8) & 0xFF);
82+
writeMSBFIRST(data & 0xFF);
83+
}
84+
return 3;
85+
}
86+
87+
88+
// EXPERIMENTAL 0.3.3
89+
size_t FastShiftOut::write32(uint32_t data)
90+
{
91+
if (_bitOrder == LSBFIRST)
92+
{
93+
writeLSBFIRST(data & 0xFF);
94+
data >>= 8;
95+
writeLSBFIRST(data & 0xFF);
96+
data >>= 8;
97+
writeLSBFIRST(data & 0xFF);
98+
data >>= 8;
99+
writeLSBFIRST(data & 0xFF);
100+
}
101+
else
102+
{
103+
writeMSBFIRST((data >> 24) & 0xFF);
104+
writeMSBFIRST((data >> 16) & 0xFF);
105+
writeMSBFIRST((data >> 8) & 0xFF);
106+
writeMSBFIRST(data & 0xFF);
107+
}
108+
return 4;
109+
}
110+
111+
112+
// EXPERIMENTAL 0.3.3
113+
size_t FastShiftOut::write(uint8_t * array, size_t size)
52114
{
53115
size_t n = 0;
54116
if (_bitOrder == LSBFIRST)
55117
{
56118
for (size_t i = size; i > 0; ) // from end to begin ????
57119
{
58120
i--;
59-
n += writeLSBFIRST(buffer[i]);
121+
writeLSBFIRST(array[i]);
60122
}
61123
}
62124
else
63125
{
64126
for (size_t i = 0; i < size; i++) // from begin to end..
65127
{
66-
n += writeMSBFIRST(buffer[i]);
128+
writeMSBFIRST(array[i]);
67129
}
68130
}
69-
return n;
131+
return size;
70132
}
71-
*/
133+
134+
135+
uint8_t FastShiftOut::lastWritten(void)
136+
{
137+
return _lastValue;
138+
}
139+
140+
141+
bool FastShiftOut::setBitOrder(const uint8_t bitOrder)
142+
{
143+
if ((bitOrder == LSBFIRST) || (bitOrder == MSBFIRST))
144+
{
145+
_bitOrder = bitOrder;
146+
return true;
147+
};
148+
return false;
149+
}
150+
151+
152+
uint8_t FastShiftOut::getBitOrder(void)
153+
{
154+
return _bitOrder;
155+
}
156+
72157

73158

74159
size_t FastShiftOut::writeLSBFIRST(uint8_t data)
@@ -137,28 +222,5 @@ size_t FastShiftOut::writeMSBFIRST(uint8_t data)
137222
}
138223

139224

140-
uint8_t FastShiftOut::lastWritten(void)
141-
{
142-
return _lastValue;
143-
}
144-
145-
146-
bool FastShiftOut::setBitOrder(const uint8_t bitOrder)
147-
{
148-
if ((bitOrder == LSBFIRST) || (bitOrder == MSBFIRST))
149-
{
150-
_bitOrder = bitOrder;
151-
return true;
152-
};
153-
return false;
154-
}
155-
156-
157-
uint8_t FastShiftOut::getBitOrder(void)
158-
{
159-
return _bitOrder;
160-
}
161-
162-
163225
// -- END OF FILE --
164226

FastShiftOut.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// FILE: FastShiftOut.h
44
// AUTHOR: Rob Tillaart
5-
// VERSION: 0.3.2
5+
// VERSION: 0.3.3
66
// PURPOSE: shiftOut class that implements the Print interface
77
// DATE: 2013-08-22
88
// URL: https://github.com/RobTillaart/FastShiftOut
@@ -11,7 +11,7 @@
1111
#include "Arduino.h"
1212
#include "Print.h"
1313

14-
#define FASTSHIFTOUT_LIB_VERSION (F("0.3.2"))
14+
#define FASTSHIFTOUT_LIB_VERSION (F("0.3.3"))
1515

1616

1717
class FastShiftOut : public Print
@@ -21,14 +21,19 @@ class FastShiftOut : public Print
2121
FastShiftOut(uint8_t dataOut, uint8_t clockPin, uint8_t bitOrder = LSBFIRST);
2222

2323
size_t write(uint8_t data);
24-
// experimental
25-
// size_t write(const uint8_t \*buffer, size_t size);
2624
uint8_t lastWritten(void);
2725

26+
// EXPERIMENTAL (wrappers)
27+
size_t write16(uint16_t data);
28+
size_t write24(uint32_t data);
29+
size_t write32(uint32_t data);
30+
size_t write(uint8_t * array, size_t size);
31+
32+
// META
2833
bool setBitOrder(uint8_t bitOrder);
2934
uint8_t getBitOrder(void);
3035

31-
// overrule bitOrder (most optimized).
36+
// overrule bitOrder, most optimized.
3237
size_t writeLSBFIRST(uint8_t data);
3338
size_t writeMSBFIRST(uint8_t data);
3439

README.md

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,42 +13,56 @@
1313

1414
Arduino library for **AVR** optimized shiftOut - e.g. 74HC595.
1515

16-
Related libraries
17-
- https://github.com/RobTillaart/FastShiftIn
18-
- https://github.com/RobTillaart/FastShiftInOut
19-
- https://github.com/RobTillaart/ShiftInSlow
20-
- https://github.com/RobTillaart/ShiftOutSlow
21-
2216

2317
## Description
2418

25-
FastShiftOut is a class that has optimized code for AVR to shift out data faster
19+
FastShiftOut is a class that has optimized code (AVR only) to shift out data faster
2620
than the normal **shiftOut()** function.
2721
It speeds up the shift using low level ports and masks. These are predetermined
2822
in the constructor of the FastShiftOut object.
2923

3024
If not an **ARDUINO_ARCH_AVR** or **ARDUINO_ARCH_MEGAAVR** the class falls back
3125
to the default shiftOut() implementation.
3226

27+
The library allows to set (and get) the bitOrder and apply this to multiple write()
28+
calls. It also provide access to **writeLSBFIRST()** and **writeMSBFIRST()** which
29+
are the low level workers and most optimized code (so far).
30+
31+
The library provides wrapper functions to write multi-byte variables.
32+
These are write16(), write24(), write32() and write(array, size).
33+
The latter is used to shift out any size object.
34+
3335

34-
## Performance
36+
### Performance
3537

36-
The performance of **write()** is substantially faster than the default Arduino
37-
**shiftOut()**, but not as fast as HW SPI.
38-
Exact how big the performance gain is can be seen with the example sketch.
38+
The performance of **write()** is substantially faster for **AVR** than the default
39+
Arduino **shiftOut()**, but not as fast as HW SPI.
40+
Exact how large the performance gain is can be seen with the example sketch.
3941
It does a comparison and shows how the class is to be used.
4042

4143
Time in microseconds, Arduino UNO
4244

43-
| function | 0.2.4 | 0.3.1 |
44-
|:-------------------------|--------:|---------:|
45-
| write() | 21.66 | 22.48 |
46-
| writeLSBFIRST() | 22.94 | 23.37 |
47-
| writeMSBFIRST() | 20.30 | 21.86 |
48-
| reference shiftOut() | 89.74 | 89.74 |
49-
| println("Hello world") | | 328.92 |
50-
| println(1357) | | 313.56 |
51-
| println(3.14159265, 4) | | 717.36 |
45+
| function | 0.2.4 | 0.3.1 | 0.3.3 |
46+
|:-------------------------|--------:|---------:|---------:|
47+
| write() | 21.66 | 22.48 | 22.37 |
48+
| writeLSBFIRST() | 22.94 | 23.37 | 23.26 |
49+
| writeMSBFIRST() | 20.30 | 21.86 | 21.75 |
50+
| reference shiftOut() | 89.74 | 89.74 | 89.60 |
51+
| println("Hello world") | | 328.92 | 328.92 |
52+
| println(1357) | | 313.56 | 311.68 |
53+
| println(3.14159265, 4) | | 717.36 | 716.04 |
54+
55+
56+
Note: 0.3.3 has improved the measurement, not the code sec.
57+
58+
59+
### Related
60+
61+
- https://github.com/RobTillaart/FastShiftIn
62+
- https://github.com/RobTillaart/FastShiftInOut
63+
- https://github.com/RobTillaart/FastShiftOut
64+
- https://github.com/RobTillaart/ShiftInSlow
65+
- https://github.com/RobTillaart/ShiftOutSlow
5266

5367

5468
## Interface
@@ -57,27 +71,53 @@ Time in microseconds, Arduino UNO
5771
#include "FastShiftOut.h"
5872
```
5973

60-
#### Functions
74+
### Constructor
6175

6276
- **FastShiftOut(uint8_t dataOut, uint8_t clockPin, uint8_t bitOrder = LSBFIRST)** Constructor.
63-
- **size_t write(const uint8_t data)** send a byte, also the workhorse of the **Print** interface.
77+
78+
### Functions
79+
80+
- **size_t write(uint8_t data)** send a byte, also the workhorse of the **Print** interface.
81+
- **size_t write16(uint16_t data)** send 2 bytes.
82+
- **size_t write24(uint32_t data)** send 3 bytes.
83+
- **size_t write32(uint32_t data)** send 4 bytes.
84+
- **size_t write(uint8_t \*array, size_t size)** send size bytes.
6485
- **uint8_t lastWritten()** returns last byte written.
86+
87+
### Meta
88+
6589
- **bool setBitOrder(uint8_t bitOrder)** set LSBFIRST or MSBFIRST. Returns false for other values.
6690
- **uint8_t getBitOrder(void)** returns LSBFIRST or MSBFIRST.
67-
- **size_t writeLSBFIRST(const uint8_t data);** most optimized.
68-
- **size_t writeMSBFIRST(const uint8_t data);** most optimized.
91+
- **size_t writeLSBFIRST(uint8_t data)** most optimized.
92+
- **size_t writeMSBFIRST(uint8_t data)** most optimized.
6993

7094

7195
As a FastShiftOut object implements the Print interface, one can also call
7296

73-
- **FSO.print(any type);** or
74-
- **FSO.println(any type);**
97+
- **FSO.print(any type)** or
98+
- **FSO.println(any type)**
7599

76100
to send e.g. a float with 4 digits over the line, or some text string.
77101

78102
Note: **FSO.print()** returns the number of characters printed, including an optional \\r or \\n.
79103

80104

105+
### Byte order
106+
107+
The functions **write16()**, **write24()** and **write32()** of this library assume
108+
that the BIT-order is also the BYTE-order.
109+
This is not always the case as an n-byte element can have n! == factorial(n)
110+
distinct byte orders.
111+
112+
So **write16()** can have two, **write24()** can have six and **write32()** can even have
113+
(in theory) 24 distinct byte orders. Although LSB and MSB are the most common,
114+
other byte orders exist, and sometimes one explicitly wants to reorder the bytes.
115+
116+
If the BIT-order is not the BYTE-order, the user has two options
117+
- call **write()** multiple times and merge the bytes in the order needed.
118+
- call **write32()** (a.o) and reorder the bytes in a separate function.
119+
120+
81121
## Notes
82122

83123
- 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").
90130

91131
#### Must
92132

133+
- keep in sync with FastShiftIn()
134+
93135
#### Should
94136

95137
- extend unit tests
96138

97139
#### Could
98140

141+
- investigate separate **BYTE**-order,
142+
- only MSBFirst and LSBFirst
143+
- **void setByteOrder()** + **uint8_t getByteOrder()**
144+
- investigate ESP32 optimization readLSBFIRST readMSBFIRST
99145
- performance ESP32
100-
- check optimized ESP32
101-
- add **size_t write(const uint8_t \*buffer, size_t size)**
102146
- example schema
103147

104148
#### Wont

0 commit comments

Comments
 (0)