ST7789 screen driver

You probably can.

We already made an st7735/89 driver that is installed with Teensyduino (Or teensy builds in Arduino 2.x builds).
st7735_t3 which is based off my ili9341_t3n library.

https://github.com/PaulStoffregen/ST7735_t3

It does not work the same way as vvindar's _t4 version, but we do have things like frame buffers and async updates, graphic primitives and the like.
 
There are probably some simple things that can be done to fix some of that. Like maybe it is not calling to set the screen orientation. At some point maybe will take a look.
 
quick update. I have not tried yet with ST7735 yet, will do that very soon.

I have made a version of the TGX 2d examples for T4 that run using the ili9341_t3n library. It is using the frame buffer, plus some hacks that compute how much each frame changed and to try to restrict to only update the bounding rect of that.

Note; the ili9341_t4 library has somethings in it that the _t3n currently does not have, like looking at the scan line, or computing sections of the display that need to updated....

If anyone wants to try it out. Note: I did quick and dirty for pin numbers and tft object define to match my Teensy Micromod board.
 

Attachments

  • AntiAliasedClock_ili9341_t3n-230404a.zip
    226.1 KB · Views: 31
  • CrazyClock_ili9341_t3x-230404a.zip
    167 KB · Views: 34
Another quick update:

I have the crazy clock running on the ST7789 320x240 size.

All I changed was the header files.
Code:
#define USE_ST7789
// This example runs on teensy 4.0/4.1 with ILI9341 via SPI.
// the screen driver library : https://github.com/vindar/ILI9341_T4
//#include <ILI9341_T4.h>
#ifdef USE_ST7789
#include <ST7735_t3.h> // Hardware-specific library
#include <ST7789_t3.h> // Hardware-specific library
#else
#include <ILI9341_t3n.h>
#endif

The object defines:
Code:
#ifdef USE_ST7789
ST7789_t3 tft = ST7789_t3(TFT_CS, TFT_DC, TFT_RST);
#else
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST);
#endif

and the init/begin:
Code:
  #ifdef USE_ST7789
  tft.init(240, 320);  // Init ST7789 320x240
  #else
  tft.begin(SPI_SPEED);
  #endif
Two of my Micromod boards, one with ILI9341 mounted on back and the 2nd with ST7789 on front
Screenshot.png

Edit: I uploaded those changes here as I also updated the sketch to use the clipping of the output code...
 

Attachments

  • CrazyClock_ili9341_t3x-230404a.zip
    167.5 KB · Views: 33
Quick update on some of this stuff.

Yesterday I did some updates to my ili9341_t3n library as well as the ST7735_t3 (includes st7789), for some of this stuff.

the ILI9341_t3n library had some code we were trying out awhile back to have it compute a bounding rectangle what area of the frame buffer is dirty (changed) and if option is set, then updateScreen will only update that area.

I fixed a bug in this code, plus:
update writeRect that in frame buffer mode, it used to say the whole rectangle was updated. This code now checks if a pixel color changes and the dirty region now is the rectangle that bounds all of these changed pixels, unioned with previous dirty region.

