ILI9488_t3 - Support for the ILI9488 on T3.x and beyond...

Finally got a first pass of DMA updateScreenAsync() to work with translating the buffer... Pushed up to the WIP branch.

Quick and dirty try of it in the simple app... Another page after the timings page...
Code:
//=============================================================================
//=============================================================================

#include <ILI9488_t3.h>
#include <ILI9488_t3_font_Arial.h>
#include <ILI9488_t3_font_ArialBold.h>
#define TFT_RST 8
#define TFT_DC 9
#define TFT_CS 10

uint16_t our_pallet[] = {
  ILI9488_BLACK,  ILI9488_RED, ILI9488_GREEN,  ILI9488_BLUE,   ILI9488_WHITE,
  ILI9488_YELLOW, ILI9488_ORANGE, ILI9488_CYAN, ILI9488_PINK };

ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST);
//=============================================================================
// Setup
//=============================================================================
void setup()
{
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  while (!Serial && (millis() < 3000));
  Serial.begin(115200);
  tft.begin();
  tft.setRotation(3); // 180
  delay(100);

  tft.fillScreen(ILI9488_BLACK);
  delay(250);
  }
//=============================================================================
// Loop
//=============================================================================
void loop()
{
  tft.useFrameBuffer(false);
  uint32_t start_time = millis();
  tft.fillScreen(ILI9488_BLACK);
  tft.fillScreen(ILI9488_RED);
  tft.fillScreen(ILI9488_GREEN);
  tft.fillScreen(ILI9488_BLUE);
  tft.fillScreen(ILI9488_WHITE);
  tft.fillScreen(ILI9488_YELLOW);
  tft.fillScreen(ILI9488_ORANGE);
  tft.fillScreen(ILI9488_CYAN);
  tft.fillScreen(ILI9488_PINK);
  tft.fillRect(0, 0, tft.width()/2, tft.height()/2, ILI9488_RED);
  tft.fillRect(tft.width()/2, 0, tft.width()/2, tft.height()/2, ILI9488_GREEN);
  tft.fillRect(0, tft.height()/2, tft.width()/2, tft.height()/2, ILI9488_BLUE);
  tft.fillRect( tft.width()/2, tft.height()/2, tft.width()/2, tft.height()/2, ILI9488_YELLOW);
  uint32_t non_frame_buffer_time = millis() - start_time;
  delay(1000);
  tft.setPallet(our_pallet, sizeof(our_pallet)/sizeof(our_pallet[0]));
  tft.colorsArePalletIndex(true);
  tft.useFrameBuffer(true);
  start_time = millis();
  tft.fillScreen(0);
  tft.fillScreen(8);
  tft.fillScreen(7);
  tft.fillScreen(6);
  tft.fillScreen(5);
  tft.fillScreen(4);
  tft.fillScreen(3);
  tft.fillScreen(2);
  tft.fillScreen(1);
  tft.fillRect(0, 0, tft.width()/2, tft.height()/2, 4);
  tft.fillRect(tft.width()/2, 0, tft.width()/2, tft.height()/2, 5);
  tft.fillRect(0, tft.height()/2, tft.width()/2, tft.height()/2, 6);
  tft.fillRect( tft.width()/2, tft.height()/2, tft.width()/2, tft.height()/2, 7);

  tft.updateScreen();
  uint32_t frame_buffer_time = millis() - start_time;
  delay(1000);
  //tft.useFrameBuffer(false);
  tft.colorsArePalletIndex(false);
  tft.fillScreen(ILI9488_BLACK);
  tft.setTextColor(ILI9488_RED);
  tft.setTextSize(3);
  tft.setCursor(0, 130);
  tft.printf("Reg: %d\nFB: %d", non_frame_buffer_time, frame_buffer_time);
  tft.updateScreen();  
  delay(1000);
  tft.colorsArePalletIndex(true);
  tft.useFrameBuffer(true);
  start_time = millis();
  tft.fillRect(0, 0, tft.width()/2, tft.height()/2, 1);
  tft.fillRect(tft.width()/2, 0, tft.width()/2, tft.height()/2, 3);
  tft.fillRect(0, tft.height()/2, tft.width()/2, tft.height()/2, 5);
  tft.fillRect( tft.width()/2, tft.height()/2, tft.width()/2, tft.height()/2, 7);
  tft.updateScreenAsync();  // Try an async update...  
  delay(2500);
}

I have not tried out the continuous option yet... Nor checked timing...

Spent good amount of time today debugging why it was all coming out screwed up... Then found again that the DMA Isr was getting called twice (ARGH).
Appears to work now, with:
Code:
		_dmatx.clearInterrupt();
 		asm("dsb");
 
@KurtE

You are amazing getting DMA working in one day. Took me most of the day playing with my LiPo's and finding out I killed 2 of the expensive one's argh is right. Will give it a try.
 
@KurtE and @defragster
Ran a quick test on the T3.6 and T$:
Code:
T3.6
REG: 1461
FB:     189
AS:        4

T$:
REG:  980
FB:     109
AS:        1
This is with @defragsters SPIClock settings in the .h file

The test sketch I used:
Code:
//=============================================================================
//=============================================================================
#include <ILI9488_t3.h>
#include <ILI9488_t3_font_Arial.h>
#include <ILI9488_t3_font_ArialBold.h>

#define TEENSY64

