RA8876 Parallel Display Library Testing

@wwatson Wondering if I configure the RA8876 to use 16 bit buss, who code uses it?

When I tried adding in calls to writeRect which uses it:
Which uses:
C++:
void RA8876_common::writeRectImpl(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pcolors) {
    uint16_t start_x = (x != CENTER) ? x : (_width - w) / 2;
    uint16_t start_y = (y != CENTER) ? y : (_height - h) / 2;


    switch (_rotation) {
        case 0: // we will just hand off for now to
                // unrolled to bte call
                //Using the BTE function is faster and will use DMA if available
                if(_bus_width != 16) {
                bteMpuWriteWithROPData8(currentPage, width(), start_x, start_y,  //Source 1 is ignored for ROP 12
                              currentPage, width(), start_x, start_y, w, h,     //destination address, pagewidth, x/y, width/height
                              RA8876_BTE_ROP_CODE_12,
                              ( const unsigned char *)pcolors);
                } else {
                bteMpuWriteWithROPData16(currentPage, width(), start_x, start_y,  //Source 1 is ignored for ROP 12
                              currentPage, width(), start_x, start_y, w, h,     //destination address, pagewidth, x/y, width/height
                              RA8876_BTE_ROP_CODE_12,
                              ( const unsigned short *)pcolors);
                }
and it totally screws up.

I believe that drawPixel is probably wrong:
C++:
void RA8876_common::drawPixel(ru16 x, ru16 y, ru16 color) {
    graphicMode(true);
    setPixelCursor(x, y);
    ramAccessPrepare();
    lcdDataWrite(color);
    lcdDataWrite(color >> 8);
#if defined(use_lcdDataWrite16bbp)
    lcdDataWrite16bbp(color);
#endif
}
I am not seeing this one being called:
C++:
void RA8876_t41_p::write16BitColor(uint16_t color) {
    delayNanoseconds(10); // Initially setup for the T4.1 board
    if (_rotation & 1)
        delayNanoseconds(20);

    if (_bus_width != 16) {
        while (0 == (p->SHIFTSTAT & (1 << 0))) {
        }
        p->SHIFTBUF[0] = generate_output_word(color & 0xff);

        while (0 == (p->SHIFTSTAT & (1 << 0))) {
        }
        p->SHIFTBUF[0] = generate_output_word(color >> 8);
    } else {
        while (0 == (p->SHIFTSTAT & (1 << 0))) {
        }
        p->SHIFTBUF[0] = color;
        Serial.printf("$$16$$write16BitColor(%x)\n", color);
    }
}

Still looking
 
@wwatson Wondering if I configure the RA8876 to use 16 bit buss, who code uses it?

When I tried adding in calls to writeRect which uses it:
Which uses:
C++:
void RA8876_common::writeRectImpl(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pcolors) {
    uint16_t start_x = (x != CENTER) ? x : (_width - w) / 2;
    uint16_t start_y = (y != CENTER) ? y : (_height - h) / 2;


    switch (_rotation) {
        case 0: // we will just hand off for now to
                // unrolled to bte call
                //Using the BTE function is faster and will use DMA if available
                if(_bus_width != 16) {
                bteMpuWriteWithROPData8(currentPage, width(), start_x, start_y,  //Source 1 is ignored for ROP 12
                              currentPage, width(), start_x, start_y, w, h,     //destination address, pagewidth, x/y, width/height
                              RA8876_BTE_ROP_CODE_12,
                              ( const unsigned char *)pcolors);
                } else {
                bteMpuWriteWithROPData16(currentPage, width(), start_x, start_y,  //Source 1 is ignored for ROP 12
                              currentPage, width(), start_x, start_y, w, h,     //destination address, pagewidth, x/y, width/height
                              RA8876_BTE_ROP_CODE_12,
                              ( const unsigned short *)pcolors);
                }
and it totally screws up.

I believe that drawPixel is probably wrong:
C++:
void RA8876_common::drawPixel(ru16 x, ru16 y, ru16 color) {
    graphicMode(true);
    setPixelCursor(x, y);
    ramAccessPrepare();
    lcdDataWrite(color);
    lcdDataWrite(color >> 8);
#if defined(use_lcdDataWrite16bbp)
    lcdDataWrite16bbp(color);
#endif
}
I am not seeing this one being called:
C++:
void RA8876_t41_p::write16BitColor(uint16_t color) {
    delayNanoseconds(10); // Initially setup for the T4.1 board
    if (_rotation & 1)
        delayNanoseconds(20);

    if (_bus_width != 16) {
        while (0 == (p->SHIFTSTAT & (1 << 0))) {
        }
        p->SHIFTBUF[0] = generate_output_word(color & 0xff);

        while (0 == (p->SHIFTSTAT & (1 << 0))) {
        }
        p->SHIFTBUF[0] = generate_output_word(color >> 8);
    } else {
        while (0 == (p->SHIFTSTAT & (1 << 0))) {
        }
        p->SHIFTBUF[0] = color;
        Serial.printf("$$16$$write16BitColor(%x)\n", color);
    }
}

Still looking
Just wired up for 16Bit BUS. I am testing write now. Got "setBusWidth(16) and setFlexIOPins(53,52,40)" working. Need to go through everything to refresh my memory:D I don't remember "write16BitColor(uint16_t color)" at all...
 
@KurtE - Found these:
Code:
// Helper functions.
void RA8876_t41_p::beginWrite16BitColors() {
    while (WR_IRQTransferDone == false) {
    } // Wait for any IRQ transfers to complete
    FlexIO_Config_SnglBeat();
    CSLow();
    DCHigh();
    delayNanoseconds(10); // Initially setup for the T4.1 board
    if (_rotation & 1)
        delayNanoseconds(20);
}
void RA8876_t41_p::write16BitColor(uint16_t color) {
    delayNanoseconds(10); // Initially setup for the T4.1 board
    if (_rotation & 1)
        delayNanoseconds(20);

    if (_bus_width == 8) {
        while (0 == (p->SHIFTSTAT & (1 << 0))) {
        }
        p->SHIFTBUF[0] = color & 0xff;

        while (0 == (p->SHIFTSTAT & (1 << 0))) {
        }
        p->SHIFTBUF[0] = color >> 8;
    } else {
        while (0 == (p->SHIFTSTAT & (1 << 0))) {
        }
        p->SHIFTBUF[0] = color;
    }
}
void RA8876_t41_p::endWrite16BitColors() {
    // De-assert /CS pin
    while (0 == (p->TIMSTAT & (1 << 0))) {
    }
    delayNanoseconds(10); // Initially setup for the T4.1 board
    CSHigh();
}
in "RA8876_t41_p.cpp". They were not in my original code. I'll start with writeRext() first for testing in 16Bit mode...
EDIT: "drawPixel()" was also changed from the original. Will check that out as well...
 
Last edited:
@KurtE
Think write16BitColor was added when we added in begin beginWrite16BitColors and endWrite16BitColors. Wonder is some of that may be called from GFX library?
 
@KurtE @mjs513 - "drawPixel()" does not seem to be working at all in 8bit or 16bit mode (DB5). Something has happened. Tested "writeRect()" works in 8/16bit mode. "pushPixels16bitAsync()" and "pushPixels16bitDMA() work in 8bit mode. I think @Rezo only had those working in 8bit mode...
 
I tried the memory transfer example, with 16 bit turned on...
1720987183188.png

I tried building for SPI, but link error.
c:/users/kurte/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: C:\Users\kurte\AppData\Local\Temp\arduino\sketches\84F1E2FB07403005F72E1FE3478F70A5\sketch\MemoryTransfer.ino.cpp.o: in function `setup':
D:\github\TeensyRA8876Combined\Ra8876_t3\examples\MemoryTransfer/MemoryTransfer.ino:196: undefined reference to `RA8876_common::putPicture(unsigned short, unsigned short, unsigned short, unsigned short, unsigned char const*)'
collect2.exe: error: ld returned 1 exit status

Code:
c:/users/kurte/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: C:\Users\kurte\AppData\Local\Temp\arduino\sketches\84F1E2FB07403005F72E1FE3478F70A5\sketch\MemoryTransfer.ino.cpp.o: in function `setup':
D:\github\TeensyRA8876Combined\Ra8876_t3\examples\MemoryTransfer/MemoryTransfer.ino:196: undefined reference to `RA8876_common::putPicture(unsigned short, unsigned short, unsigned short, unsigned short, unsigned char const*)'
collect2.exe: error: ld returned 1 exit status
 
Got "drawPixel()" worcking 8/16bit mode:
Code:
//**************************************************************//
/* Write a 16bpp pixel                                          */
//**************************************************************//
void RA8876_common::drawPixel(ru16 x, ru16 y, ru16 color) {
    graphicMode(true);
    setPixelCursor(x, y);
    ramAccessPrepare();
    lcdDataWrite16(color);
//    lcdDataWrite(color);
//    lcdDataWrite(color >> 8);
//#if defined(use_lcdDataWrite16bbp)
//    lcdDataWrite16bbp(color);
//#endif
}
"lcdDataWrite16bbp()" is redundant I think. Only calling instance was in above...
 
@KurtE - Try this:

Code:
/*
  Memory Transfer RA8876

  M Sandercock May 15 2020

  Test memory transfer to send a picture to the RA8876 screen, then use BTE memory copy to move it around

  Most of the time you would want to just put an image onto the screen, so use the library putPicture() function.

  Another common operation is "chroma key" that allows one (and only one) color in the source
  to be designated as transparent. Chroma key can not be combined with a ROP operation.

  Window Alpha is a more natural method of blending two images together, like for a fade effect.

  The "Raster Operation" ROP codes cover all 16 possible ways of combining individual pixels in binary.
  For example, you can have a binary-AND or binary-OR operation from two sources.
  One source might be the destination: if you want to lighten an image already on the screen.
  Or we just ignore the second source and put one source into the destination.
  Some codes are not useful: code 0 and 15 are just black and white and BTE is slightly slower than
  using the drawing functions to make a black or white rectangle.

  Explanation of ROP codes:
  ROP Number  Operation Description
  0           0         Pure black
  1           ~(S0+S1)  OR both (makes a bright image) then invert (image mostly dark)
  2           ~S0.S1    Invert source 0 then AND with source 1. Where S1 is white, you see the pure inverse of S0
  3           ~S0       Invert source 0. White becomes black, blue becomes orange, green becomes magenta...
  4           S0.~S1    AND source 0 with the inverse of source 1. Where S1 is black, you see S0
  5           ~S1       Ignores source 0, inverts source 1.
  6           S0^S1     XOR. Anything on white makes black. Anything on black is normal. This operation is special because it's reversible.
  7           ~(S0.S1)  AND both (makes darker image) then invert (output is mostly bright)
  8           S0.S1     AND. Where S1 is white, you see S0 unchanged. Generally makes the entire image darker.
  9           ~(S0^S1)  Inverse of XOR. Where S1 was white you see S0 unchanged
  10          S1        Ignores S0. Note that early tests show this may be significantly faster than its pair operation #12.
  11          ~S0+S1    S1 ORed with the inverse of S0.
  12          S0        Ignores S1. Simply copies S0 to the output.
  13          S0+~S1    S0 ORed wit the inverse of S1
  14          S0+S1     OR both. Generally makes entire image lighter as everything gets pushed closer to full white.
  15          1         Pure white.

  Using 16-bit data instead of 8-bit doesn't double the speed. It turns out that 16 bit is slower
  because the built-in byte-reversal SPI transfer is not yet available on the Teensy 4.x

  If SPI DMA is available, it will be used, so putPicture() and the other operations sending lots of SPI data will return very quickly.
  You can send more instructions to the LCD immediately and they will wait for the DMA to finish.
*/
#include "Cube_172.h"

//#define use_spi
#if defined(use_spi)
#include <SPI.h>
#include <RA8876_t3.h>
#else
#include <RA8876_t41_p.h>
#endif
#include <math.h>

#if defined(use_spi)
#define RA8876_CS 10
#define RA8876_RESET 9
#define BACKLITE 7 //External backlight control connected to this Arduino pin
RA8876_t3 tft = RA8876_t3(RA8876_CS, RA8876_RESET); //Using standard SPI pins
#else
uint8_t dc = 13;
uint8_t cs = 11;
uint8_t rst = 12;
#define BACKLITE 7 //External backlight control connected to this Arduino pin
RA8876_t41_p tft = RA8876_t41_p(dc,cs,rst); //(dc, cs, rst)
#endif



void writeImage(int x, int y, int w, int h, const unsigned char *image) {
  //copy from the PROGMEM array to the screen, at the specified x/y location
  //This code is identical to what's inside tft.putPicture()
 
  //Sending bytes individually, in normal byte order
  if(tft.getBusWidth() == 8) {
    tft.bteMpuWriteWithROPData8(tft.currentPage, tft.width(), x, y,  //Source 1 is ignored for now
                                tft.currentPage, tft.width(), x, y, w, h,     //destination address, pagewidth, x/y, width/height
                                RA8876_BTE_ROP_CODE_12,
                                image);
  } else {
    tft.bteMpuWriteWithROPData16(tft.currentPage, tft.width(), x, y,  //Source 1 is ignored for now
                                 tft.currentPage, tft.width(), x, y, w, h,     //destination address, pagewidth, x/y, width/height
                                 RA8876_BTE_ROP_CODE_12,
                                 (uint16_t *)image);
  }     
}

void writeImage16(int x, int y, int w, int h, const unsigned char *image) {
  //copy from the PROGMEM array to the screen, at the specified x/y location

  //Cast the data array pointer to insist that it contains 16-bit unsigned integers
  //The only benefit of this is if you already had your data in byte-reversed 16-bit form.
  //It's actually slower than the 8 bit version.
  if(tft.getBusWidth() == 16) {
    tft.bteMpuWriteWithROPData16(tft.currentPage, tft.width(), x, y,  //Source 1 is ignored for now
                                 tft.currentPage, tft.width(), x, y, w, h,     //destination address, pagewidth, x/y, width/height
                                 RA8876_BTE_ROP_CODE_12,
                                 (uint16_t *)image);
  } else {
    tft.bteMpuWriteWithROPData8(tft.currentPage, tft.width(), x, y,  //Source 1 is ignored for now
                                tft.currentPage, tft.width(), x, y, w, h,     //destination address, pagewidth, x/y, width/height
                                RA8876_BTE_ROP_CODE_12,
                                image);
  }
}

void writeImageChromakey(int x, int y, int w, int h, ru16 chromakeyColor, const unsigned char *image) {
  //copy from the PROGMEM array to the screen, at the specified x/y location with one color transparent
  if(tft.getBusWidth() == 16) {
    tft.bteMpuWriteWithChromaKeyData16(//no source 1 for this operation
      tft.currentPage, tft.width(), x, y, w, h,     //destination address, x/y, width/height
      chromakeyColor,
      (uint16_t *)image);
  } else {
    tft.bteMpuWriteWithChromaKeyData8(//no source 1 for this operation
      tft.currentPage, tft.width(), x, y, w, h,     //destination address, x/y, width/height
      chromakeyColor,
      image);
  }
}

void copyImageROP(int x, int y, int w, int h, uint8_t rop, const unsigned char *image) {
  //copy from existing area on screen - you will see this is much faster than loading data over SPI

  tft.bteMemoryCopyWithROP(tft.currentPage, tft.width(), 20, 5, //source 0 hardcoded to come from the top-left square, which is the "normal"
                           tft.currentPage, tft.width(), 20 + 4 * (20 + IMG_WIDTH), 5 + 2 * (24 + IMG_HEIGHT), //source 1 (I'm calling it background) is hardcoded to the bottom-right square
                           tft.currentPage, tft.width(), x, y, w, h,     //destination address, x/y, width/height
                           rop);
}

void drawBG(int x, int y, int w, int h) {
  //Draw a simple geometric background to overlay the different ROP effects
  //Do the timing printout only once, to compare the time taken for a rectangle fill
  unsigned long startTime = micros();
  tft.fillRect(x, y, w, h, BLACK);
  tft.check2dBusy();
  unsigned long endTime = micros();
  static bool toPrint = true;
  if (toPrint) {
    Serial.print("fillRect operation takes ");
    Serial.print((float)(endTime - startTime) / 1000.0, 3);
    Serial.println(" microseconds to fill the image area.");
    toPrint = false;
  }
  tft.fillRect(x + 3, y + 3, w - 6, h / 3, WHITE);
  tft.fillRect(x + 3, y + 3 + h / 3, w - 6, h / 3, SKYBLUE);
  tft.fillCircle(x + w / 2, y + h / 2, h / 4, CRIMSON);
  tft.fillTriangle(x + 2 * w / 8, y + 3 * h / 8, x + 1 * w / 8, y + 5 * h / 8, x + 3 * w / 8, y + 5 * h / 8, DARKGREEN);
  tft.fillRect(x + 5 * w / 8, y + 3 * h / 8, w / 4, h / 4, DARKYELLOW);
}

//The function below is not called in the default code, but it is useful to demonstrate the "write data yourself" ability...
void writeImageChromakeyZoom(int x, int y, int w, int h, ru16 chromakeyColor, int magnification, const unsigned char *image) {
  //copy from the PROGMEM array to the screen, at the specified x/y location
  //zooms in on the image by 2X by simply repeating each pixel 2^2 times, 3X uses 3^2 repeats
  //magnification should be a small integer like 2 or 3.

  //I'm looking for incorrect chromakey pixels, so I want to put this on a plain background
  tft.fillRect(x, y, w * magnification, h * magnification, MAGENTA);

  tft.bteMpuWriteWithChromaKey(//no source 1 for this operation
    tft.currentPage, tft.width(), x, y,           //destination address, x/y
    w * magnification, h * magnification,         //width/height of output
    chromakeyColor);

  for (int sourceRow = 0; sourceRow < h; sourceRow++) {
    for (int destRow = 0; destRow < magnification; destRow++) {
      for (int sourceCol = 0; sourceCol < w; sourceCol++) {
        for (int destCol = 0; destCol < magnification; destCol++) {
          //Remember each pixel is 2 bytes
          tft.lcdDataWrite(image[sourceRow * w * 2 + sourceCol * 2]);
          tft.lcdDataWrite(image[sourceRow * w * 2 + sourceCol * 2 + 1]);
        }
      }
    }
  }
}

void setup() {
  unsigned long startTime, endTime, end2Time;
  while (!Serial && millis() < 5000) {} //wait for Serial Monitor

  Serial.printf("%cLCD Memory Transfer test starting!",12);
  Serial.print("Compiled ");
  Serial.print(__DATE__);
  Serial.print(" at ");
  Serial.println(__TIME__);

  //I'm guessing most copies of this display are using external PWM
  //backlight control instead of the internal RA8876 PWM.
  //Connect a Teensy pin to pin 14 on the display.
  //Can use analogWrite() but I suggest you increase the PWM frequency first so it doesn't sing.
  pinMode(BACKLITE, OUTPUT);
//  analogWriteFrequency(BACKLITE, 1000000);
  digitalWrite(BACKLITE, HIGH);
//  analogWrite(BACKLITE, 256);

  // Set 16bit mode
  //tft.setBusWidth(16);
  // DB5.0 WR pin, RD pin, D0 pin.
  //tft.setFlexIOPins(53,52,40);

#if defined(use_spi)
  tft.begin();
#else
  tft.begin(20);// 20 is working in 8bit and 16bit mode on T41
#endif

  tft.fillScreen(DARKBLUE);
  tft.setFontSize(1, false);

  //draw some background images, to try out different ROPs
  for (int j = 0; j < 3; j++) {
    for (int i = 0; i < 5; i++) {
      drawBG(20 + i * (20 + IMG_WIDTH), 5 + j * (24 + IMG_HEIGHT), IMG_HEIGHT, IMG_WIDTH);
    }
  }
  tft.setCursor(20 + 4 * (20 + IMG_WIDTH), 5 + 2 * (24 + IMG_HEIGHT) + IMG_HEIGHT);
  tft.setTextColor(WHITE, DARKBLUE);
  tft.print("Background");

  //This example sends the image three times, so you can see the
  //different trade-offs using either put-picture, 8-bit or 16-bit transfers...

  startTime = micros();
  tft.putPicture(20, 5, IMG_WIDTH, IMG_HEIGHT, image_565);  //basic send, using 8-bit data
  endTime = micros();
  tft.setCursor(20 , 5 + IMG_HEIGHT);
  tft.setTextColor(WHITE, DARKBLUE);
  tft.print("Normal");
  end2Time = micros();
  Serial.print("Put-picture from PROGMEM to display took ");
  Serial.print((float)(endTime - startTime) / 1000.0, 3);
  Serial.print("us to begin the operation.\n  But the next LCD operation was delayed by ");
  Serial.print((float)(end2Time - endTime) / 1000.0, 3);
  Serial.println("us because data transfer was still underway");

  if(tft.getBusWidth() == 16) {
    startTime = micros();
    writeImage16(20, 5, IMG_WIDTH, IMG_HEIGHT, image_565);  //basic send, using 16-bit byte-swapped data
    endTime = micros();
    Serial.print("16-bit copy from PROGMEM to display took ");
    Serial.print((float)(end2Time - startTime) / 1000.0, 3);
    Serial.println("us to begin the transfer (data is on its way while you read this.)");
  } else {
    startTime = micros();
    writeImage(20, 5, IMG_WIDTH, IMG_HEIGHT, image_565);  //Duplicate of basic send
    endTime = micros();
    Serial.print("8-bit Copy from PROGMEM to display took ");
    Serial.print((float)(endTime - startTime) / 1000.0, 3);
    Serial.println("us to begin the transfer (data is on its way while you read this.)");
  }

  //Chromakey can also be done as 16-bit or 8-bit but the time taken is identical to the normal write
  //It's actually the same operation underneath, just with the background color set to the chromakey
  startTime = micros();
  writeImageChromakey(20 + 1 * (IMG_WIDTH + 20), 5, IMG_WIDTH, IMG_HEIGHT, 0xffdf, image_565);
  end2Time = micros();
  tft.setCursor(20 + 1 * (IMG_WIDTH + 20), 5 + IMG_HEIGHT);
  tft.setTextColor(WHITE, DARKBLUE);
  tft.print("Chromakey");
  Serial.print("Chromakey copy from PROGMEM to display took ");
  Serial.print((float)(end2Time - startTime) / 1000.0, 3);
  Serial.println("us to run to completion.");

  //Now run through all the ROP options to see what they look like...

  uint8_t rop = 15;
  int i = 2;
  int j = 0;
  do {
    startTime = micros();
    copyImageROP(20 + i * (IMG_WIDTH + 20), 5 + j * (24 + IMG_HEIGHT), IMG_WIDTH, IMG_HEIGHT, rop, image_565);
    endTime = micros();

    //at this point, we can keep working but the BTE operation is ongoing, inside the RAiO chip
    tft.check2dBusy(); //wait until chip is not busy
    unsigned long end2 = micros();

    tft.setCursor(20 + i * (IMG_WIDTH + 20), 5 + IMG_HEIGHT + j * (24 + IMG_HEIGHT));
    tft.setTextColor(WHITE, DARKBLUE);
    tft.print("ROP ");
    tft.print(rop);

    Serial.print("ROP ");
    Serial.print(rop);
    Serial.print("  BTE copy took ");
    Serial.print((float)(endTime - startTime), 3);
//    Serial.print((float)(endTime - startTime) / 1000.0, 3);
    Serial.print("us, followed by ");
    Serial.print((float)(end2 - endTime), 3);
//    Serial.print((float)(end2 - endTime) / 1000.0, 3);
    Serial.println("us internal processing in the RAiO chip.");

    //Some of the ROP operations are not necessary to display
    //  so we will "skip" them by not moving the graphics pointer forwards to the next square
    //But the Serial output will show you how long they took,
    //  since you're probably most interested in the speed of memory-to-memory ROP10 or ROP12.
    switch (rop) {
      case 0:
      case 15:
        //ROP 0 is plain black
        //ROP 15 (plain white) is the same speed and equally useless
        break;
      case 10:
        //leaves secound source unchanged
        break;
      case 12:
        //we already saw this operation in the normal write for the top-left square
        break;
      default:
        //move on to the next space for display
        i++;
        if (i >= 5) {
          i = 0;
          j++;
        }
    }
    rop++;
    if(rop>15) rop = 0;
  } while (rop != 15 && j < 3);

  //If you need to examine your chromakey zoomed-in, looking for errant pixels, try this...
  //writeImageChromakeyZoom(20 + 2*(IMG_WIDTH + 20), 5, IMG_WIDTH, IMG_HEIGHT, 0xffdf, 3, image_565);

  Serial.println("\n\nFirst Page Finished, PRESS ANY KEY...");
  while (Serial.available() > 0) {
    Serial.read(); //clear input buffer
  }
  while (Serial.available() == 0) {
    //wait forever for any key press on Serial Monitor
  }
  Serial.println("Test Alpha...");

  //Now I want to try some different usage of the BTE functions but I've run out of space on this page
  //Jump to 2nd page, but we'll be using the data (image and background) off the first page...

  tft.selectScreen(SCREEN_2);
  tft.fillScreen(DARKGREEN);
  tft.setCursor(400, 180);
  tft.setTextColor(WHITE, DARKGREEN);
  tft.printf(" Test Alpha...");
}

void loop() {
  static uint8_t alpha = 0;
  static int8_t increment = 1;

  alpha += increment;

  tft.setCursor(400, 200 + IMG_HEIGHT);
  tft.setTextColor(WHITE, DARKGREEN);
  tft.print(alpha);
  tft.print("  ");

  tft.bteMemoryCopyWindowAlpha(SCREEN_1, tft.width(), 20, 5,  //source 0, our cube image
                               SCREEN_1, tft.width(), 20 + 4 * (20 + IMG_WIDTH), 5 + 2 * (24 + IMG_HEIGHT), //source 1 (I'm calling it background) from the bottom-right square
                               tft.currentPage, tft.width(), 400, 200, IMG_WIDTH, IMG_HEIGHT,     //destination address, x/y, width/height
                               alpha);

  delay(100);

  if (alpha >= 32) {
    increment = -1;
    delay(800);
  }
  if (alpha == 0) {
    increment = 1;
    delay(800);
  }
}

void waitforInput()
{
  Serial.println("Press anykey to continue");
  while (Serial.read() == -1) ;
  while (Serial.read() != -1) ;
}

I put this back to my original version when I first got 16bit mode working. You will find "memoryTransfr.ino.org" in the same directory which was the original version. I just tested it in 8/16bit mode:
memoryTransfer.jpg

Hopefully that was the issue...
 
The sketch you showed above looks very much like the one currently in the examples...
Still did not build when SPI..

So I moved the putPicture code out of T41 into common, and both build now.

So works fine at 8 bit mode TTL and now SPI.

But 16 bit mode still looks like what I posted earlier. Will experiment more.
I did push up my current stuff in my T40_WIP branch. I modify your sketch slighly for my carier board, plus currently need to do
tft.setBacklight(true);...

Time to take a break
 
The sketch you showed above looks very much like the one currently in the examples...
Still did not build when SPI..

So I moved the putPicture code out of T41 into common, and both build now.

So works fine at 8 bit mode TTL and now SPI.

But 16 bit mode still looks like what I posted earlier. Will experiment more.
I did push up my current stuff in my T40_WIP branch. I modify your sketch slighly for my carier board, plus currently need to do
tft.setBacklight(true);...

Time to take a break
I can't remember why "putPicture()" was moved. Hopefully after more testing I will be able to setup my SPI display. Right now the "graphicsCursor.ino" sketch is not working completely. The graphics cursor moves properly but none of the button presses are working. Don't know why yet...
 
I rehooked up the display now acting different, faulting in writeRect in 16 bit mode…

will investigate more in morning
 
I rehooked up the display now acting different, faulting in writeRect in 16 bit mode…

will investigate more in morning
Really weird. writeRect is always the most stable. I wonder if it has anything to do with the delayNanoseconds() in:
Code:
bteMpuWriteWithROPData16()
in RA8876_t41_p.cpp? maybe play with that...
 
So I moved the putPicture code out of T41 into common, and both build now.
Thats a pit confusing we had moved putPicture in common in the combined_t4x_wip branch of the other repo???? And when last tested using that branch it worked. But @KurtE you are write its not in the repo TeensyRA8876Combined - wonder if there is anything else missing.
 
Thats a pit confusing we had moved putPicture in common in the combined_t4x_wip branch of the other repo???? And when last tested using that branch it worked. But @KurtE you are write its not in the repo TeensyRA8876Combined - wonder if there is anything else missing.
I just checked RA8876_common.cpp in TeensyRA8876Combined and it's not there. It's in RA8876_t41_p.cpp??? I'll move it over...
 
Thats a pit confusing we had moved putPicture in common in the combined_t4x_wip branch of the other repo???? And when last tested using that branch it worked. But @KurtE you are write its not in the repo TeensyRA8876Combined - wonder if there is anything else missing.
Good question, I think this was done out of the cherry pick branch, not sure if we missed any later changes in the branch I froked from
I just checked RA8876_common.cpp in TeensyRA8876Combined and it's not there. It's in RA8876_t41_p.cpp??? I'll move it over...

In my T40_WIP I already moved it... Just trying to get 16 bit mode working in it....
But could do PR of what I have including the T4 back for you to play with.

EDIT: The readRect/writeRect in the Kurt... faults it also does in the hacked up readPixels:
Code:
Hit Enter to continue
bteMpuWriteWithROPData16(50 95 128 40 12 - 20003928)
CrashReport:
  A problem occurred at (system time) 4:53:35
  Code was executing from address 0x17FA
  CFSR: 82
    (DACCVIOL) Data Access Violation
    (MMARVALID) Accessed Address: 0x20006842 (Stack problem)
      Check for stack overflows, array bounds, etc.
  Temperature inside the chip was 42.16 °C
  Startup CPU clock speed is 600MHz
  Reboot was caused by auto reboot after fault or bad interrupt detected
Hit Enter to continue
Code:
C:\Users\kurte\AppData\Local\Temp\arduino\sketches\66410FA15BD3E5DDC86403EA9F1377AC>addr2line -e RA8876p_readPixels.ino.elf 0x17FA
c:\Users\kurte\Documents\Arduino\libraries\RA8876_t41_p\src/RA8876_t41_p.cpp:1374

Code:
void RA8876_t41_p::bteMpuWriteWithROPData16(ru32 s1_addr, ru16 s1_image_width, ru16 s1_x, ru16 s1_y, ru32 des_addr, ru16 des_image_width,
                                            ru16 des_x, ru16 des_y, ru16 width, ru16 height, ru8 rop_code, const unsigned short *data) {
    ru16 i, j;
    Serial.printf("bteMpuWriteWithROPData16(%u %u %u %u %u - %x)\n", des_x, des_y, width, height, rop_code, data);
    bteMpuWriteWithROP(s1_addr, s1_image_width, s1_x, s1_y, des_addr, des_image_width, des_x, des_y, width, height, rop_code);

    while (WR_IRQTransferDone == false) {
    } // Wait for any IRQ transfers to complete

    FlexIO_Config_SnglBeat();
    CSLow();
    DCHigh();
    for (j = 0; j < height; j++) {
        for (i = 0; i < width; i++) {
            delayNanoseconds(10); // Initially setup for the T4.1 board
            if (_rotation & 1)
                delayNanoseconds(70);
            uint16_t pixel = *data++;
            //p->SHIFTBUF[0] = ((pixel & 0xff)  << 8) | (pixel >> 8);
>>>>>            p->SHIFTBUF[0] = *data++;
            /*Wait for transfer to be completed */
            while (0 == (p->SHIFTSTAT & (1 << 0))) {
            }
            while (0 == (p->TIMSTAT & (1 << 0))) {
            }
        }
    }
    /* De-assert /CS pin */
    CSHigh();
}
 
Last edited:
@KurtE - Here is the my working version of bteMpuWriteWithROPData16():
Code:
void RA8876_t41_p::bteMpuWriteWithROPData16(ru32 s1_addr, ru16 s1_image_width, ru16 s1_x, ru16 s1_y, ru32 des_addr, ru16 des_image_width,
                                            ru16 des_x, ru16 des_y, ru16 width, ru16 height, ru8 rop_code, const unsigned short *data) {
    ru16 i, j;
    bteMpuWriteWithROP(s1_addr, s1_image_width, s1_x, s1_y, des_addr, des_image_width, des_x, des_y, width, height, rop_code);

    while (WR_IRQTransferDone == false) {
    } // Wait for any IRQ transfers to complete

    FlexIO_Config_SnglBeat();
    CSLow();
    DCHigh();
    for (j = 0; j < height; j++) {
        for (i = 0; i < width; i++) {
            delayNanoseconds(10); // Initially setup for the T4.1 board
            if (_rotation & 1)
                delayNanoseconds(70);
            p->SHIFTBUF[0] = *data++;
            /*Wait for transfer to be completed */
            while (0 == (p->SHIFTSTAT & (1 << 0))) {
            }
            while (0 == (p->TIMSTAT & (1 << 0))) {
            }
        }
    }
    /* De-assert /CS pin */
    CSHigh();
}
Basically the same.
I'll download both branches of your repo and test them here. Are you using the DB5?
Dang, to slow this morning. Need more coffee:)
 
I'll download both branches of your repo and test them here. Are you using the DB5?
Dang, to slow this morning. Need more coffee:)
Right now using T4.1... Was trying to eliminate as many unknown variables as possible...

1721046637723.png

Here is 16 bit mode, in my test output coe... The parts I circled in Orange show where readRect and writeRect
colors don't match...

The stuff circled in pink are some simple writeRects... The bars were done with writeRect8BPP, the simple Red and Blue square where normal writeRect

So next to debug 16 bit color reads...
 
@KurtE - Got the same results here with T40_WIP as above and also with RA8876p_readPixels. Colors seem shifted. This was on the DB5 in 16bit mode. I also tested memoryTransfer sketch and it works in 8/16bit modes...
 
@mjs513 - looks the same as I showed above...

Note: I hacked up the read function:
Code:
ru8 RA8876_t41_p::lcdDataRead(bool finalize) {
    uint16_t dummy __attribute__((unused)) = 0;
    uint16_t data = 0;

    while (WR_IRQTransferDone == false) {
    } // Wait for any IRQ transfers to complete

//    FlexIO_Clear_Config_SnglBeat();
    FlexIO_Config_SnglBeat_Read();

    CSLow();  // Must to go low after config above.
    DCHigh(); // Set HIGH for data read

    RDLow(); // Set RD pin low manually

    while (0 == (p->SHIFTSTAT & (1 << 3))) {
    }
    dummy = read_shiftbuf_byte();
    while (0 == (p->SHIFTSTAT & (1 << 3))) {
    }
    if (_bus_width != 16)
        data = read_shiftbuf_byte();
    else {
        data = p->SHIFTBUFBYS[3];
        static uint16_t debug_count = 100;
        if (debug_count) {
            debug_count--;
            Serial.printf("R:%x\n", data);
        }
        data = (data >> 8) & 0xff;
        //data = (p->SHIFTBUFBYS[3] >> 8) & 0xff;
    }

    RDHigh(); // Set RD pin high manually

    CSHigh();

    // Serial.printf("lcdDataread(): Dummy 0x%4.4x, data 0x%4.4x\n", dummy, data);

    // Set FlexIO back to Write mode
    FlexIO_Config_SnglBeat(); // Not sure if this is needed.
    return data;
}

In the ReadPixel sketch I hacked up to try to read center pixel of each band:
Code:
    for (int i = 0; i < COUNT_BANDS; i++) {
        tft.fillRect(BAND_START_X + (BAND_WIDTH * i), BAND_START_Y, BAND_WIDTH, BAND_HEIGHT, band_colors[i]);
    }
    WaitForUserInput();

    // lets try to read one pixel center of each band
    for (int i = 0; i < COUNT_BANDS; i++) {
        uint16_t pixel = tft.readPixel(BAND_START_X + (BAND_WIDTH * i) + BAND_WIDTH/2, BAND_START_Y + BAND_HEIGHT / 2);
        Serial.printf("Band %u: color: %x read:%x\n", i, band_colors[i], pixel);
    }
Output does not look like the logic of reading twice in 16 bit mode may work correctly...
Code:
Hit Enter to continue
R:0
R:d8
R:d8
Band 0: color: f800 read:0
R:d8
R:e007
R:e007
Band 1: color: 7e0 read:e0e0
R:e007
R:1fd8
R:1fd8
Band 2: color: f81f read:1f1f
R:1fd8
R:ef5b
R:ef5b
Band 3: color: 7bef read:efef
R:ef5b
R:ffdf
R:ffdf
Band 4: color: ffff read:ffff
R:ffdf
R:e0df
R:e0df
Band 5: color: ffe0 read:e0e0
R:e0df
R:ff07
R:ff07
Band 6: color: 7ff read:ffff
R:ff07
R:1f00
R:1f00
Band 7: color: 1f read:1f1f
R:1f00
R:d8
 
With the first rotations I am reading and comparing the read pixel for each of the four rotatons and they match what you see:

Code:
ROTATION: 0
Rect Color: 0x1f, Pixel Color: 0x1f
Circle Color: 0x7e0, Pixel Color: 0x7e0
Hit Enter to continue
TFT Width: 600, Height: 1024
ROTATION: 1
Rect Color: 0x1f, Pixel Color: 0x1f
Circle Color: 0x7e0, Pixel Color: 0x7e0
Hit Enter to continue
TFT Width: 1024, Height: 600
ROTATION: 2
Rect Color: 0x1f, Pixel Color: 0x1f
Circle Color: 0x7e0, Pixel Color: 0x7e0
Hit Enter to continue
TFT Width: 600, Height: 1024
ROTATION: 3
Rect Color: 0x1f, Pixel Color: 0x1f
Circle Color: 0x7e0, Pixel Color: 0x7e0
 
Think we might need a lcdDataRead16. Playing around readPixel and lcddataread. Notice anything interesting
Code:
TFT Width: 600, Height: 1024
ROTATION: 1
lcdDataread(): Dummy 0xe007, data 0x1f00
lcdDataread(): Dummy 0x0000, data 0x1f00
Rect Color: 0x1f, Pixel Color: 0x1f
lcdDataread(): Dummy 0x1f00, data 0xe007
lcdDataread(): Dummy 0x0000, data 0xe007
Circle Color: 0x7e0, Pixel Color: 0xe0
Hit Enter to continue
lcdDataread(): Dummy 0xc800, data 0xc800
TFT Width: 1024, Height: 600
ROTATION: 2
lcdDataread(): Dummy 0xe007, data 0x1f00
lcdDataread(): Dummy 0x0000, data 0x1f00
Rect Color: 0x1f, Pixel Color: 0x1f
lcdDataread(): Dummy 0x1f00, data 0xe007
lcdDataread(): Dummy 0x0000, data 0xe007
Circle Color: 0x7e0, Pixel Color: 0xe0
Hit Enter to continue
lcdDataread(): Dummy 0xc800, data 0xc800
TFT Width: 600, Height: 1024
ROTATION: 3
lcdDataread(): Dummy 0xe007, data 0x1f00
lcdDataread(): Dummy 0x0000, data 0x1f00
Rect Color: 0x1f, Pixel Color: 0x1f
lcdDataread(): Dummy 0x1f00, data 0x1f00
lcdDataread(): Dummy 0x0000, data 0xe007
Circle Color: 0x7e0, Pixel Color: 0xe0
Hit Enter to continue

Note this with getPixel changes

Code:
    dummy = lcdDataRead();
    //rdata = (lcdDataRead() & 0xff); // read low byte
    //rdata |= lcdDataRead() << 8;    // add high byte
    rdata = lcdDataRead();
    return rdata;

If I comment out the dummy = lcdDataRead
Code:
FT Width: 1024, Height: 600
ROTATION: 0
lcdDataread(): Dummy 0x0000, data 0x1f00
Rect Color: 0x1f, Pixel Color: 0x1f
lcdDataread(): Dummy 0x1f00, data 0x1f00
Circle Color: 0x7e0, Pixel Color: 0x1f
Hit Enter to continue
lcdDataread(): Dummy 0xc000, data 0xc000
TFT Width: 600, Height: 1024
ROTATION: 1
lcdDataread(): Dummy 0xe007, data 0x1f00
Rect Color: 0x1f, Pixel Color: 0x1f
lcdDataread(): Dummy 0x1f00, data 0x1f00
Circle Color: 0x7e0, Pixel Color: 0x1f
Hit Enter to continue

commenting both dummy reads in lcdDataRead and getPixel

Code:
FT Width: 1024, Height: 600
ROTATION: 0
lcdDataread(): Dummy 0x0000, data 0x1f00
Rect Color: 0x1f, Pixel Color: 0x1f
lcdDataread(): Dummy 0x1f00, data 0x1f00
Circle Color: 0x7e0, Pixel Color: 0x1f
Hit Enter to continue
lcdDataread(): Dummy 0xc000, data 0xc000
TFT Width: 600, Height: 1024
ROTATION: 1
lcdDataread(): Dummy 0xe007, data 0x1f00
Rect Color: 0x1f, Pixel Color: 0x1f
lcdDataread(): Dummy 0x1f00, data 0x1f00
Circle Color: 0x7e0, Pixel Color: 0x1f
Hit Enter to continue

No clue where to go from here
 
Last edited:
Back
Top