Playing around with yet another version of ILI9341_t3 library (ILI9341_t3n)

I was looking at that page earlier and noticed it was using a Teensy 3.1 and Purple test board, wasn't sure if it would work on a 3.6.
 
Works great with all of the Teensy 3.x boards. Actually the display works on a T-LC as well, but this library does not work with it as it relies on the SPI PUSHR registers.
 
Nope, It simply needs to be hooked up to a valid set of IO pins. example to which pins shown in https://www.pjrc.com/store/display_ili9341.html are one set of pins that should work.

With my version of the library you can use any of the SPI busses on the T3.5/6 which both have 3 spi busses.

FrankB has a flexiboard for the T3.5/6 which is setup for the displays. Actually for the Touch screen version: https://www.pjrc.com/store/display_ili9341_touch.html
I also have a board that is similar to Frank's
 
Thank you Kurt, I've looked at Franks flexiboard what's your board like? I'm likely to get the display touch screen version from pjrc store.
 
I wondered why the link I posted was only $10 - indeed get the Larger TouchScreen version and it has really cool interrupt aware touch interface. It was probably one of the earlier things I tested on the Beta K66 hardware for the T_3.6 - and I used one of the Purple boards to do it.

Franks' Flexiboards are nice for building on. I bought some of an earlier one and he sent me one of his ver #3 boards {with his working beta Teensy64} - it looks very nice and complete.
 
Thanks for the info defragster. I've watched many youtube videos about the teensy and the displays and that made me take the step to get a 3.6 as well as its ability to handle FFT. I've learned a lot from reading many posts in this forum. Most of the info is pretty far over my head but getting closer! Frank could use some bullet points of the features and benefits of his Flexiboard as well as making it easier to buy one. Just thought I would humbly say.
 
I am not a DMA expert, but I have played around with it, both for this display, plus the Async SPI code and I had it working with three SPI displays on the T3.6/5 one on each display and had them all doing Async (DMA) updates at the same time... So it is probably worth a try.
 
Hello KurtE, managed to get my screen running after putting sck on the wrong pin and scratching my head for about two hours. It seems very fast. I noticed that rotation only works for 0 and 2, do you know when you will be able to fix the other 2 rotation settings?
 
Hello KurtE, managed to get my screen running after putting sck on the wrong pin and scratching my head for about two hours. It seems very fast. I noticed that rotation only works for 0 and 2, do you know when you will be able to fix the other 2 rotation settings?

What is not working on 1 and 3? Everything or the DMA stuff? I will try to take a look later today.

Update:
I tried on my Flex board, with my Frame buffer output and clip test program and was able to set rotation to all four rotations. I only did some basic testing, but did not notice anything obviously not working...
Code:
#include <ili9341_t3n_font_Arial.h>
#include <ili9341_t3n_font_ArialBold.h>
#include <ILI9341_t3n.h>

#define ROTATION 3

#include "SPI.h"
#define KURTS_FLEXI
#ifdef KURTS_FLEXI
#define TFT_DC 22
#define TFT_CS 15
#define TFT_RST -1
#define TFT_SCK 14
#define TFT_MISO 12
#define TFT_MOSI 7
#define DEBUG_PIN 13
#else
#define TFT_DC  9
#define TFT_CS 10
#define TFT_RST 7
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11
#endif
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO, &SPIN);
Adafruit_GFX_Button button;
uint8_t use_dma = 0;
uint8_t use_clip_rect = 0;
uint8_t use_set_origin = 0;
uint8_t use_fb = 0;

#define ORIGIN_TEST_X 50
#define ORIGIN_TEST_Y 50

void setup() {
  while (!Serial && (millis() < 4000)) ;
  Serial.begin(115200);


  tft.begin();
  tft.setRotation(ROTATION);
  tft.fillScreen(ILI9341_BLACK);

  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
#ifdef DEBUG_PIN
  pinMode(DEBUG_PIN, OUTPUT);
#endif

  button.initButton(&tft, 200, 125, 100, 40, ILI9341_GREEN, ILI9341_YELLOW, ILI9341_RED, "UP", 1);

  drawTestScreen();
}