#if defined(__MK66FX1M0__) && !defined(TEENSY64)
#define TFT_RST 255
#define TFT_DC 20
#define TFT_CS 21
ILI9488_t3n tft = ILI9488_t3n(TFT_CS, TFT_DC, TFT_RST);
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
// On Teensy 4 beta with Paul's breakout out:
// Using pins (MOSI, MISO, SCK which are labeled on Audio board breakout location
// which are not in the Normal processor positions
// Also DC=10(CS), CS=9(BCLK) and RST 23(MCLK)
#define TFT_RST 23
#define TFT_DC 9
#define TFT_CS 10
ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST);
#elif defined(TEENSY64)
#define TFT_RST 255
#define TFT_DC 20
#define TFT_CS 21
#define TFT_SCK 14
#define TFT_MISO 39
#define TFT_MOSI 28
ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO);
#else
#error "This example App will only work with Teensy 3.6 or Teensy 4."
#endif

uint16_t our_pallet[] = {
  ILI9488_BLACK,  ILI9488_RED, ILI9488_GREEN,  ILI9488_BLUE,   ILI9488_WHITE,
  ILI9488_YELLOW, ILI9488_ORANGE, ILI9488_CYAN, ILI9488_PINK };

//=============================================================================
// Setup
//=============================================================================
void setup()
{
  //pinMode(2, OUTPUT);
  //pinMode(3, OUTPUT);
  //pinMode(4, OUTPUT);
  while (!Serial && (millis() < 3000));
  Serial.begin(115200);
  tft.begin();
  tft.setRotation(3); // 180
  delay(100);

  tft.fillScreen(ILI9488_BLACK);
  delay(250);
  }
//=============================================================================
// Loop
//=============================================================================
void loop()
{
  tft.useFrameBuffer(false);
  uint32_t start_time = millis();
  tft.fillScreen(ILI9488_BLACK);
  tft.fillScreen(ILI9488_RED);
  tft.fillScreen(ILI9488_GREEN);
  tft.fillScreen(ILI9488_BLUE);
  tft.fillScreen(ILI9488_WHITE);
  tft.fillScreen(ILI9488_YELLOW);
  tft.fillScreen(ILI9488_ORANGE);
  tft.fillScreen(ILI9488_CYAN);
  tft.fillScreen(ILI9488_PINK);
  tft.fillRect(0, 0, tft.width()/2, tft.height()/2, ILI9488_RED);
  tft.fillRect(tft.width()/2, 0, tft.width()/2, tft.height()/2, ILI9488_GREEN);
  tft.fillRect(0, tft.height()/2, tft.width()/2, tft.height()/2, ILI9488_BLUE);
  tft.fillRect( tft.width()/2, tft.height()/2, tft.width()/2, tft.height()/2, ILI9488_YELLOW);
  uint32_t non_frame_buffer_time = millis() - start_time;
  delay(1000);
  
  tft.setPallet(our_pallet, sizeof(our_pallet)/sizeof(our_pallet[0]));
  tft.colorsArePalletIndex(true);
  tft.useFrameBuffer(true);
  start_time = millis();
  tft.fillScreen(0);
  tft.fillScreen(8);
  tft.fillScreen(7);
  tft.fillScreen(6);
  tft.fillScreen(5);
  tft.fillScreen(4);
  tft.fillScreen(3);
  tft.fillScreen(2);
  tft.fillScreen(1);
  tft.fillRect(0, 0, tft.width()/2, tft.height()/2, 4);
  tft.fillRect(tft.width()/2, 0, tft.width()/2, tft.height()/2, 5);
  tft.fillRect(0, tft.height()/2, tft.width()/2, tft.height()/2, 6);
  tft.fillRect( tft.width()/2, tft.height()/2, tft.width()/2, tft.height()/2, 7);
  tft.updateScreen();
  uint32_t frame_buffer_time = millis() - start_time;
  delay(1000);
  
  tft.colorsArePalletIndex(true);
  tft.useFrameBuffer(true);
  start_time = millis();
  tft.fillRect(0, 0, tft.width()/2, tft.height()/2, 1);
  tft.fillRect(tft.width()/2, 0, tft.width()/2, tft.height()/2, 3);
  tft.fillRect(0, tft.height()/2, tft.width()/2, tft.height()/2, 5);
  tft.fillRect( tft.width()/2, tft.height()/2, tft.width()/2, tft.height()/2, 7);
  tft.updateScreenAsync();  // Try an async update...
  uint32_t async_time = millis() - start_time;
  [COLOR="#FF0000"]delay(1000);[/COLOR]
  
  //tft.useFrameBuffer(false);
  tft.colorsArePalletIndex(false);
  tft.fillScreen(ILI9488_BLACK);
  tft.setTextColor(ILI9488_RED);
  tft.setTextSize(3);
  tft.setCursor(0, 130);
  tft.printf("Reg: %d\nFB: %d\nAS:%d", non_frame_buffer_time, frame_buffer_time,async_time);
  tft.updateScreen();  
  delay(2500);
}
Just as a note the highlighted delay has to be there otherwise it hangs my T$
 
Good work on the DMA @KurtE... will try it soon.

@mjs513 - wondering if the whole delay(1000) is needed - or just 150 to make sure the DMA write completes?

on the other front ... NOT WHITED at 72 MHz SPI :: Been running the github DemoSauce on T$ ~2 hours {50 twisty loops} at the 10 secs unchanged - so no counts or pixel set/check.
I'm wondering if there was some edge case altered in the core SPI_transaction processing that tripped on T$ not T_3.6? I did see a WHITE out recently - but that may have been for taking the prior zip of ILI9488_t3-Frame_Buffer_Pallet as at some point those edits were redone … not seen since.
 
Warning DMA currently only on T4. Next test a little continuous update mode... Also some simple speed startup speed enhancement...

That is for example we push 4 bytes for X range and y Range and loop waiting for these to complete. We could use this time to fill the first buffer, such that when these transfers complete we can hopefully instantly start the DMA...

