@@ -455,40 +455,43 @@ void Adafruit_SPITFT::pushColor(uint16_t color) {
455455/* *************************************************************************/
456456void Adafruit_SPITFT::writePixels (uint16_t *colors, uint32_t len) {
457457#ifdef USE_SPI_DMA
458- int maxSpan = maxFillLen / 2 ; // One scanline max
459- uint8_t pixelBufIdx = 0 ; // Active pixel buffer number
460- while (len) {
461- int count = (len < maxSpan) ? len : maxSpan;
462-
463- // Because TFT and SAMD endianisms are different, must swap bytes
464- // from the 'colors' array passed into a DMA working buffer. This
465- // can take place while the prior DMA transfer is in progress,
466- // hence the need for two pixelBufs.
467- for (int i=0 ; i<count; i++) {
468- pixelBuf[pixelBufIdx][i] = __builtin_bswap16 (*colors++);
469- }
470- // The transfers themselves are relatively small, so we don't
471- // need a long descriptor list. We just alternate between the
472- // first two, sharing pixelBufIdx for that purpose.
473- descriptor[pixelBufIdx].SRCADDR .reg =
474- (uint32_t )pixelBuf[pixelBufIdx] + count * 2 ;
475- descriptor[pixelBufIdx].BTCTRL .bit .SRCINC = 1 ;
476- descriptor[pixelBufIdx].BTCNT .reg = count * 2 ;
477- descriptor[pixelBufIdx].DESCADDR .reg = 0 ;
478-
479- while (dma_busy); // wait for prior line to complete
480-
481- // Move new descriptor into place...
482- memcpy (dptr, &descriptor[pixelBufIdx], sizeof (DmacDescriptor));
483- dma_busy = true ;
484- dma.startJob (); // Trigger SPI DMA transfer
485- pixelBufIdx = 1 - pixelBufIdx; // Swap DMA pixel buffers
458+ if (_sclk < 0 ) { // using hardware SPI?
459+ int maxSpan = maxFillLen / 2 ; // One scanline max
460+ uint8_t pixelBufIdx = 0 ; // Active pixel buffer number
461+ while (len) {
462+ int count = (len < maxSpan) ? len : maxSpan;
463+
464+ // Because TFT and SAMD endianisms are different, must swap bytes
465+ // from the 'colors' array passed into a DMA working buffer. This
466+ // can take place while the prior DMA transfer is in progress,
467+ // hence the need for two pixelBufs.
468+ for (int i=0 ; i<count; i++) {
469+ pixelBuf[pixelBufIdx][i] = __builtin_bswap16 (*colors++);
470+ }
471+ // The transfers themselves are relatively small, so we don't
472+ // need a long descriptor list. We just alternate between the
473+ // first two, sharing pixelBufIdx for that purpose.
474+ descriptor[pixelBufIdx].SRCADDR .reg =
475+ (uint32_t )pixelBuf[pixelBufIdx] + count * 2 ;
476+ descriptor[pixelBufIdx].BTCTRL .bit .SRCINC = 1 ;
477+ descriptor[pixelBufIdx].BTCNT .reg = count * 2 ;
478+ descriptor[pixelBufIdx].DESCADDR .reg = 0 ;
479+
480+ while (dma_busy); // wait for prior line to complete
481+
482+ // Move new descriptor into place...
483+ memcpy (dptr, &descriptor[pixelBufIdx], sizeof (DmacDescriptor));
484+ dma_busy = true ;
485+ dma.startJob (); // Trigger SPI DMA transfer
486+ pixelBufIdx = 1 - pixelBufIdx; // Swap DMA pixel buffers
486487
487- len -= count;
488+ len -= count;
489+ }
490+ lastFillColor = 0x0000 ; // pixelBuf has been sullied
491+ lastFillLen = 0 ;
492+ while (dma_busy); // Wait for last line to complete
493+ return ;
488494 }
489- lastFillColor = 0x0000 ; // pixelBuf has been sullied
490- lastFillLen = 0 ;
491- while (dma_busy); // Wait for last line to complete
492495#else
493496 SPI_WRITE_PIXELS ((uint8_t *)colors , len * 2 );
494497#endif
@@ -503,115 +506,118 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len) {
503506/* *************************************************************************/
504507void Adafruit_SPITFT::writeColor (uint16_t color, uint32_t len) {
505508
509+ uint8_t hi = color >> 8 , lo = color;
510+
511+ if (_sclk < 0 ) { // Using hardware SPI
512+
506513#ifdef USE_SPI_DMA
507514
508- int i, d, numDescriptors;
509- if ((color >> 8 ) == (color & 0xFF )) { // If high & low bytes are same...
510- onePixelBuf = color;
511- // Can do this with a relatively short descriptor list,
512- // each transferring a max of 32,767 (not 32,768) pixels.
513- // This won't run off the end of the allocated descriptor list,
514- // since we're using much larger chunks per descriptor here.
515- numDescriptors = (len + 32766 ) / 32767 ;
516- for (d=0 ; d<numDescriptors; d++) {
517- int count = (len < 32767 ) ? len : 32767 ;
518- descriptor[d].SRCADDR .reg = (uint32_t )&onePixelBuf;
519- descriptor[d].BTCTRL .bit .SRCINC = 0 ;
520- descriptor[d].BTCNT .reg = count * 2 ;
521- descriptor[d].DESCADDR .reg = (uint32_t )&descriptor[d+1 ];
522- len -= count;
523- }
524- descriptor[d-1 ].DESCADDR .reg = 0 ;
525- } else {
526- // If high and low bytes are distinct, it's necessary to fill
527- // a buffer with pixel data (swapping high and low bytes because
528- // TFT and SAMD are different endianisms) and create a longer
529- // descriptor list pointing repeatedly to this data. We can do
530- // this slightly faster working 2 pixels (32 bits) at a time.
531- uint32_t *pixelPtr = (uint32_t *)pixelBuf[0 ],
532- twoPixels = __builtin_bswap16 (color) * 0x00010001 ;
533- // We can avoid some or all of the buffer-filling if the color
534- // is the same as last time...
535- if (color == lastFillColor) {
536- // If length is longer than prior instance, fill only the
537- // additional pixels in the buffer and update lastFillLen.
538- if (len > lastFillLen) {
539- int fillStart = lastFillLen / 2 ,
540- fillEnd = (((len < maxFillLen) ?
541- len : maxFillLen) + 1 ) / 2 ;
542- for (i=fillStart; i<fillEnd; i++) pixelPtr[i] = twoPixels;
543- lastFillLen = fillEnd * 2 ;
544- } // else do nothing, don't set pixels, don't change lastFillLen
515+ int i, d, numDescriptors;
516+ if (hi == lo) { // If high & low bytes are same...
517+ onePixelBuf = color;
518+ // Can do this with a relatively short descriptor list,
519+ // each transferring a max of 32,767 (not 32,768) pixels.
520+ // This won't run off the end of the allocated descriptor list,
521+ // since we're using much larger chunks per descriptor here.
522+ numDescriptors = (len + 32766 ) / 32767 ;
523+ for (d=0 ; d<numDescriptors; d++) {
524+ int count = (len < 32767 ) ? len : 32767 ;
525+ descriptor[d].SRCADDR .reg = (uint32_t )&onePixelBuf;
526+ descriptor[d].BTCTRL .bit .SRCINC = 0 ;
527+ descriptor[d].BTCNT .reg = count * 2 ;
528+ descriptor[d].DESCADDR .reg = (uint32_t )&descriptor[d+1 ];
529+ len -= count;
530+ }
531+ descriptor[d-1 ].DESCADDR .reg = 0 ;
545532 } else {
546- int fillEnd = (((len < maxFillLen) ?
547- len : maxFillLen) + 1 ) / 2 ;
548- for (i=0 ; i<fillEnd; i++) pixelPtr[i] = twoPixels;
549- lastFillLen = fillEnd * 2 ;
550- lastFillColor = color;
551- }
533+ // If high and low bytes are distinct, it's necessary to fill
534+ // a buffer with pixel data (swapping high and low bytes because
535+ // TFT and SAMD are different endianisms) and create a longer
536+ // descriptor list pointing repeatedly to this data. We can do
537+ // this slightly faster working 2 pixels (32 bits) at a time.
538+ uint32_t *pixelPtr = (uint32_t *)pixelBuf[0 ],
539+ twoPixels = __builtin_bswap16 (color) * 0x00010001 ;
540+ // We can avoid some or all of the buffer-filling if the color
541+ // is the same as last time...
542+ if (color == lastFillColor) {
543+ // If length is longer than prior instance, fill only the
544+ // additional pixels in the buffer and update lastFillLen.
545+ if (len > lastFillLen) {
546+ int fillStart = lastFillLen / 2 ,
547+ fillEnd = (((len < maxFillLen) ?
548+ len : maxFillLen) + 1 ) / 2 ;
549+ for (i=fillStart; i<fillEnd; i++) pixelPtr[i] = twoPixels;
550+ lastFillLen = fillEnd * 2 ;
551+ } // else do nothing, don't set pixels or change lastFillLen
552+ } else {
553+ int fillEnd = (((len < maxFillLen) ?
554+ len : maxFillLen) + 1 ) / 2 ;
555+ for (i=0 ; i<fillEnd; i++) pixelPtr[i] = twoPixels;
556+ lastFillLen = fillEnd * 2 ;
557+ lastFillColor = color;
558+ }
552559
553- numDescriptors = (len + maxFillLen - 1 ) / maxFillLen;
554- for (d=0 ; d<numDescriptors; d++) {
555- int pixels = (len < maxFillLen) ? len : maxFillLen,
556- bytes = pixels * 2 ;
557- descriptor[d].SRCADDR .reg = (uint32_t )pixelPtr + bytes;
558- descriptor[d].BTCTRL .bit .SRCINC = 1 ;
559- descriptor[d].BTCNT .reg = bytes;
560- descriptor[d].DESCADDR .reg = (uint32_t )&descriptor[d+1 ];
561- len -= pixels;
560+ numDescriptors = (len + maxFillLen - 1 ) / maxFillLen;
561+ for (d=0 ; d<numDescriptors; d++) {
562+ int pixels = (len < maxFillLen) ? len : maxFillLen,
563+ bytes = pixels * 2 ;
564+ descriptor[d].SRCADDR .reg = (uint32_t )pixelPtr + bytes;
565+ descriptor[d].BTCTRL .bit .SRCINC = 1 ;
566+ descriptor[d].BTCNT .reg = bytes;
567+ descriptor[d].DESCADDR .reg = (uint32_t )&descriptor[d+1 ];
568+ len -= pixels;
569+ }
570+ descriptor[d-1 ].DESCADDR .reg = 0 ;
562571 }
563- descriptor[d-1 ].DESCADDR .reg = 0 ;
564- }
565- memcpy (dptr, &descriptor[0 ], sizeof (DmacDescriptor));
572+ memcpy (dptr, &descriptor[0 ], sizeof (DmacDescriptor));
566573
567- dma_busy = true ;
568- dma.startJob (); // Trigger SPI DMA transfer
569- while (dma_busy); // Wait for completion
574+ dma_busy = true ;
575+ dma.startJob ();
576+ while (dma_busy); // Wait for completion
570577
571- // Unfortunately the wait is necessary. An earlier version returned
572- // immediately and checked dma_busy on startWrite() instead, but it
573- // turns out to be MUCH slower on many graphics operations (as when
574- // drawing lines, pixel-by-pixel), perhaps because it's a volatile
575- // type and doesn't cache.
578+ // Unfortunately the wait is necessary. An earlier version returned
579+ // immediately and checked dma_busy on startWrite() instead, but it
580+ // turns out to be MUCH slower on many graphics operations (as when
581+ // drawing lines, pixel-by-pixel), perhaps because it's a volatile
582+ // type and doesn't cache. Working on this .
576583
577584#else // Non-DMA
578585
579- #ifdef SPI_HAS_WRITE_PIXELS
580- if (_sclk >= 0 ){
581- for (uint32_t t=0 ; t<len; t++){
582- writePixel (color);
586+ #ifdef SPI_HAS_WRITE_PIXELS
587+ #define TMPBUF_LONGWORDS (SPI_MAX_PIXELS_AT_ONCE + 1 ) / 2
588+ #define TMPBUF_PIXELS (TMPBUF_LONGWORDS * 2 )
589+ static uint32_t temp[TMPBUF_LONGWORDS];
590+ uint32_t c32 = color * 0x00010001 ;
591+ uint16_t bufLen = (len < TMPBUF_PIXELS) ? len : TMPBUF_PIXELS,
592+ xferLen, fillLen;
593+
594+ // Fill temp buffer 32 bits at a time
595+ fillLen = (bufLen + 1 ) / 2 ; // Round up to next 32-bit boundary
596+ for (uint32_t t=0 ; t<fillLen; t++) {
597+ temp[t] = c2;
583598 }
584- return ;
585- }
586- static uint16_t temp[SPI_MAX_PIXELS_AT_ONCE];
587- size_t blen = (len > SPI_MAX_PIXELS_AT_ONCE)?SPI_MAX_PIXELS_AT_ONCE:len;
588- uint16_t tlen = 0 ;
589-
590- for (uint32_t t=0 ; t<blen; t++){
591- temp[t] = color;
592- }
593599
594- while (len){
595- tlen = (len>blen)?blen:len;
596- writePixels (temp, tlen);
597- len -= tlen;
598- }
599- #else
600- uint8_t hi = color >> 8 , lo = color;
601- if (_sclk < 0 ){ // AVR Optimization
602- for (uint32_t t=len; t; t--){
600+ // Issue pixels in blocks from temp buffer
601+ while (len) { // While pixels remain
602+ xferLen = (bufLen < len) ? bufLen : len; // How many this pass?
603+ writePixels (temp, xferLen);
604+ len -= xferLen;
605+ }
606+ #else
607+ while (len--) {
603608 HSPI_WRITE (hi);
604609 HSPI_WRITE (lo);
605610 }
606- return ;
607- }
608- for (uint32_t t=len; t; t--){
609- spiWrite (hi);
610- spiWrite (lo);
611- }
612- #endif
611+ #endif
613612
614613#endif // end non-DMA
614+
615+ } else { // Bitbang SPI
616+ while (len--) {
617+ spiWrite (hi);
618+ spiWrite (lo);
619+ }
620+ }
615621}
616622
617623/* *************************************************************************/
0 commit comments