void SetupOrClearClipRectAndOffsets() {
  if (use_clip_rect) {
    tft.setClipRect();  // make sure we clear the whole screen
    tft.setOrigin();    // make sure none are set yet

    tft.fillScreen(ILI9341_LIGHTGREY);

    // Now lets set origin.
    if (use_set_origin)
      tft.setOrigin(ORIGIN_TEST_X, ORIGIN_TEST_Y);
    int x = tft.width() / 4;
    int y = tft.height() / 4;
    int w = tft.width() / 2;
    int h = tft.height() / 2;
    tft.drawRect(x, y, w, h, ILI9341_ORANGE);
    tft.updateScreen();
    tft.setClipRect(x + 1, y + 1, w - 2, h - 2);
    delay(250);

  } else {
    tft.setClipRect();
    if (use_set_origin)
      tft.setOrigin(ORIGIN_TEST_X, ORIGIN_TEST_Y);
    else
      tft.setOrigin();
  }
}


uint16_t palette[256];  // Should probably be 256, but I don't use many colors...
uint16_t pixel_data[2500];
const uint8_t pict1bpp[] = {0xff, 0xff, 0xc0, 0x03, 0xa0, 0x05, 0x90, 0x9, 0x88, 0x11, 0x84, 0x21, 0x82, 0x41, 0x81, 0x81,
                            0x81, 0x81, 0x82, 0x41, 0x84, 0x21, 0x88, 0x11, 0x90, 0x09, 0xa0, 0x05, 0xc0, 0x03, 0xff, 0xff
                           };
const uint8_t pict2bpp[] = {
  0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff,
  0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff,
  0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 
  0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 
  0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 
  0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 
  0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 
  0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 
  0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff,
  0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff,
  0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 
  0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 
  0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 
  0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 
  0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 
  0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 
};
const uint8_t pict4bpp[] = {  
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00,  
  0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00,  
  0x00, 0x11, 0x22, 0x22, 0x22, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x22, 0x22, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x33, 0x33, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x33, 0x33, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x33, 0x33, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x33, 0x33, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x22, 0x22, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x22, 0x22, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00,  
  0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00,  
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};


                           
void drawTestScreen() {
  Serial.printf("Use FB: %d ", use_fb); Serial.flush();
  tft.useFrameBuffer(use_fb);
  SetupOrClearClipRectAndOffsets();
  uint32_t start_time = millis();
  tft.fillScreen(use_fb ? ILI9341_RED : ILI9341_BLACK);
  //tft.setFont(Inconsolata_60);
  tft.setFont(Arial_24_Bold);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(0, 0);
  tft.println("Test");
  tft.setTextColor(ILI9341_WHITE, ILI9341_RED);
  tft.println("text");
  tft.setCursor(85, 65);
  tft.print("XYZ");
  tft.setFontAdafruit();
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("01234");
  tft.setTextColor(ILI9341_WHITE, ILI9341_GREEN);
  tft.println("56789!@#$%");

  tft.drawRect(0, 150, 100, 50, ILI9341_WHITE);
  tft.drawLine(0, 150, 100, 50, ILI9341_GREEN);
  tft.fillRectVGradient(125, 150, 50, 50, ILI9341_GREEN, ILI9341_YELLOW);
  tft.fillRectHGradient(200, 150, 50, 50, ILI9341_YELLOW, ILI9341_GREEN);
  // Try a read rect and write rect
#ifdef DEBUG_PIN
  digitalWrite(DEBUG_PIN, HIGH);
#endif

  tft.readRect(0, 0, 50, 50, pixel_data);

#ifdef DEBUG_PIN
  digitalWrite(DEBUG_PIN, LOW);
#endif
  tft.writeRect(250, 0, 50, 50, pixel_data);

  // Lets try to pack this rectangle of data into 8 byte
  tft.readRect(85, 65, 50, 50, pixel_data);
  uint16_t *ppd16 = pixel_data;
  uint8_t *ppd8 = (uint8_t*)pixel_data;
  uint8_t palette_cnt = 0;
  int palette_index;
  for (int i = 0; i < 2500; i++) {
    for (palette_index = 0; palette_index < palette_cnt; palette_index++) {
      if (*ppd16 == palette[palette_index])
        break;
    }
    if (palette_index >= palette_cnt) {
      palette[palette_cnt++] = *ppd16;  // save away the color
    }
    *ppd8++ = palette_index;
    ppd16++;
  }
  tft.writeRect8BPP(200, 50, 50, 50, (uint8_t*)pixel_data, palette);
  palette[0] = ILI9341_CYAN; 
  palette[1] = ILI9341_OLIVE; 
  tft.writeRect1BPP(75, 100, 16, 16, pict1bpp, palette);
  tft.writeRect1BPP(320-90, 75, 16, 16, pict1bpp, palette);
  
  palette[2] = ILI9341_MAROON; 
  palette[3] = ILI9341_PINK; 
  tft.writeRect2BPP(75, 125, 32, 16, pict2bpp, palette);

  tft.writeRectNBPP(15, 125, 32, 16, 2, pict2bpp, palette);
  tft.writeRectNBPP(75, 150, 16, 16, 4, pict4bpp, palette);

  // Try drawing button
  tft.setFontAdafruit();
  button.drawButton();

  if (use_dma) {
    tft.startUpdateScreenDMA(); 
  } else {
    tft.updateScreen();
  }
  Serial.println(millis() - start_time, DEC);

  if (use_dma && use_fb) {
    delay(500);
    Serial.printf("DMA error status: %x\n", DMA_ES);
  }

  use_fb = use_fb ? 0 : 1 ;
  Serial.println(use_fb, DEC);


}