Probably tomorrow...
 
Sounds wonderfully magical KurtE! I pulled the 1st pass DMA 2 hours back - but not unzipped yet.

@KurtE - re mjs513 post #78 - is there a way to tell when async DMA update in progress/complete? I'm assuming pushing new writes during the update - of the 'tft.colorsArePalletIndex(false);' or 'tft.updateScreen();' if not the other tft.() commands during the update caused the hang observed?
> given WIP - maybe this is 'current' behavior?

The 'github' DemoSauce another 2 hours running on T$ with no WHITE screen - just running. So the 9488 seems able to run at the speed the T$ ends up at when 72 MHz is requested. It is faster than 30 MHz for sure.

The only ODD/Bad looking Demo in the Sauce is the Cube3D where the T_3.6 is smooth and the T$ is jumpy/bouncy where all the others seems to flow smoothly.
 
@mjs513 … To prevent Async collision/Hang instead of delay(1000) :: tft.waitUpdateAsyncComplete();

This comes out USB Serial - one time after the 2nd pass - then you can drop SerMon - now shows SPICLOCK at start and AsyncComplete wait time:
T:\tCode\T4\KEdma01\KEdma01.ino Apr 15 2019 01:57:08
ILI9488_SPICLOCK @ 72000000
Reg: 980
FB: 109
AS:1
Reg: 982
FBvoid: 1043
ASwt:116
T:\tCode\T4\KEdma01\KEdma01.ino Apr 15 2019 01:59:20
ILI9488_SPICLOCK @ 30000000
Reg: 1468
FB: 158
AS:1
Reg: 1469
FBvoid: 1532
ASwt:165

Where FBvoid - is the loop when each screen draw is followed by 'tft.updateScreen()' so the update time can be tracked:
Code:
	for ( int ii = 0; ii < 9; ii++) {
		tft.fillScreen(ii);
		if ( zz % 2 ) tft.updateScreen();
	}

<edit> Updated next post:: Full sample - Updated from @mjs513 p#78 since I copied the wrong one to start - TFT_RST==8:
Code:
//=============================================================================
//=============================================================================
#include <ILI9488_t3.h>
#include <ILI9488_t3_font_Arial.h>
#include <ILI9488_t3_font_ArialBold.h>

#define TEENSY64

#if defined(__MK66FX1M0__) && !defined(TEENSY64)
#define TFT_RST 255
#define TFT_DC 20
#define TFT_CS 21
ILI9488_t3n tft = ILI9488_t3n(TFT_CS, TFT_DC, TFT_RST);
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
// On Teensy 4 beta with Paul's breakout out:
// Using pins (MOSI, MISO, SCK which are labeled on Audio board breakout location
// which are not in the Normal processor positions
// Also DC=10(CS), CS=9(BCLK) and RST 23(MCLK)
#define TFT_RST 8
#define TFT_DC 9
#define TFT_CS 10
ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST);
#elif defined(TEENSY64)
#define TFT_RST 255
#define TFT_DC 20
#define TFT_CS 21
#define TFT_SCK 14
#define TFT_MISO 39
#define TFT_MOSI 28
ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO);
#else
#error "This example App will only work with Teensy 3.6 or Teensy 4."
#endif

uint16_t our_pallet[] = {
	ILI9488_BLACK,  ILI9488_RED, ILI9488_GREEN,  ILI9488_BLUE,   ILI9488_WHITE,
	ILI9488_YELLOW, ILI9488_ORANGE, ILI9488_CYAN, ILI9488_PINK
};

