Skip to content

Commit 605474e

Browse files
Add bigEndian flag to writePixels()
1 parent 5f38af1 commit 605474e

File tree

2 files changed

+83
-39
lines changed

2 files changed

+83
-39
lines changed

Adafruit_SPITFT.cpp

Lines changed: 81 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -864,19 +864,33 @@ void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
864864
/*!
865865
@brief Issue a series of pixels from memory to the display. Not self-
866866
contained; should follow startWrite() and setAddrWindow() calls.
867-
@param colors Pointer to array of 16-bit pixel values in '565' RGB
868-
format.
869-
@param len Number of elements in 'colors' array.
870-
@param block If true (default case if unspecified), function blocks
871-
until DMA transfer is complete. This is simply IGNORED
872-
if DMA is not enabled. If false, the function returns
873-
immediately after the last DMA transfer is started,
874-
and one should use the dmaWait() function before
875-
doing ANY other display-related activities (or even any
876-
SPI-related activities, if using an SPI display that
877-
shares the bus with other devices).
867+
@param colors Pointer to array of 16-bit pixel values in '565' RGB
868+
format.
869+
@param len Number of elements in 'colors' array.
870+
@param block If true (default case if unspecified), function blocks
871+
until DMA transfer is complete. This is simply IGNORED
872+
if DMA is not enabled. If false, the function returns
873+
immediately after the last DMA transfer is started,
874+
and one should use the dmaWait() function before
875+
doing ANY other display-related activities (or even
876+
any SPI-related activities, if using an SPI display
877+
that shares the bus with other devices).
878+
@param bigEndian If using DMA, and if set true, bitmap in memory is in
879+
big-endian order (most significant byte first). By
880+
default this is false, as most microcontrollers seem
881+
to be little-endian and 16-bit pixel values must be
882+
byte-swapped before issuing to the display (which tend
883+
to be big-endian when using SPI or 8-bit parallel).
884+
If an application can optimize around this -- for
885+
example, a bitmap in a uint16_t array having the byte
886+
values already reordered big-endian, this can save
887+
some processing time here, ESPECIALLY if using this
888+
function's non-blocking DMA mode. Not all cases are
889+
covered...this is really here only for SAMD DMA and
890+
much forethought on the application side.
878891
*/
879-
void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block) {
892+
void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len,
893+
bool block, bool bigEndian) {
880894

881895
if(!len) return; // Avoid 0-byte transfers
882896

@@ -895,36 +909,65 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block) {
895909
pinPeripheral(tft8._wr, wrPeripheral);
896910
}
897911
#endif // end __SAMD51__
898-
while(len) {
899-
int count = (len < maxSpan) ? len : maxSpan;
900-
901-
// Because TFT and SAMD endianisms are different, must swap bytes
902-
// from the 'colors' array passed into a DMA working buffer. This
903-
// can take place while the prior DMA transfer is in progress,
904-
// hence the need for two pixelBufs.
905-
for(int i=0; i<count; i++) {
906-
pixelBuf[pixelBufIdx][i] = __builtin_bswap16(*colors++);
912+
if(!bigEndian) { // Normal little-endian situation...
913+
while(len) {
914+
int count = (len < maxSpan) ? len : maxSpan;
915+
916+
// Because TFT and SAMD endianisms are different, must swap
917+
// bytes from the 'colors' array passed into a DMA working
918+
// buffer. This can take place while the prior DMA transfer
919+
// is in progress, hence the need for two pixelBufs.
920+
for(int i=0; i<count; i++) {
921+
pixelBuf[pixelBufIdx][i] = __builtin_bswap16(*colors++);
922+
}
923+
// The transfers themselves are relatively small, so we don't
924+
// need a long descriptor list. We just alternate between the
925+
// first two, sharing pixelBufIdx for that purpose.
926+
descriptor[pixelBufIdx].SRCADDR.reg =
927+
(uint32_t)pixelBuf[pixelBufIdx] + count * 2;
928+
descriptor[pixelBufIdx].BTCTRL.bit.SRCINC = 1;
929+
descriptor[pixelBufIdx].BTCNT.reg = count * 2;
930+
descriptor[pixelBufIdx].DESCADDR.reg = 0;
931+
932+
while(dma_busy); // Wait for prior line to finish
933+
934+
// Move new descriptor into place...
935+
memcpy(dptr, &descriptor[pixelBufIdx], sizeof(DmacDescriptor));
936+
dma_busy = true;
937+
dma.startJob(); // Trigger SPI DMA transfer
938+
if(connection == TFT_PARALLEL) dma.trigger();
939+
pixelBufIdx = 1 - pixelBufIdx; // Swap DMA pixel buffers
940+
941+
len -= count;
907942
}
908-
// The transfers themselves are relatively small, so we don't
909-
// need a long descriptor list. We just alternate between the
910-
// first two, sharing pixelBufIdx for that purpose.
911-
descriptor[pixelBufIdx].SRCADDR.reg =
912-
(uint32_t)pixelBuf[pixelBufIdx] + count * 2;
913-
descriptor[pixelBufIdx].BTCTRL.bit.SRCINC = 1;
914-
descriptor[pixelBufIdx].BTCNT.reg = count * 2;
915-
descriptor[pixelBufIdx].DESCADDR.reg = 0;
916-
917-
while(dma_busy); // Wait for prior line to finish
918-
919-
// Move new descriptor into place...
920-
memcpy(dptr, &descriptor[pixelBufIdx], sizeof(DmacDescriptor));
943+
} else { // bigEndian == true
944+
// With big-endian pixel data, this can be handled as a single
945+
// DMA transfer using chained descriptors. Even full screen, this
946+
// needs only a relatively short descriptor list, each
947+
// transferring a max of 32,767 (not 32,768) pixels. The list
948+
// was allocated large enough to accommodate a full screen's
949+
// worth of data, so this won't run past the end of the list.
950+
int d, numDescriptors = (len + 32766) / 32767;
951+
for(d=0; d<numDescriptors; d++) {
952+
int count = (len < 32767) ? len : 32767;
953+
descriptor[d].SRCADDR.reg = (uint32_t)colors;
954+
descriptor[d].BTCTRL.bit.SRCINC = 1;
955+
descriptor[d].BTCNT.reg = count * 2;
956+
descriptor[d].DESCADDR.reg = (uint32_t)&descriptor[d+1];
957+
len -= count;
958+
colors += count;
959+
}
960+
descriptor[d-1].DESCADDR.reg = 0;
961+
962+
while(dma_busy); // Wait for prior transfer (if any) to finish
963+
964+
// Move first descriptor into place and start transfer...
965+
memcpy(dptr, &descriptor[0], sizeof(DmacDescriptor));
921966
dma_busy = true;
922967
dma.startJob(); // Trigger SPI DMA transfer
923968
if(connection == TFT_PARALLEL) dma.trigger();
924-
pixelBufIdx = 1 - pixelBufIdx; // Swap DMA pixel buffers
969+
} // end bigEndian
925970

926-
len -= count;
927-
}
928971
lastFillColor = 0x0000; // pixelBuf has been sullied
929972
lastFillLen = 0;
930973
if(block) {
@@ -1006,7 +1049,7 @@ void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) {
10061049
#else // !ESP32
10071050
#if defined(USE_SPI_DMA)
10081051
if(((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) &&
1009-
(len >= 16)) { // DMA setup takes longer on short pixel runs
1052+
(len >= 16)) { // Don't bother with DMA on short pixel runs
10101053
int i, d, numDescriptors;
10111054
if(hi == lo) { // If high & low bytes are same...
10121055
onePixelBuf = color;

Adafruit_SPITFT.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ class Adafruit_SPITFT : public Adafruit_GFX {
195195
// before ending the transaction. It's more efficient than starting a
196196
// transaction every time.
197197
void writePixel(int16_t x, int16_t y, uint16_t color);
198-
void writePixels(uint16_t *colors, uint32_t len, bool block=true);
198+
void writePixels(uint16_t *colors, uint32_t len,
199+
bool block=true, bool bigEndian=false);
199200
void writeColor(uint16_t color, uint32_t len);
200201
void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
201202
uint16_t color);

0 commit comments

Comments
 (0)