void drawTextScreen(bool fOpaque) {
  SetupOrClearClipRectAndOffsets();
  uint32_t start_time = millis();
  tft.useFrameBuffer(use_fb);
  tft.fillScreen(use_fb ? ILI9341_RED : ILI9341_BLACK);
  tft.setFont(Arial_40_Bold);
  if (fOpaque)
    tft.setTextColor(ILI9341_WHITE, use_fb ? ILI9341_BLACK : ILI9341_RED);
  else
    tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(0, 5);
  tft.println("AbCdEfGhIj");
  tft.setFont(Arial_28_Bold);
  tft.println("0123456789!@#$");
#if 1
  tft.setFont(Arial_20_Bold);
  tft.println("abcdefghijklmnopq");
  tft.setFont(Arial_14_Bold);
  tft.println("ABCDEFGHIJKLMNOPQRST");
  tft.setFont(Arial_10_Bold);
  tft.println("0123456789zyxwvutu");
#endif
  tft.updateScreen();

  Serial.printf("Use FB: %d OP: %d, DT: %d OR: %d\n", use_fb, fOpaque, use_set_origin, millis() - start_time);
}

//=============================================================================
// Try continuous update
//=============================================================================
void testDMAContUpdate() {
  // Force frame buffer on
  Serial.printf("continuous DMA udpate test - Frame mode on\n"); Serial.flush();
      use_fb = 1; //
  
  tft.useFrameBuffer(use_fb);
  tft.fillScreen(ILI9341_GREEN);

  tft.startUpdateScreenDMA(true);

  uint32_t frame_count;  

  while ((frame_count = tft.frameCount()) < 10) yield();
  tft.fillScreen(ILI9341_YELLOW);

  while ((frame_count = tft.frameCount()) < 20) yield();
  tft.fillScreen(ILI9341_RED);

  while ((frame_count = tft.frameCount()) < 30) yield();
  tft.fillScreen(ILI9341_BLACK);

  while ((frame_count = tft.frameCount()) < 40) yield();

  tft.setCursor(0, 100);
  tft.setFont(Arial_20_Bold);
  tft.println("DONE");

  tft.endUpdateScreenDMA();

  Serial.println("Finished test");


}

void loop(void) {
  // See if any text entered
  int ich;
  if ((ich = Serial.read()) != -1) {
    while (Serial.read() != -1) delay(1);
    if (ich == 'c') {
      use_clip_rect = !use_clip_rect;
      if (use_clip_rect) Serial.println("Clip Rectangle Turned on");
      else Serial.println("Clip Rectangle turned off");
      return;
    }
    if (ich == 'd') {
      use_dma = !use_dma;
      if (use_dma) Serial.println("DMA Turned on");
      else Serial.println("DMA turned off");
      return;
    }

    if (ich == 's') {
      use_set_origin = !use_set_origin;
      if (use_set_origin) Serial.printf("Set origin to %d, %d\n", ORIGIN_TEST_X, ORIGIN_TEST_Y);
      else Serial.println("Clear origin");
      return;
    }
    if (ich == 'o')
      drawTextScreen(1);
    else if (ich == 't')
      drawTextScreen(0);
    else if (ich == 'r') {
      testDMAContUpdate();
    }
    else
      drawTestScreen();
  }

}
 
