Skip to content

Commit c288843

Browse files
Add swapBytes() function, fix some longstanding endian issues in writePixels()
1 parent 221bb41 commit c288843

File tree

3 files changed

+61
-33
lines changed

3 files changed

+61
-33
lines changed

Adafruit_SPITFT.cpp

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,24 @@ void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
949949
}
950950
}
951951

952+
/*!
953+
@brief Swap bytes in an array of pixels; converts little-to-big or
954+
big-to-little endian. Used by writePixels() below in some
955+
situations, but may also be helpful for user code occasionally.
956+
@param src Source address of 16-bit pixels buffer.
957+
@param len Number of pixels to byte-swap.
958+
@param dest Optional destination address if different than src --
959+
otherwise, if NULL (default) or same address is passed,
960+
pixel buffer is overwritten in-place.
961+
*/
962+
void swapBytes(uint16_t *src, uint32_t len, uint16_t *dest) {
963+
if (!dest)
964+
dest = src; // NULL -> overwrite src buffer
965+
for (uint32_t i = 0; i < len; i++) {
966+
dest[i] = __builtin_bswap16(src[i]);
967+
}
968+
}
969+
952970
/*!
953971
@brief Issue a series of pixels from memory to the display. Not self-
954972
contained; should follow startWrite() and setAddrWindow() calls.
@@ -963,19 +981,16 @@ void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
963981
doing ANY other display-related activities (or even
964982
any SPI-related activities, if using an SPI display
965983
that shares the bus with other devices).
966-
@param bigEndian If using DMA, and if set true, bitmap in memory is in
967-
big-endian order (most significant byte first). By
968-
default this is false, as most microcontrollers seem
969-
to be little-endian and 16-bit pixel values must be
970-
byte-swapped before issuing to the display (which tend
971-
to be big-endian when using SPI or 8-bit parallel).
972-
If an application can optimize around this -- for
973-
example, a bitmap in a uint16_t array having the byte
974-
values already reordered big-endian, this can save
975-
some processing time here, ESPECIALLY if using this
976-
function's non-blocking DMA mode. Not all cases are
977-
covered...this is really here only for SAMD DMA and
978-
much forethought on the application side.
984+
@param bigEndian If true, bitmap in memory is in big-endian order (most
985+
significant byte first). By default this is false, as
986+
most microcontrollers seem to be little-endian and
987+
16-bit pixel values must be byte-swapped before
988+
issuing to the display (which tend toward big-endian
989+
when using SPI or 8-bit parallel). If an application
990+
can optimize around this -- for example, a bitmap in a
991+
uint16_t array having the byte values already ordered
992+
big-endian, this can save time here, ESPECIALLY if
993+
using this function's non-blocking DMA mode.
979994
*/
980995
void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block,
981996
bool bigEndian) {
@@ -987,28 +1002,23 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block,
9871002
(void)block;
9881003
(void)bigEndian;
9891004

990-
#if defined(ESP32) // ESP32 has a special SPI pixel-writing function...
1005+
#if defined(ESP32)
9911006
if (connection == TFT_HARD_SPI) {
992-
hwspi._spi->writePixels(colors, len * 2);
1007+
if (!bigEndian) {
1008+
hwspi._spi->writePixels(colors, len * 2); // Inbuilt endian-swap
1009+
} else {
1010+
hwspi._spi->writeBytes(colors, len * 2); // Issue bytes direct
1011+
}
9931012
return;
9941013
}
9951014
#elif defined(ARDUINO_NRF52_ADAFRUIT) && \
9961015
defined(NRF52840_XXAA) // Adafruit nRF52 use SPIM3 DMA at 32Mhz
997-
// TFT and SPI DMA endian is different we need to swap bytes
9981016
if (!bigEndian) {
999-
for (uint32_t i = 0; i < len; i++) {
1000-
colors[i] = __builtin_bswap16(colors[i]);
1001-
}
1017+
byteSwap(colors, len); // convert little-to-big endian for display
10021018
}
1003-
1004-
// use the separate tx, rx buf variant to prevent overwrite the buffer
1005-
hwspi._spi->transfer(colors, NULL, 2 * len);
1006-
1007-
// swap back color buffer
1019+
hwspi._spi->transfer(colors, NULL, 2 * len); // NULL RX to avoid overwrite
10081020
if (!bigEndian) {
1009-
for (uint32_t i = 0; i < len; i++) {
1010-
colors[i] = __builtin_bswap16(colors[i]);
1011-
}
1021+
byteSwap(colors, len); // big-to-little endian to restore pixel buffer
10121022
}
10131023

10141024
return;
@@ -1031,9 +1041,9 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block,
10311041
// bytes from the 'colors' array passed into a DMA working
10321042
// buffer. This can take place while the prior DMA transfer
10331043
// is in progress, hence the need for two pixelBufs.
1034-
for (int i = 0; i < count; i++) {
1035-
pixelBuf[pixelBufIdx][i] = __builtin_bswap16(*colors++);
1036-
}
1044+
swapBytes(colors, count, pixelBuf[pixelBufIdx]);
1045+
colors += count;
1046+
10371047
// The transfers themselves are relatively small, so we don't
10381048
// need a long descriptor list. We just alternate between the
10391049
// first two, sharing pixelBufIdx for that purpose.
@@ -1106,8 +1116,22 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block,
11061116

11071117
// All other cases (bitbang SPI or non-DMA hard SPI or parallel),
11081118
// use a loop with the normal 16-bit data write function:
1109-
while (len--) {
1110-
SPI_WRITE16(*colors++);
1119+
1120+
if (!bigEndian) {
1121+
while (len--) {
1122+
SPI_WRITE16(*colors++);
1123+
}
1124+
} else {
1125+
// Well this is awkward. SPI_WRITE16() was designed for little-endian
1126+
// hosts and big-endian displays as that's nearly always the typical
1127+
// case. If the bigEndian flag was set, data is already in display's
1128+
// order...so each pixel needs byte-swapping before being issued.
1129+
// Rather than having a separate big-endian SPI_WRITE16 (adding more
1130+
// bloat), it's preferred if calling function is smart and only uses
1131+
// bigEndian where DMA is supported. But we gotta handle this...
1132+
while (len--) {
1133+
SPI_WRITE16(__builtin_bswap16(*colors++));
1134+
}
11111135
}
11121136
}
11131137

@@ -2362,6 +2386,7 @@ void Adafruit_SPITFT::SPI_WRITE16(uint16_t w) {
23622386
#elif defined(ESP8266) || defined(ESP32)
23632387
hwspi._spi->write16(w);
23642388
#else
2389+
// MSB, LSB because TFTs are generally big-endian
23652390
hwspi._spi->transfer(w >> 8);
23662391
hwspi._spi->transfer(w);
23672392
#endif

Adafruit_SPITFT.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ class Adafruit_SPITFT : public Adafruit_GFX {
232232
// Another new function, companion to the new non-blocking
233233
// writePixels() variant.
234234
void dmaWait(void);
235+
// Used by writePixels() in some situations, but might have rare need in
236+
// user code, so it's public...
237+
void swapBytes(uint16_t *src, uint32_t len, uint16_t *dest = NULL);
235238

236239
// These functions are similar to the 'write' functions above, but with
237240
// a chip-select and/or SPI transaction built-in. They're typically used

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Adafruit GFX Library
2-
version=1.10.7
2+
version=1.10.8
33
author=Adafruit
44
maintainer=Adafruit <[email protected]>
55
sentence=Adafruit GFX graphics core library, this is the 'core' class that all our other graphics libraries derive from.

0 commit comments

Comments
 (0)