mirror of
https://github.com/adafruit/Adafruit-GFX-Library.git
synced 2026-10-26 22:10:52 +00:00
Add swapBytes() function, fix some longstanding endian issues in writePixels()
This commit is contained in:
1 parent
221bb41cd2
commit
c288843ec3
3 files changed
+61
-33
No files matched your search
+57
-32
@@ -949,6 +949,24 @@ void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Swap bytes in an array of pixels; converts little-to-big or
|
||||
big-to-little endian. Used by writePixels() below in some
|
||||
situations, but may also be helpful for user code occasionally.
|
||||
@param src Source address of 16-bit pixels buffer.
|
||||
@param len Number of pixels to byte-swap.
|
||||
@param dest Optional destination address if different than src --
|
||||
otherwise, if NULL (default) or same address is passed,
|
||||
pixel buffer is overwritten in-place.
|
||||
*/
|
||||
void swapBytes(uint16_t *src, uint32_t len, uint16_t *dest) {
|
||||
if (!dest)
|
||||
dest = src; // NULL -> overwrite src buffer
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
dest[i] = __builtin_bswap16(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Issue a series of pixels from memory to the display. Not self-
|
||||
contained; should follow startWrite() and setAddrWindow() calls.
|
||||
@@ -963,19 +981,16 @@ void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
doing ANY other display-related activities (or even
|
||||
any SPI-related activities, if using an SPI display
|
||||
that shares the bus with other devices).
|
||||
@param bigEndian If using DMA, and if set true, bitmap in memory is in
|
||||
big-endian order (most significant byte first). By
|
||||
default this is false, as most microcontrollers seem
|
||||
to be little-endian and 16-bit pixel values must be
|
||||
byte-swapped before issuing to the display (which tend
|
||||
to be big-endian when using SPI or 8-bit parallel).
|
||||
If an application can optimize around this -- for
|
||||
example, a bitmap in a uint16_t array having the byte
|
||||
values already reordered big-endian, this can save
|
||||
some processing time here, ESPECIALLY if using this
|
||||
function's non-blocking DMA mode. Not all cases are
|
||||
covered...this is really here only for SAMD DMA and
|
||||
much forethought on the application side.
|
||||
@param bigEndian If true, bitmap in memory is in big-endian order (most
|
||||
significant byte first). By default this is false, as
|
||||
most microcontrollers seem to be little-endian and
|
||||
16-bit pixel values must be byte-swapped before
|
||||
issuing to the display (which tend toward big-endian
|
||||
when using SPI or 8-bit parallel). If an application
|
||||
can optimize around this -- for example, a bitmap in a
|
||||
uint16_t array having the byte values already ordered
|
||||
big-endian, this can save time here, ESPECIALLY if
|
||||
using this function's non-blocking DMA mode.
|
||||
*/
|
||||
void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block,
|
||||
bool bigEndian) {
|
||||
@@ -987,28 +1002,23 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block,
|
||||
(void)block;
|
||||
(void)bigEndian;
|
||||
|
||||
#if defined(ESP32) // ESP32 has a special SPI pixel-writing function...
|
||||
#if defined(ESP32)
|
||||
if (connection == TFT_HARD_SPI) {
|
||||
hwspi._spi->writePixels(colors, len * 2);
|
||||
if (!bigEndian) {
|
||||
hwspi._spi->writePixels(colors, len * 2); // Inbuilt endian-swap
|
||||
} else {
|
||||
hwspi._spi->writeBytes(colors, len * 2); // Issue bytes direct
|
||||
}
|
||||
return;
|
||||
}
|
||||
#elif defined(ARDUINO_NRF52_ADAFRUIT) && \
|
||||
defined(NRF52840_XXAA) // Adafruit nRF52 use SPIM3 DMA at 32Mhz
|
||||
// TFT and SPI DMA endian is different we need to swap bytes
|
||||
if (!bigEndian) {
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
colors[i] = __builtin_bswap16(colors[i]);
|
||||
}
|
||||
byteSwap(colors, len); // convert little-to-big endian for display
|
||||
}
|
||||
|
||||
// use the separate tx, rx buf variant to prevent overwrite the buffer
|
||||
hwspi._spi->transfer(colors, NULL, 2 * len);
|
||||
|
||||
// swap back color buffer
|
||||
hwspi._spi->transfer(colors, NULL, 2 * len); // NULL RX to avoid overwrite
|
||||
if (!bigEndian) {
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
colors[i] = __builtin_bswap16(colors[i]);
|
||||
}
|
||||
byteSwap(colors, len); // big-to-little endian to restore pixel buffer
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1031,9 +1041,9 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block,
|
||||
// bytes from the 'colors' array passed into a DMA working
|
||||
// buffer. This can take place while the prior DMA transfer
|
||||
// is in progress, hence the need for two pixelBufs.
|
||||
for (int i = 0; i < count; i++) {
|
||||
pixelBuf[pixelBufIdx][i] = __builtin_bswap16(*colors++);
|
||||
}
|
||||
swapBytes(colors, count, pixelBuf[pixelBufIdx]);
|
||||
colors += count;
|
||||
|
||||
// The transfers themselves are relatively small, so we don't
|
||||
// need a long descriptor list. We just alternate between the
|
||||
// first two, sharing pixelBufIdx for that purpose.
|
||||
@@ -1106,8 +1116,22 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block,
|
||||
|
||||
// All other cases (bitbang SPI or non-DMA hard SPI or parallel),
|
||||
// use a loop with the normal 16-bit data write function:
|
||||
while (len--) {
|
||||
SPI_WRITE16(*colors++);
|
||||
|
||||
if (!bigEndian) {
|
||||
while (len--) {
|
||||
SPI_WRITE16(*colors++);
|
||||
}
|
||||
} else {
|
||||
// Well this is awkward. SPI_WRITE16() was designed for little-endian
|
||||
// hosts and big-endian displays as that's nearly always the typical
|
||||
// case. If the bigEndian flag was set, data is already in display's
|
||||
// order...so each pixel needs byte-swapping before being issued.
|
||||
// Rather than having a separate big-endian SPI_WRITE16 (adding more
|
||||
// bloat), it's preferred if calling function is smart and only uses
|
||||
// bigEndian where DMA is supported. But we gotta handle this...
|
||||
while (len--) {
|
||||
SPI_WRITE16(__builtin_bswap16(*colors++));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2362,6 +2386,7 @@ void Adafruit_SPITFT::SPI_WRITE16(uint16_t w) {
|
||||
#elif defined(ESP8266) || defined(ESP32)
|
||||
hwspi._spi->write16(w);
|
||||
#else
|
||||
// MSB, LSB because TFTs are generally big-endian
|
||||
hwspi._spi->transfer(w >> 8);
|
||||
hwspi._spi->transfer(w);
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user