Last edited:
What is not working on 1 and 3? Everything or the DMA stuff? I will try to take a look later today.

Update:
I tried on my Flex board, with my Frame buffer output and clip test program and was able to set rotation to all four rotations. I only did some basic testing, but did not notice anything obviously not working...
Code:
#include <ili9341_t3n_font_Arial.h>
#include <ili9341_t3n_font_ArialBold.h>
#include <ILI9341_t3n.h>

#define ROTATION 3

#include "SPI.h"
#define KURTS_FLEXI
#ifdef KURTS_FLEXI
#define TFT_DC 22
#define TFT_CS 15
#define TFT_RST -1
#define TFT_SCK 14
#define TFT_MISO 12
#define TFT_MOSI 7
#define DEBUG_PIN 13
#else
#define TFT_DC  9
#define TFT_CS 10
#define TFT_RST 7
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11
#endif
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO, &SPIN);
Adafruit_GFX_Button button;
uint8_t use_dma = 0;
uint8_t use_clip_rect = 0;
uint8_t use_set_origin = 0;
uint8_t use_fb = 0;

#define ORIGIN_TEST_X 50
#define ORIGIN_TEST_Y 50

void setup() {
  while (!Serial && (millis() < 4000)) ;
  Serial.begin(115200);


  tft.begin();
  tft.setRotation(ROTATION);
  tft.fillScreen(ILI9341_BLACK);

  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
#ifdef DEBUG_PIN
  pinMode(DEBUG_PIN, OUTPUT);
#endif

  button.initButton(&tft, 200, 125, 100, 40, ILI9341_GREEN, ILI9341_YELLOW, ILI9341_RED, "UP", 1);

  drawTestScreen();
}

void SetupOrClearClipRectAndOffsets() {
  if (use_clip_rect) {
    tft.setClipRect();  // make sure we clear the whole screen
    tft.setOrigin();    // make sure none are set yet

    tft.fillScreen(ILI9341_LIGHTGREY);

    // Now lets set origin.
    if (use_set_origin)
      tft.setOrigin(ORIGIN_TEST_X, ORIGIN_TEST_Y);
    int x = tft.width() / 4;
    int y = tft.height() / 4;
    int w = tft.width() / 2;
    int h = tft.height() / 2;
    tft.drawRect(x, y, w, h, ILI9341_ORANGE);
    tft.updateScreen();
    tft.setClipRect(x + 1, y + 1, w - 2, h - 2);
    delay(250);

  } else {
    tft.setClipRect();
    if (use_set_origin)
      tft.setOrigin(ORIGIN_TEST_X, ORIGIN_TEST_Y);
    else
      tft.setOrigin();
  }
}


uint16_t palette[256];  // Should probably be 256, but I don't use many colors...
uint16_t pixel_data[2500];
const uint8_t pict1bpp[] = {0xff, 0xff, 0xc0, 0x03, 0xa0, 0x05, 0x90, 0x9, 0x88, 0x11, 0x84, 0x21, 0x82, 0x41, 0x81, 0x81,
                            0x81, 0x81, 0x82, 0x41, 0x84, 0x21, 0x88, 0x11, 0x90, 0x09, 0xa0, 0x05, 0xc0, 0x03, 0xff, 0xff
                           };