//=============================================================================
// Setup
//=============================================================================
void setup()
{
	//pinMode(2, OUTPUT);
	//pinMode(3, OUTPUT);
	//pinMode(4, OUTPUT);
	while (!Serial && (millis() < 3000));
	Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
    Serial.print("ILI9488_SPICLOCK @ ");
    Serial.println(ILI9488_SPICLOCK);
	Serial.begin(115200);
	tft.begin();
	tft.setRotation(3); // 180
	delay(100);

	tft.fillScreen(ILI9488_BLACK);
	delay(250);
}
//=============================================================================
// Loop
//=============================================================================
int zz = 0;
uint32_t non_frame_buffer_time[2] = {0, 0};
uint32_t frame_buffer_time[2] = {0, 0};
void loop()
{
	tft.useFrameBuffer(false);
	uint32_t start_time = millis();
	tft.fillScreen(ILI9488_BLACK);
	tft.fillScreen(ILI9488_RED);
	tft.fillScreen(ILI9488_GREEN);
	tft.fillScreen(ILI9488_BLUE);
	tft.fillScreen(ILI9488_WHITE);
	tft.fillScreen(ILI9488_YELLOW);
	tft.fillScreen(ILI9488_ORANGE);
	tft.fillScreen(ILI9488_CYAN);
	tft.fillScreen(ILI9488_PINK);
	tft.fillRect(0, 0, tft.width() / 2, tft.height() / 2, ILI9488_RED);
	tft.fillRect(tft.width() / 2, 0, tft.width() / 2, tft.height() / 2, ILI9488_GREEN);
	tft.fillRect(0, tft.height() / 2, tft.width() / 2, tft.height() / 2, ILI9488_BLUE);
	tft.fillRect( tft.width() / 2, tft.height() / 2, tft.width() / 2, tft.height() / 2, ILI9488_YELLOW);
	non_frame_buffer_time[zz % 2] = millis() - start_time;
	delay(1000);

	tft.setPallet(our_pallet, sizeof(our_pallet) / sizeof(our_pallet[0]));
	tft.colorsArePalletIndex(true);
	tft.useFrameBuffer(true);
	start_time = millis();
	for ( int ii = 0; ii < 9; ii++) {
		tft.fillScreen(ii);
		if ( zz % 2 ) tft.updateScreen();
	}
	tft.fillRect(0, 0, tft.width() / 2, tft.height() / 2, 4);
	tft.fillRect(tft.width() / 2, 0, tft.width() / 2, tft.height() / 2, 5);
	tft.fillRect(0, tft.height() / 2, tft.width() / 2, tft.height() / 2, 6);
	tft.fillRect( tft.width() / 2, tft.height() / 2, tft.width() / 2, tft.height() / 2, 7);
	tft.updateScreen();
	frame_buffer_time[zz % 2] = millis() - start_time;
	delay(1000);

	tft.colorsArePalletIndex(true);
	tft.useFrameBuffer(true);
	start_time = millis();
	tft.fillRect(0, 0, tft.width() / 2, tft.height() / 2, 1);
	tft.fillRect(tft.width() / 2, 0, tft.width() / 2, tft.height() / 2, 3);
	tft.fillRect(0, tft.height() / 2, tft.width() / 2, tft.height() / 2, 5);
	tft.fillRect( tft.width() / 2, tft.height() / 2, tft.width() / 2, tft.height() / 2, 7);
	tft.updateScreenAsync();  // Try an async update...
	uint32_t async_time = millis() - start_time;
	// delay(1000);
	start_time = millis();
	tft.waitUpdateAsyncComplete();
	uint32_t async_time_wait = millis() - start_time;

	//tft.useFrameBuffer(false);
	tft.colorsArePalletIndex(false);
	tft.fillScreen(ILI9488_BLACK);
	tft.setTextColor(ILI9488_RED);
	tft.setTextSize(3);
	tft.setCursor(0, 130);
	tft.printf("Reg: %d\nFB: %d\nAS:%d", non_frame_buffer_time[0], frame_buffer_time[0], async_time);
	tft.printf("\nReg: %d\nFBvoid: %d\nASwt:%d", non_frame_buffer_time[1], frame_buffer_time[1], async_time_wait);
	tft.updateScreen();
	if ( zz == 1 ) {
		Serial.printf("Reg: %d\nFB: %d\nAS:%d", non_frame_buffer_time[0], frame_buffer_time[0], async_time);
		Serial.printf("\nReg: %d\nFBvoid: %d\nASwt:%d", non_frame_buffer_time[1], frame_buffer_time[1], async_time_wait);
	}
	zz++;
	delay(2500);
}
 
Last edited:
MINOR sketch update - made the test more symmetric {use of color pallet array} and fewer code lines - both use for loop on fillScreen() made function call to draw screen quarter colors.

I am now seeing a white line/blob appear on screen above final red box just before the stats screen when delay is delay(1000 - async_time_wait); - not sure if this is in the original @KurtE sample?:
Code:
//=============================================================================
//=============================================================================
#include <ILI9488_t3.h>
#include <ILI9488_t3_font_Arial.h>
#include <ILI9488_t3_font_ArialBold.h>

#define TEENSY64

#if defined(__MK66FX1M0__) && !defined(TEENSY64)
#define TFT_RST 255
#define TFT_DC 20
#define TFT_CS 21
ILI9488_t3n tft = ILI9488_t3n(TFT_CS, TFT_DC, TFT_RST);
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
// On Teensy 4 beta with Paul's breakout out:
// Using pins (MOSI, MISO, SCK which are labeled on Audio board breakout location
// which are not in the Normal processor positions
// Also DC=10(CS), CS=9(BCLK) and RST 23(MCLK)
#define TFT_RST 8
#define TFT_DC 9
#define TFT_CS 10
ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST);
#elif defined(TEENSY64)
#define TFT_RST 255
#define TFT_DC 20
#define TFT_CS 21
#define TFT_SCK 14
#define TFT_MISO 39
#define TFT_MOSI 28
ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO);
#else
#error "This example App will only work with Teensy 3.6 or Teensy 4."
#endif

uint16_t our_pallet[] = {
	ILI9488_BLACK,  ILI9488_RED, ILI9488_GREEN,  ILI9488_BLUE,   ILI9488_WHITE,
	ILI9488_YELLOW, ILI9488_ORANGE, ILI9488_CYAN, ILI9488_PINK
};

void showQuarters( uint32_t aa, uint32_t bb, uint32_t cc, uint32_t dd) {
	tft.fillRect(0, 0, tft.width() / 2, tft.height() / 2, aa);
	tft.fillRect(tft.width() / 2, 0, tft.width() / 2, tft.height() / 2, bb);
	tft.fillRect(0, tft.height() / 2, tft.width() / 2, tft.height() / 2, cc);
	tft.fillRect( tft.width() / 2, tft.height() / 2, tft.width() / 2, tft.height() / 2, dd);
}