This appears to be working with the example sketch (so far only updated the Anti aliased clock sketch. With this the code I used to update the screen from what the graphics library fb was changed from:
Code:
void update_display(bool force_whole_display) {
  if (!force_whole_display) {
    // look for bounding range of changes.
    uint16_t first_changed_x = tft.width();
    uint16_t last_changed_x = 0;
    uint16_t first_changed_y = tft.height();
    uint16_t last_changed_y = 0;

    for (uint16_t y = 0; y < tft.height(); y++) {
      uint16_t* ptftfb_y = &ib[y * tft.width()];
      uint16_t* pimage_newfb_y = &fb[y * tft.width()];
      uint16_t x;
      for (x = 0; x < tft.width(); x++) {
        // find first if any change in line.
        if (ptftfb_y[x] != pimage_newfb_y[x]) {
          if (first_changed_y == tft.height()) first_changed_y = y;
          last_changed_y = y;
          if (x < first_changed_x) first_changed_x = x;
          break;
        }
      }
      // find last change in line
      if (x < tft.width()) {
        for (x = tft.width() - 1; x > last_changed_x; x--) {
          if (ptftfb_y[x] != pimage_newfb_y[x]) {
            last_changed_x = x;  //
            break;
          }
        }
      }
    }
    // now have the bounds
    tft.setClipRect(first_changed_x, first_changed_y, (last_changed_x - first_changed_x) + 1, (last_changed_y - first_changed_y) + 1);
    static uint8_t debug_count = 20;
    if (debug_count) {
      Serial.printf("(%u, %u), (%u, %u)\n", first_changed_x, last_changed_x, first_changed_y, last_changed_y );
      debug_count--;
    }

  } else {
    tft.setClipRect();
  }
  memcpy(ib, fb, sizeof(fb));
  tft.updateScreen();  // simply update.
}

To simply
Code:
void update_display(bool force_whole_display) {
  if (force_whole_display) {
      tft.setClipRect();
      tft.updateScreen();
      return;
  }

  // lets try writeRect
  tft.writeRect(0, 0, tft.width(), tft.height(), fb);
  tft.updateChangedAreasOnly(true); // really only need to call this once. 
  tft.updateScreen();  // simply update.

}
And this code simplified farther as I really don't need the force whole display stuff.

I then merged these dirty region changes into the ST77xx code and verified that the updates were only drawing sub-region of the clock.

There are still changes I will do over time, like I believe a few graphic primitives don't currently update this dirty region computation.
Plus I could update more of these type primitives to not marked the whole rectangle but only the dirty regions.

But first I will probably merge this dirty region stuff into ILI9488 code and will probably change the test code to at first maybe leave the TGX frame buffer at 320x240 as the example code I believe depends on this to look right. And then will have the writeRect, center it on the display

More playing
 
Quick update on some of this stuff.

Yesterday I did some updates to my ili9341_t3n library as well as the ST7735_t3 (includes st7789), for some of this stuff.

the ILI9341_t3n library had some code we were trying out awhile back to have it compute a bounding rectangle what area of the frame buffer is dirty (changed) and if option is set, then updateScreen will only update that area.

I fixed a bug in this code, plus:
update writeRect that in frame buffer mode, it used to say the whole rectangle was updated. This code now checks if a pixel color changes and the dirty region now is the rectangle that bounds all of these changed pixels, unioned with previous dirty region.

This appears to be working with the example sketch (so far only updated the Anti aliased clock sketch. With this the code I used to update the screen from what the graphics library fb was changed from:
Code:
void update_display(bool force_whole_display) {
  if (!force_whole_display) {
    // look for bounding range of changes.
    uint16_t first_changed_x = tft.width();
    uint16_t last_changed_x = 0;
    uint16_t first_changed_y = tft.height();
    uint16_t last_changed_y = 0;

    for (uint16_t y = 0; y < tft.height(); y++) {
      uint16_t* ptftfb_y = &ib[y * tft.width()];
      uint16_t* pimage_newfb_y = &fb[y * tft.width()];
      uint16_t x;
      for (x = 0; x < tft.width(); x++) {
        // find first if any change in line.
        if (ptftfb_y[x] != pimage_newfb_y[x]) {
          if (first_changed_y == tft.height()) first_changed_y = y;
          last_changed_y = y;
          if (x < first_changed_x) first_changed_x = x;
          break;
        }
      }
      // find last change in line
      if (x < tft.width()) {
        for (x = tft.width() - 1; x > last_changed_x; x--) {
          if (ptftfb_y[x] != pimage_newfb_y[x]) {
            last_changed_x = x;  //
            break;
          }
        }
      }
    }
    // now have the bounds
    tft.setClipRect(first_changed_x, first_changed_y, (last_changed_x - first_changed_x) + 1, (last_changed_y - first_changed_y) + 1);
    static uint8_t debug_count = 20;
    if (debug_count) {
      Serial.printf("(%u, %u), (%u, %u)\n", first_changed_x, last_changed_x, first_changed_y, last_changed_y );
      debug_count--;
    }

  } else {
    tft.setClipRect();
  }
  memcpy(ib, fb, sizeof(fb));
  tft.updateScreen();  // simply update.
}

To simply
Code:
void update_display(bool force_whole_display) {
  if (force_whole_display) {
      tft.setClipRect();
      tft.updateScreen();
      return;
  }

  // lets try writeRect
  tft.writeRect(0, 0, tft.width(), tft.height(), fb);
  tft.updateChangedAreasOnly(true); // really only need to call this once. 
  tft.updateScreen();  // simply update.

}
And this code simplified farther as I really don't need the force whole display stuff.

I then merged these dirty region changes into the ST77xx code and verified that the updates were only drawing sub-region of the clock.

There are still changes I will do over time, like I believe a few graphic primitives don't currently update this dirty region computation.
Plus I could update more of these type primitives to not marked the whole rectangle but only the dirty regions.

But first I will probably merge this dirty region stuff into ILI9488 code and will probably change the test code to at first maybe leave the TGX frame buffer at 320x240 as the example code I believe depends on this to look right. And then will have the writeRect, center it on the display

More playing

Nice work @KurtE. Updates to Graphics libs never stop do they.
 
I tried using st7735_t3 with this https://github.com/vindar/tgx using a framebuffer but if i rotate the screen everything gets scrambled on the screen and it also updates the whole screen and not only the parts that change.

Bolimpa, were you able to get the 1.9" 170x320 screen working? I also have it. It works with the Adafruit library but not with the Teensy ST7735/ST7789.

Kurt, would you happen to know what I would need to modify to get the 170x320 resolution working?
 
Bolimpa, were you able to get the 1.9" 170x320 screen working? I also have it. It works with the Adafruit library but not with the Teensy ST7735/ST7789.

Kurt, would you happen to know what I would need to modify to get the 170x320 resolution working?
Probably.
We need to change in ST7789_t3.cpp/.h, the init method as well as the setRotation, and make it a little more generic, like Adafruit did.

That is init needs to define where the start row, columns are, and they define two sets instead of 1 such that the setRotation can use the 2nd set for two of the orientations, instead of trying to compute it...

I will try to do a quick update later this morning, when I am more awake
 
That's awesome! I did see the difference in the init in the adafruit code but wasn't sure how to make it work with the existing code. If you can make an update that would be really, really great. Thank you!
 
Back
Top