const uint8_t pict2bpp[] = {
  0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff,
  0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff,
  0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 
  0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 
  0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 
  0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 
  0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 
  0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 
  0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff,
  0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff,
  0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 
  0x55, 0x55, 0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 
  0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 
  0xaa, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 
  0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 
  0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa, 
};
const uint8_t pict4bpp[] = {  
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00,  
  0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00,  
  0x00, 0x11, 0x22, 0x22, 0x22, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x22, 0x22, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x33, 0x33, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x33, 0x33, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x33, 0x33, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x33, 0x33, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x22, 0x22, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x22, 0x22, 0x22, 0x22, 0x11, 0x00,
  0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00,  
  0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00,  
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};


                           
void drawTestScreen() {
  Serial.printf("Use FB: %d ", use_fb); Serial.flush();
  tft.useFrameBuffer(use_fb);
  SetupOrClearClipRectAndOffsets();
  uint32_t start_time = millis();
  tft.fillScreen(use_fb ? ILI9341_RED : ILI9341_BLACK);
  //tft.setFont(Inconsolata_60);
  tft.setFont(Arial_24_Bold);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(0, 0);
  tft.println("Test");
  tft.setTextColor(ILI9341_WHITE, ILI9341_RED);
  tft.println("text");
  tft.setCursor(85, 65);
  tft.print("XYZ");
  tft.setFontAdafruit();
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("01234");
  tft.setTextColor(ILI9341_WHITE, ILI9341_GREEN);
  tft.println("56789!@#$%");

  tft.drawRect(0, 150, 100, 50, ILI9341_WHITE);
  tft.drawLine(0, 150, 100, 50, ILI9341_GREEN);
  tft.fillRectVGradient(125, 150, 50, 50, ILI9341_GREEN, ILI9341_YELLOW);
  tft.fillRectHGradient(200, 150, 50, 50, ILI9341_YELLOW, ILI9341_GREEN);
  // Try a read rect and write rect
#ifdef DEBUG_PIN
  digitalWrite(DEBUG_PIN, HIGH);
#endif

  tft.readRect(0, 0, 50, 50, pixel_data);

#ifdef DEBUG_PIN
  digitalWrite(DEBUG_PIN, LOW);
#endif
  tft.writeRect(250, 0, 50, 50, pixel_data);

  // Lets try to pack this rectangle of data into 8 byte
  tft.readRect(85, 65, 50, 50, pixel_data);
  uint16_t *ppd16 = pixel_data;
  uint8_t *ppd8 = (uint8_t*)pixel_data;
  uint8_t palette_cnt = 0;
  int palette_index;
  for (int i = 0; i < 2500; i++) {
    for (palette_index = 0; palette_index < palette_cnt; palette_index++) {
      if (*ppd16 == palette[palette_index])
        break;
    }
    if (palette_index >= palette_cnt) {
      palette[palette_cnt++] = *ppd16;  // save away the color
    }
    *ppd8++ = palette_index;
    ppd16++;
  }
  tft.writeRect8BPP(200, 50, 50, 50, (uint8_t*)pixel_data, palette);
  palette[0] = ILI9341_CYAN; 
  palette[1] = ILI9341_OLIVE; 
  tft.writeRect1BPP(75, 100, 16, 16, pict1bpp, palette);
  tft.writeRect1BPP(320-90, 75, 16, 16, pict1bpp, palette);
  
  palette[2] = ILI9341_MAROON; 
  palette[3] = ILI9341_PINK; 
  tft.writeRect2BPP(75, 125, 32, 16, pict2bpp, palette);

  tft.writeRectNBPP(15, 125, 32, 16, 2, pict2bpp, palette);
  tft.writeRectNBPP(75, 150, 16, 16, 4, pict4bpp, palette);

  // Try drawing button
  tft.setFontAdafruit();
  button.drawButton();

  if (use_dma) {
    tft.startUpdateScreenDMA(); 
  } else {
    tft.updateScreen();
  }
  Serial.println(millis() - start_time, DEC);

  if (use_dma && use_fb) {
    delay(500);
    Serial.printf("DMA error status: %x\n", DMA_ES);
  }

  use_fb = use_fb ? 0 : 1 ;
  Serial.println(use_fb, DEC);


}

void drawTextScreen(bool fOpaque) {
  SetupOrClearClipRectAndOffsets();
  uint32_t start_time = millis();
  tft.useFrameBuffer(use_fb);
  tft.fillScreen(use_fb ? ILI9341_RED : ILI9341_BLACK);
  tft.setFont(Arial_40_Bold);
  if (fOpaque)
    tft.setTextColor(ILI9341_WHITE, use_fb ? ILI9341_BLACK : ILI9341_RED);
  else
    tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(0, 5);
  tft.println("AbCdEfGhIj");
  tft.setFont(Arial_28_Bold);
  tft.println("0123456789!@#$");
#if 1
  tft.setFont(Arial_20_Bold);
  tft.println("abcdefghijklmnopq");
  tft.setFont(Arial_14_Bold);
  tft.println("ABCDEFGHIJKLMNOPQRST");
  tft.setFont(Arial_10_Bold);
  tft.println("0123456789zyxwvutu");
#endif
  tft.updateScreen();

  Serial.printf("Use FB: %d OP: %d, DT: %d OR: %d\n", use_fb, fOpaque, use_set_origin, millis() - start_time);
}