//=============================================================================
// Setup
//=============================================================================
void setup()
{
#ifdef DEBUG_ASYNC_LEDS
	pinMode(2, OUTPUT);
	pinMode(3, OUTPUT);
	pinMode(4, OUTPUT);
#endif
	while (!Serial && (millis() < 3000));
	Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
	Serial.print("ILI9488_SPICLOCK @ ");
	Serial.println(ILI9488_SPICLOCK);
	Serial.begin(115200);
	tft.begin();
	tft.setRotation(3); // 180
	delay(100);

	tft.fillScreen(ILI9488_BLACK);
	delay(250);
}
//=============================================================================
// Loop
//=============================================================================
int zz = 0;
uint32_t non_frame_buffer_time[2] = {0, 0};
uint32_t frame_buffer_time[2] = {0, 0};
void loop()
{
	tft.useFrameBuffer(false);
	uint32_t start_time = micros();
	for ( uint ii = 0; ii < sizeof(our_pallet) / sizeof(our_pallet[0]); ii++) {
		tft.fillScreen(our_pallet[ii]);
	}
	showQuarters( our_pallet[1], our_pallet[2], our_pallet[3], our_pallet[5] );
	non_frame_buffer_time[zz % 2] = micros() - start_time;
	delay(1000);

	tft.setPallet(our_pallet, sizeof(our_pallet) / sizeof(our_pallet[0]));
	tft.colorsArePalletIndex(true);
	tft.useFrameBuffer(true);
	start_time = micros();
	for ( uint ii = 0; ii < sizeof(our_pallet) / sizeof(our_pallet[0]); ii++) {
		tft.fillScreen(ii);
		if ( zz % 2 ) tft.updateScreen();
	}
	showQuarters( 4, 5, 6, 7 );
	tft.updateScreen();
	frame_buffer_time[zz % 2] = micros() - start_time;
	delay(1000);

	tft.colorsArePalletIndex(true);
	tft.useFrameBuffer(true);
	start_time = micros();
	showQuarters( 1, 3, 5, 7 );
	tft.updateScreenAsync();  // Try an async update...
	uint32_t async_time = micros() - start_time;
	start_time = micros();
	tft.waitUpdateAsyncComplete();
	uint32_t async_time_wait = micros() - start_time;
	delay(1000 - async_time_wait/1000);

	//tft.useFrameBuffer(false);
	tft.colorsArePalletIndex(false);
	tft.fillScreen(ILI9488_BLACK);
	tft.setTextColor(ILI9488_RED);
	tft.setTextSize(3);
	tft.setCursor(0, 130);
	tft.printf("Reg: %d\nFB: %d\nAS:%d", non_frame_buffer_time[0], frame_buffer_time[0], async_time);
	tft.printf("\nReg: %d\nFBvoid: %d\nASwt:%d", non_frame_buffer_time[1], frame_buffer_time[1], async_time_wait);
	tft.updateScreen();
	if ( zz == 1 ) {
		Serial.printf("Reg: %d\nFB: %d\nAS:%d", non_frame_buffer_time[0], frame_buffer_time[0], async_time);
		Serial.printf("\nReg: %d\nFBvoid: %d\nASwt:%d", non_frame_buffer_time[1], frame_buffer_time[1], async_time_wait);
	}
	zz++;
	delay(2500);
}
 
Last edited:
@KurtE - hopefully this is a shortened and valid sketch using DMA/FBuffer? Either this or above works to show same issue - but this code easier to work debug perhaps and the cleared area in top quarter takes off the glare.

I restored the pinmode for 'DEBUG_ASYNC_LEDS' - but that would need to be #define in the .h not .cpp to work.

It shows the WHITE 'above offscreen' it seems at the END of the DMA write? Something is tormenting the tft controller?

I reduced the one RED quarter - the white appears above that like in the full sketch above. Only it may not be white and there are other colored pixels sparsley showing before in the same offscreen area?

Code:
//=============================================================================
//=============================================================================
#include <ILI9488_t3.h>
#include <ILI9488_t3_font_Arial.h>
#include <ILI9488_t3_font_ArialBold.h>

#define TFT_RST 8
#define TFT_DC 9
#define TFT_CS 10
ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST);

uint16_t our_pallet[] = {
	ILI9488_BLACK,  ILI9488_RED, ILI9488_GREEN,  ILI9488_BLUE,   ILI9488_WHITE,
	ILI9488_YELLOW, ILI9488_ORANGE, ILI9488_CYAN, ILI9488_PINK
};

void showQuarters( uint32_t aa, uint32_t bb, uint32_t cc, uint32_t dd) {
	tft.fillRect(10, 10, tft.width() / 4, tft.height() / 4, aa);
	tft.fillRect(tft.width() / 2, 0, tft.width() / 2, tft.height() / 2, bb);
	tft.fillRect(0, tft.height() / 2, tft.width() / 2, tft.height() / 2, cc);
	tft.fillRect( tft.width() / 2, tft.height() / 2, tft.width() / 2, tft.height() / 2, dd);
}

//=============================================================================
// Setup
//=============================================================================
void setup()
{
#ifdef DEBUG_ASYNC_LEDS
	pinMode(2, OUTPUT);
	pinMode(3, OUTPUT);
	pinMode(4, OUTPUT);
#endif
	while (!Serial && (millis() < 3000));
	Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
	Serial.print("ILI9488_SPICLOCK @ ");
	Serial.println(ILI9488_SPICLOCK);
	Serial.begin(115200);
	tft.begin();
	tft.setRotation(3); // 180
	delay(100);

	tft.fillScreen(ILI9488_BLACK);
	tft.setPallet(our_pallet, sizeof(our_pallet) / sizeof(our_pallet[0]));
	delay(250);
}
//=============================================================================
// Loop
//=============================================================================
int zz = 0;
uint32_t non_frame_buffer_time[2] = {0, 0};
uint32_t frame_buffer_time[2] = {0, 0};
void loop()
{
	tft.useFrameBuffer(false);
	tft.fillScreen(ILI9488_BLACK);
	tft.setTextColor(ILI9488_RED);
	tft.setTextSize(3);
	tft.setCursor(0, 50);
	tft.printf("You\nAre\nHere\nhello world");
	delay(500);

	tft.colorsArePalletIndex(true);
	tft.useFrameBuffer(true);
	showQuarters( 1, 3, 5, 7 );
	delay(2500);
	tft.updateScreenAsync();  // Try an async update...
	tft.waitUpdateAsyncComplete();

	delay(2500);
}
 
