@@ -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;
0 commit comments