//=============================================================================
// Try continuous update
//=============================================================================
void testDMAContUpdate() {
  // Force frame buffer on
  Serial.printf("continuous DMA udpate test - Frame mode on\n"); Serial.flush();
      use_fb = 1; //
  
  tft.useFrameBuffer(use_fb);
  tft.fillScreen(ILI9341_GREEN);

  tft.startUpdateScreenDMA(true);

  uint32_t frame_count;  

  while ((frame_count = tft.frameCount()) < 10) yield();
  tft.fillScreen(ILI9341_YELLOW);

  while ((frame_count = tft.frameCount()) < 20) yield();
  tft.fillScreen(ILI9341_RED);

  while ((frame_count = tft.frameCount()) < 30) yield();
  tft.fillScreen(ILI9341_BLACK);

  while ((frame_count = tft.frameCount()) < 40) yield();

  tft.setCursor(0, 100);
  tft.setFont(Arial_20_Bold);
  tft.println("DONE");

  tft.endUpdateScreenDMA();

  Serial.println("Finished test");


}

void loop(void) {
  // See if any text entered
  int ich;
  if ((ich = Serial.read()) != -1) {
    while (Serial.read() != -1) delay(1);
    if (ich == 'c') {
      use_clip_rect = !use_clip_rect;
      if (use_clip_rect) Serial.println("Clip Rectangle Turned on");
      else Serial.println("Clip Rectangle turned off");
      return;
    }
    if (ich == 'd') {
      use_dma = !use_dma;
      if (use_dma) Serial.println("DMA Turned on");
      else Serial.println("DMA turned off");
      return;
    }

    if (ich == 's') {
      use_set_origin = !use_set_origin;
      if (use_set_origin) Serial.printf("Set origin to %d, %d\n", ORIGIN_TEST_X, ORIGIN_TEST_Y);
      else Serial.println("Clear origin");
      return;
    }
    if (ich == 'o')
      drawTextScreen(1);
    else if (ich == 't')
      drawTextScreen(0);
    else if (ich == 'r') {
      testDMAContUpdate();
    }
    else
      drawTestScreen();
  }

}


Here is the test code I used, it works fine with 0 and 2 but 1 and 3 scramble the text.

Code:
#include "SPI.h"
#include <ILI9341_t3DMA.h>

#define TFT_DC      9
#define TFT_CS      10
#define TFT_RST     8  // 255 = unused, connect to 3.3V
#define TFT_MOSI    11
#define TFT_SCLK    13
#define TFT_MISO    12

ILI9341_t3DMA tft = ILI9341_t3DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);

void setup() {

  tft.begin(); 
  tft.setRotation(1); //broken
  tft.dfillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(2);
  tft.println("Waiting for Arduino Serial Monitor...");
  tft.refreshOnce();
  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("ILI9341 Test!"); 
  tft.refreshOnce();

}


void loop(void) {
    



}
 
Wrong library ;) That is Frank's library, mine is ILI9341_t3n.
I did borrow some of Frank's stuff, but then updated it to work in all orientations, plus merged in lots of stuff, that had Pull requests for the main library, plus...

Here is a version of your above, using my Frame buffer stuff.

Code:
#include "SPI.h"
#include <ILI9341_t3n.h>
#define KURTS_FLEXI
#ifdef KURTS_FLEXI
#define TFT_DC 22
#define TFT_CS 15
#define TFT_RST -1
#define TFT_SCLK 14
#define TFT_MISO 12
#define TFT_MOSI 7
#define DEBUG_PIN 13
#else
#define TFT_DC      9
#define TFT_CS      10
#define TFT_RST     8  // 255 = unused, connect to 3.3V
#define TFT_MOSI    11
#define TFT_SCLK    13
#define TFT_MISO    12
#endif
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);

void setup() {

  tft.begin();
  tft.useFrameBuffer(true);
  tft.setRotation(1); //broken
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(2);
  tft.println("Waiting for Arduino Serial Monitor...");
  tft.updateScreen();
  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("ILI9341 Test!");
  tft.println("Connected!");
  tft.updateScreen();

}


void loop(void) {


}
 
Wrong library ;) That is Frank's library, mine is ILI9341_t3n.
I did borrow some of Frank's stuff, but then updated it to work in all orientations, plus merged in lots of stuff, that had Pull requests for the main library, plus...

Here is a version of your above, using my Frame buffer stuff.