@defragster and @KurtE

I ran the test sketch in post 83 with one minor change - for Asynch time I am using micros instead of millis:
D:\Users\Merli\Documents\Arduino\9488_DMA_Test_defrag\9488_DMA_Test_defrag.ino Apr 15 2019 08:04:37
Code:
ILI9488_SPICLOCK @ 72000000
Reg: 980
FB: 109
AS:537
Reg: 981
FBvoid: 1044
ASwt:116

I am not seeing a blob above the final red box but I am seeing more of a red line at I would say is the first line in the display about the final red box. I am using a T$ for the testing.
 
@mjs513 and @defragster - Blob on top of display area, is indicating that I am overrunning the data...

That is:
if you do a full update of the display: all 480x320 pixels, it expects that after the setting up the output rectangle (setAddr call) and start filling
Output of RAMWR command, that I will output 480*320*3 bytes of pixel data, or with DMA 480*320/80 DMA Interrupts (setups)... So it is looking like I maybe did not tell it to stop soon enough and more pixel data was output which when you output ram data and complete the output, it wraps back around to the start of the ram region again... (good for continuous updates, but...)
 
Micros is fun ... updated above.

I'm using a T$ as well - DMA not working on T_3.6.

I just thought to confirm 'ILI9488_SPICLOCK 30000000' works the same at 72 MHz - I see off screen pixels not black - both sketches above.
 
@mjs513 and @defragster - Blob on top of display area, is indicating that I am overrunning the data...

That is:
if you do a full update of the display: all 480x320 pixels, it expects that after the setting up the output rectangle (setAddr call) and start filling
Output of RAMWR command, that I will output 480*320*3 bytes of pixel data, or with DMA 480*320/80 DMA Interrupts (setups)... So it is looking like I maybe did not tell it to stop soon enough and more pixel data was output which when you output ram data and complete the output, it wraps back around to the start of the ram region again... (good for continuous updates, but...)

That was my suspicion … "seems at the END of the DMA write?" … seemed worth noting.

T:\tCode\T4\KEdma01\KEdma01.ino Apr 15 2019 05:39:56
ILI9488_SPICLOCK @ 30000000
Reg: 1468347
FB: 157921
AS:537
Reg: 1468311
FBvoid: 1532528
ASwt:165119
T:\tCode\T4\KEdma01\KEdma01.ino Apr 15 2019 05:40:36
ILI9488_SPICLOCK @ 72000000
Reg: 979633
FB: 109047
AS:536
Reg: 981293
FBvoid: 1043794
ASwt:116195
 
@KurtE and @defragster and others,

Have an off topic comment (so what else is new for us). Working with a lib for the serial servos and its using va_list. It compiles fine for Arduino uno but when I do the compile for T3.5 is gets upset.

PS. @KurtE in your other thread on AX-12s what level shifters are you using on serial?
 
It has been awhile, but the Phoenix code (hexapod) did/does have code to roughly play a sequence of notes, which at least used to compile:
Something like:
Code:
void SoundNoTimer(unsigned long duration,  unsigned int frequency)
{
// The tone command does sort of work, but does not play multiple sounds smoothly
//  tone(SOUND_PIN, frequency, duration);  // Try the arduino library
//  delay(duration);
  // Try to get something working on DUE...
  long toggle_count = 0;
  long lusDelayPerHalfCycle;
  boolean fHigh = false;
  // Set the pinMode as OUTPUT
  pinMode(SOUND_PIN, OUTPUT);
  digitalWrite(SOUND_PIN, LOW);
  toggle_count = 2 * frequency * duration / 1000;
  lusDelayPerHalfCycle = 1000000L/(frequency * 2);

  // if we are using an 8 bit timer, scan through prescalars to find the best fit
  while (toggle_count--) {
    // toggle the pin
    fHigh  = !fHigh;
    digitalWrite(SOUND_PIN, fHigh? LOW : HIGH);
    // delay a half cycle
    delayMicroseconds(lusDelayPerHalfCycle);
  }    
  digitalWrite(SOUND_PIN, LOW);
}

void MSound(byte cNotes, ...)
{
  va_list ap;
  unsigned int uDur;
  unsigned int uFreq;
  va_start(ap, cNotes);

  while (cNotes > 0) {
    uDur = va_arg(ap, unsigned int);
    uFreq = va_arg(ap, unsigned int);
    SoundNoTimer(uDur, uFreq);
    cNotes--;
  }
  va_end(ap);
}
Don't see anywhere where I may be including anything special for the va_list stuff, but my guess is it needs: #include <stdarg.h>

As for level shifters, I have played with several... Actually for a long time I did not bother with them on T3.2 or like as while the AX servos say 5v logic, they appeared to work OK with 3.3v and the T3.2 could handle 5v responses... I have also played around with using 1 or 2, remember the DXL servos are half duplex. So sometimes I use the half duplex support of the Teensy processor (TX) pin and then only have to level shift that one.... Other times I setup to use both RX and TX and use a direction pin (like RS485 like support).

Here is a schematic for the Robotis OpenCM 9.04 board that is similar to what I have used used and probably will: http://support.robotis.com/en/baggage_files/opencm/opencm904_rev_10_final_schematic.pdf with something like 74LVC1G125 and SN74LVC1G126. They both have an enable pin, one is OE and the other is NOT OE, so depending on the state of the direction pin, one of them will be active...
 
@defragster @mjs513 - Pushed up change hopefully fixed the data over run... So no more first line garbage (I think...)
@defragster also ran your simplified one...
 
Another quick update: Started playing with continuous updates. There is some offset issue that I am trying to debug...