Code:
#include "SPI.h"
#include <ILI9341_t3n.h>
#define KURTS_FLEXI
#ifdef KURTS_FLEXI
#define TFT_DC 22
#define TFT_CS 15
#define TFT_RST -1
#define TFT_SCLK 14
#define TFT_MISO 12
#define TFT_MOSI 7
#define DEBUG_PIN 13
#else
#define TFT_DC      9
#define TFT_CS      10
#define TFT_RST     8  // 255 = unused, connect to 3.3V
#define TFT_MOSI    11
#define TFT_SCLK    13
#define TFT_MISO    12
#endif
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);

void setup() {

  tft.begin();
  tft.useFrameBuffer(true);
  tft.setRotation(1); //broken
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(2);
  tft.println("Waiting for Arduino Serial Monitor...");
  tft.updateScreen();
  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("ILI9341 Test!");
  tft.println("Connected!");
  tft.updateScreen();

}


void loop(void) {


}

Well bah, I took it from your Github :rolleyes:
 
KurtE, been busy prepping for IRMA. Took a look at your example on post 88, for some reason when I compile the IDE it says it only needs 5,272 bytes of memory, shouldn't the Frame Buffer eat up far more then that?
 
Well bah, I took it from your Github
Yep - I forked his library, in order to make some changes and make Pull Requests....
KurtE, been busy prepping for IRMA. Took a look at your example on post 88, for some reason when I compile the IDE it says it only needs 5,272 bytes of memory, shouldn't the Frame Buffer eat up far more then that?
It malloc's the memory as the library can be and, and is most often used without using the frame buffer, especially on everything but the T3.6
 
Hello again KurtE, hoping to get back to playing with this now that I have most of the IRMA damage cleaned up. Is there a way to force the frame buffer to be always on instead of using malloc? It makes it hard to tell how much usable space I will have for other things when a large chunk is invisible until needed.
 
Hope you did not get too much damage!

I have a version of the code where I did not use malloc (was experimenting with DMAMEM...) but I don't think I ever pushed that version up.

My feeling is that I do not want to allocate a frame buffer unless an app actually uses one...

But it should not be hard to make a version where you allocate it...

That is if you allocate your own buffer:
Code:
uint16_t frame_buffer[320*240];    // define your own buffer.
Then modify the ili9341_t3n library header file (.h), right where you see:
Code:
uint8_t useFrameBuffer(boolean b); // use the frame buffer?  First call will allocate

We could add a new method:
Code:
void setFrameBuffer(uint16_t *buf) {_pfbtft = buf;}

Then add a call to this in your setup function before you ever call useFrameBuffer... The useFrameBuffer will see that _pfbtft and not allocate it... Note: what I show here does not do any validity checking and would need to be careful not to have the free method called. My guess no one actually has their tft object destroyed anyway.

If I get a chance I will try it out, but if you feel like it, should not be hard to try out... And if it works well. You could issue Pull request ;)
 
I guess the better question is. Which option would work better for my application. I'm trying to avoid spending large amounts of CPU time updating the screen.
I would like to have an open loop running in the 5Khz range but the screen would probably be the most intensive thing I need to do in some cases. I have a few dozen math operations per cycle, the ADC grunt work will be DMA so I will just be moving the data around and crunching numbers for that. I'm sure there will be other "Features" I add that will have there own CPU needs, but right now updating the screen without eating up tons of CPU time is my biggest concern. I'm actually considering just running the screen from a separate T3.2 like I did with my Electric Gocart Project. But if I can avoid the extra cost and just use whats on the T3.6 that would be nice, I'm just having a hard time figuring out what I need.

I have the PCB and the Acrylic Case 98% designed, I just need to verify my circuits and code will work. And figure out if there is anything else I should add.. (like the hardware over current detection I just jotted down at work during break lol)
 
Hard to say what is the best way to go. It all depends on your needs and the like.

I just pushed up a new branch of the library: https://github.com/KurtE/ILI9341_t3n/tree/Async-Support

Which is merging in the stuff from my try dma branch... Will like to get this into master soon...
Note: It uses my latest versions of SPIN... Which is setup to use the current versions of SPI...

I renamed several of the Async support functions, to get rid of the lets DMA and go more with Async

So now you still can explicitly have the screen update without using DMA and wait for it to complete using: updateScreen();
But you can also do this async using DMA: with the function: updateScreenAsync();
Note: there is an optional variable that is if you wish to simply have the update only happen once (default) or continuous. If you go continuous you can end it using the method:
endUpdateAsync... If you have an Async operation active, you can wait for it to complete with: waitUpdateAsyncComplete()
You can find out if an async is still active: ayncUpdateActive()
And you can get a frame count of how many times screen was updated: ...

Note: There may be an issue stopping the Async updates... need to investigate... I don't typically use this as I prefer to be in control. That is I would prefer to do all of the updates to the screen then update again than have parts of update on one refresh and other parts on the next refresh... Especially if you do things like: erase (fillRect or fillScreen) to background and then draw new stuff. When you do the updates yourself you can avoid flashes, but if continuous updates are happening, then you risk seeing part or all of the output of fill screen on one frame and then new stuff on next....

I added the ability to pass in your own frame buffer.
Code:
// Let's allocate the frame buffer ourself. 
uint16_t tft_frame_buffer[ILI9341_TFTWIDTH * ILI9341_TFTHEIGHT];
...
void setup() {
...

  tft.begin();
  tft.setFrameBuffer(tft_frame_buffer);
...
This gives you the choice to simply allocate it like this if you would like. You can also try putting it into DMAMEM area like:
Code:
DMAMEM uint16_t ili9341_frame_buffer[ILI9341_TFTWIDTH*ILI9341_TFTHEIGHT];
Which may speed up access

Again soon I will migrate this branch into master.
 
Ug, its always something. Was going to try the Async version but not sure what the SPINClass should be set to.....

Code:
#include "SPI.h"
#include <ILI9341_t3n.h>
#define TFT_DC      9
#define TFT_CS      10
#define TFT_RST     8  // 255 = unused, connect to 3.3V
#define TFT_MOSI    11
#define TFT_SCLK    13
#define TFT_MISO    12

ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, [B]???????[/B]);
uint16_t tft_frame_buffer[ILI9341_TFTWIDTH * ILI9341_TFTHEIGHT];



void setup() {

  tft.begin();
  tft.setFrameBuffer(tft_frame_buffer);
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(2);
  tft.println("Waiting for Arduino Serial Monitor...");
  tft.updateScreen();
  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("ILI9341 Test!");
  tft.println("Connected!");
  tft.updateScreen();

}


void loop(void) {


}

Code:
D:\Arduino\hardware\teensy\avr\libraries\ILI9341_t3n\ILI9341_t3n.cpp: In constructor 'ILI9341_t3n::ILI9341_t3n(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, SPINClass*)':

D:\Arduino\hardware\teensy\avr\libraries\ILI9341_t3n\ILI9341_t3n.cpp:103:28: error: 'class SPINClass' has no member named 'port'

  _pkinetisk_spi = &_pspin->port();

                            ^

D:\Arduino\hardware\teensy\avr\libraries\ILI9341_t3n\ILI9341_t3n.cpp: In member function 'void ILI9341_t3n::begin()':

D:\Arduino\hardware\teensy\avr\libraries\ILI9341_t3n\ILI9341_t3n.cpp:1456:31: error: 'class SPINClass' has no member named 'port'

     _pkinetisk_spi = &_pspin->port();

                               ^

D:\Arduino\hardware\teensy\avr\libraries\ILI9341_t3n\ILI9341_t3n.cpp:1465:32: error: 'class SPINClass' has no member named 'port'

      _pkinetisk_spi = &_pspin->port();

                                ^

Error compiling for board Teensy 3.6.
 
You probably need to update to a later version of SPIN. With the newer releases of Teensyduino and the rework of SPI, the newer SPIN code was updated to be closer to SPI code... Goal, get enough functionality into SPI to make SPIN no longer needed. If that becomes a problem, can try to build a version again using old SPIN...
 
You probably need to update to a later version of SPIN. With the newer releases of Teensyduino and the rework of SPI, the newer SPIN code was updated to be closer to SPI code... Goal, get enough functionality into SPI to make SPIN no longer needed. If that becomes a problem, can try to build a version again using old SPIN...

Using the latest SPIN from your github. I'll play some more with it after work.
 
:eek: - Looks like I have not migrated the SPIN stuff to the master branch :0 -

In the mean time you might try the SPIN branch - WIP-SPIN-1-CLASS

I probably should have archived the earlier master of ILI9341_t3n to use with older SPI implementations...
 
I merged that branch into master... I also kept a version for those who need Pre SPI as one class version...
 
Back
Top