But if you want to play:
Code:
//=============================================================================
//=============================================================================
#include <ILI9488_t3.h>
#include <ILI9488_t3_font_Arial.h>
#include <ILI9488_t3_font_ArialBold.h>

#define TFT_RST 8
#define TFT_DC 9
#define TFT_CS 10
ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST);

uint16_t our_pallet[] = {
  ILI9488_BLACK,  ILI9488_RED, ILI9488_GREEN,  ILI9488_BLUE,   ILI9488_WHITE,
  ILI9488_YELLOW, ILI9488_ORANGE, ILI9488_CYAN, ILI9488_PINK
};

//=============================================================================
// Setup
//=============================================================================
void setup()
{
#ifdef DEBUG_ASYNC_LEDS
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
#endif
  while (!Serial && (millis() < 3000));
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  Serial.print("ILI9488_SPICLOCK @ ");
  Serial.println(ILI9488_SPICLOCK);
  Serial.begin(115200);
  tft.begin();
  tft.setRotation(3); // 180
  delay(100);

  tft.fillScreen(ILI9488_BLACK);
  tft.useFrameBuffer(true);
  tft.setPallet(our_pallet, sizeof(our_pallet) / sizeof(our_pallet[0]));
  tft.colorsArePalletIndex(true);
  delay(250);
}
//=============================================================================
// Loop
//=============================================================================
int zz = 0;
uint32_t non_frame_buffer_time[2] = {0, 0};
uint32_t frame_buffer_time[2] = {0, 0};
void loop()
{
  // First simple pallet output sync output
  tft.fillScreen(0);
  uint16_t x = 5;
  uint16_t y = 5;

  for (uint8_t i = 1; i < (sizeof(our_pallet) / sizeof(our_pallet[0])); i++) {
    tft.drawRect(x, y, tft.width() - x * 2, tft.height() - y * 2, i);
    x += tft.width() / 16;
    y += tft.height() / 16;
  }
  tft.updateScreen();
  delay(2500);

  x = 5;
  y = 5;

  // next simple pallet Async output;
  for (uint8_t i = 1; i < (sizeof(our_pallet) / sizeof(our_pallet[0])); i++) {
    tft.fillRect(x, y, tft.width() - x * 2, tft.height() - y * 2, i);
    x += tft.width() / 16;
    y += tft.height() / 16;
  }
  tft.updateScreenAsync();  // Try an async update...
  tft.waitUpdateAsyncComplete();

  delay(2500);

  // Next lets try some continuous outputs...
  // Lets update the screen in 16 chunks, every 2 frames.
  uint32_t next_update_frame_count = 5;
  tft.setTextColor(0);
  tft.setTextSize(2);
  tft.setCursor(5, 5);
  tft.print("Cont...");
  tft.updateScreen();
  delay(500);
  tft.print(" Again...");
  tft.updateScreenAsync();
  delay(500);


  tft.updateScreenAsync(true);  // Try an async update...
  for (uint16_t i = 1; i <= 16; i++) {
    // wait for the next frame...
    while (tft.frameCount() < next_update_frame_count) ;
    x = 5;
    y = 5;
    tft.setClipRect(0, 0, tft.width(), i * (tft.height() / 16));
    for (uint8_t i = 1; i < (sizeof(our_pallet) / sizeof(our_pallet[0])); i++) {
      tft.fillRect(x, y, tft.width() - x * 2, tft.height() - y * 2, 8 - i);
      x += tft.width() / 16;
      y += tft.height() / 16;

      next_update_frame_count += 2;

    }
  }
  tft.setClipRect();
  tft.endUpdateAsync();  // Tell system to cancel async updates
  tft.waitUpdateAsyncComplete();

  delay(1000);
}
Can be simplified, but has a few extras in here to see if I can see what it is going wrong...
 
@KurtE
Just tried the updates with the old sketch and the new sketch in post #92. I'm not getting anything on the display - it pretty much stays white. Is this is what suppose to happen?
 
@KurtE - looks good!
>> Prior complete and minimized sketch works here - NO tft ARTIFACTS showing! Tested 30 and 72 MHz - no change in displayed Times on full sketch.

Also ran the continuous update p#92 sketch and no problem compile/upload - assume the partial draw then shift and repeat is the intended test pattern.

If this were in 9488.h I could stop re-adding each time:
Code:
#include <SPI.h>
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
#if F_BUS >= 64000000
#define ILI9488_SPICLOCK 64000000
#define ILI9488_SPICLOCK_READ 4000000
#else
#define ILI9488_SPICLOCK 30000000
#define ILI9488_SPICLOCK_READ 2000000
#endif
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)  // Teensy 4.x
#define ILI9488_SPICLOCK 30000000
//#define ILI9488_SPICLOCK 72000000
#define ILI9488_SPICLOCK_READ 4000000
#else
#define ILI9488_SPICLOCK 30000000
#define ILI9488_SPICLOCK_READ 2000000
#endif
 
@KurtE
Not that I fixed the RST pin, that's what I get for coping and pasting. I agree with @defragster. With the sketch in post#84, no more artifact at the top of the screen.

With the continuous update sketch, p92, compiles and runs but I see what you mean about an offset being off. Pardon the pun
 
Hi @defragster and @mjs513 - First should restate that I have only implemented the Async (DMA) updates so far for T4...

I think I have it pretty well limping along as shown in sketch... Updated here:
Code:
//=============================================================================
//=============================================================================
#include <ILI9488_t3.h>
#include <ILI9488_t3_font_Arial.h>
#include <ILI9488_t3_font_ArialBold.h>

#define TFT_RST 8
#define TFT_DC 9
#define TFT_CS 10
ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST);

uint16_t our_pallet[] = {
  ILI9488_BLACK,  ILI9488_RED, ILI9488_GREEN,  ILI9488_BLUE,   ILI9488_WHITE,
  ILI9488_YELLOW, ILI9488_ORANGE, ILI9488_CYAN, ILI9488_PINK
};

//=============================================================================
// Setup
//=============================================================================
void setup()
{
  tft.begin();
  tft.setRotation(3); // 180
  delay(100);

  tft.fillScreen(ILI9488_BLACK);
  tft.useFrameBuffer(true);
  tft.setPallet(our_pallet, sizeof(our_pallet) / sizeof(our_pallet[0]));
  tft.colorsArePalletIndex(true);
  delay(250);
}
//=============================================================================
// Loop
//=============================================================================
int zz = 0;
uint32_t non_frame_buffer_time[2] = {0, 0};
uint32_t frame_buffer_time[2] = {0, 0};
void loop()
{
  // First simple pallet output sync output
  tft.fillScreen(0);
  uint16_t x = 5;
  uint16_t y = 5;

  for (uint8_t i = 1; i < (sizeof(our_pallet) / sizeof(our_pallet[0])); i++) {
    tft.drawRect(x, y, tft.width() - x * 2, tft.height() - y * 2, i);
    x += tft.width() / 16;
    y += tft.height() / 16;
  }
  tft.updateScreen();
  delay(2500);

  x = 5;
  y = 5;

  // next simple pallet Async output;
  for (uint8_t i = 1; i < (sizeof(our_pallet) / sizeof(our_pallet[0])); i++) {
    tft.fillRect(x, y, tft.width() - x * 2, tft.height() - y * 2, i);
    x += tft.width() / 16;
    y += tft.height() / 16;
  }
  tft.updateScreenAsync();  // Try an async update...
  tft.waitUpdateAsyncComplete();

  delay(2500);

  // Next lets try some continuous outputs...
  // Lets update the screen in 16 chunks, every 2 frames.
  uint32_t next_update_frame_count = 2;
  tft.setTextColor(0);
  tft.setTextSize(2);
  tft.setCursor(5, 5);
  tft.print("Cont...");
  tft.updateScreen();
  tft.updateScreenAsync(true);  // Try an async update...
  for (uint16_t i = 1; i <= 16; i++) {
    // wait for the next frame...
    while (tft.frameCount() < next_update_frame_count) ;
    x = 5;
    y = 5;
    tft.setClipRect(0, 0, tft.width(), i * (tft.height() / 16));
    for (uint8_t i = 1; i < (sizeof(our_pallet) / sizeof(our_pallet[0])); i++) {
      tft.fillRect(x, y, tft.width() - x * 2, tft.height() - y * 2, 8 - i);
      x += tft.width() / 16;
      y += tft.height() / 16;
    }
    next_update_frame_count += 2;
  }
  tft.setClipRect();
  tft.endUpdateAsync();  // Tell system to cancel async updates
  tft.waitUpdateAsyncComplete();

  delay(1000);
}
It runs through something like 32 frames, and between each two it updates the fill rect colors using clip rectangle to only update next part of the screen...

Probably next up: T3.6...
 
Got the .cpp update from github - that removed the screen shift.

Added this after the last delay(1000).
Shows screen draw progresses the palette line colors outward as intended with no signs of issues except some tearing/flashing:
Code:
	for (uint16_t kk = 0; kk < 4; kk++) {
		for (uint16_t jj = 1; jj < sizeof(our_pallet) / sizeof(our_pallet[0]); jj++) {
			for (uint16_t i = 1; i <= 16; i++) {
				x = 5;
				y = 5;
				tft.setClipRect(0, 0, tft.width(), i * (tft.height() / 16));
				for (uint8_t i = 1; i < (sizeof(our_pallet) / sizeof(our_pallet[0])); i++) {
					tft.fillRect(x, y, tft.width() - x * 2, tft.height() - y * 2, ((jj + i) % 9));
					x += tft.width() / 16;
					y += tft.height() / 16;
				}
			}
			tft.updateScreen();
			tft.waitUpdateAsyncComplete();
		}
	}
	delay(1000);

And back in:
Code:
	for (uint16_t kk = 0; kk < 8; kk++) {
		for (uint16_t jj = 1; jj < sizeof(our_pallet) / sizeof(our_pallet[0]); jj++) {
			for (uint16_t i = 1; i <= 16; i++) {
				x = 5;
				y = 5;
				tft.setClipRect(0, 0, tft.width(), i * (tft.height() / 16));
				for (uint8_t i = 1; i < (sizeof(our_pallet) / sizeof(our_pallet[0])); i++) {
					if ( kk < 4 )
						tft.fillRect(x, y, tft.width() - x * 2, tft.height() - y * 2, ((jj + i) % 9));
					else
						tft.fillRect(x, y, tft.width() - x * 2, tft.height() - y * 2, ((18+(jj - i)) % 9));
					x += tft.width() / 16;
					y += tft.height() / 16;
				}
			}
			tft.updateScreen();
			tft.waitUpdateAsyncComplete();
		}
	}
	delay(1000);
 
Just downloaded and gave it a go with and without @defragster's added test case.

I tested at 30/72Mhz without any problems. I don't see any of the issues of "tearing and flashing of the screen except when the Tim's psychedelic effect hits :) Then I get dizzy.
 
@mjs513 and @defragster - pushed up pass 1 of T3.6 support. I think there should be an issue with alignment of pixels... But it looks OK,

Need to see how bad it is, but the test screen is showing not too bad.
 
Back
Top