ST7789_t3 (part of ST7735 library) support for displays without CS pin

@mjs513 - Good morning (almost 5am)...

Looks good on ReadMe...

A couple of things that might be mentioned (or not)..

Since the smaller ST7735 and maybe ST7789 displays have fewer pixels, you can on some of them enable a frame buffer on a T3.2 as well. I believe in this case I did add support for Async updates as well.

If the Teensy has more than one SPI buss. And the IO pins are all on a different SPI buss than that buss will be used. (i.e. you can use SPI1 or SPI2).

With this, on a board such as a T4 or T3.5 or T3.6 you can potentially have three displays all on different SPI busses and using the Async updates you can have all three of them updating their display at the same time.

(Now a few minutes after 5 as had to take dogs out)
 
@mjs513 - Good morning (almost 5am)...

Looks good on ReadMe...

A couple of things that might be mentioned (or not)..

Since the smaller ST7735 and maybe ST7789 displays have fewer pixels, you can on some of them enable a frame buffer on a T3.2 as well. I believe in this case I did add support for Async updates as well.

If the Teensy has more than one SPI buss. And the IO pins are all on a different SPI buss than that buss will be used. (i.e. you can use SPI1 or SPI2).

With this, on a board such as a T4 or T3.5 or T3.6 you can potentially have three displays all on different SPI busses and using the Async updates you can have all three of them updating their display at the same time.

(Now a few minutes after 5 as had to take dogs out)
That's early morning its 8:30 here. I updated the readme with your suggested changes.
 
Done! PR submitted. Now I feel better. It was just one of those things that was hanging out there - always bad on documentation. :)
 
I have been taking a diversion from some of my other diversions, and thought I would play around with some of the stuff in the st7735_t3 library.

We have been doing different things over the months of trying to make more of our display drivers more compatible with each other, so I thought I would do a quick test,

So I wondered how hard it would be to convert the RA8875 clock or clock2 to ST7789 in current case 240x240...

Not hard... But then wondered what if I displayed a background image how bad would the clock look if there was an image.

I did a real quick and dirty of then enable frame buffer, down image, draw clock, draw hands, tell system to redraw screen. And I ran into some issues, things were not drawing correct with the Frame buffer...

So this morning fixed that. I pushed up to current working branch with open PR... https://github.com/KurtE/ST7735_t3/tree/ili9341_fonts_maybe_center

Clock hands could improve. Wonder if anyone has a simple rotate draw image, where you can pass in maybe bitmap, sizes, center point and delta angle and maybe a what color is transparent...

May have to play later
 

Attachments

  • ST77xx_clock-200128b.zip
    201.7 KB · Views: 91
Simple update...

I am playing around with drawing the hands, using the idea of rotating logical bitmap that did a quick and dirty define for in the sketch...

It ain't perfect, but did find a bug or two...

IMG_1058.jpg

The hour and minute hands use two different ways to try to figure out best way to rotate the image. The hour hand was done straight forward walk through bitmap if bit is set,
then convert the image in 2d (https://academo.org/demos/rotation-about-point/) and then displayed.... But I thought it was leaving holes in the output.

Second way was to figure out rough area that might be updated on screen, then for each screen point in the region convert to image position (and see if that bit is set...


There are probably a lot cleaner ways, but was a fun exercise for someone whose math is beyond rusty!
 

Attachments

  • ST77xx_clock-200130b.zip
    203.1 KB · Views: 113
Hi there, I'm having problems trying to use this library with hardware SPI1,
Code:
#define TFT_CS 0 
#define TFT_RST -1 //wired to +3v3
#define TFT_DC  9 
#define TFT_BACKLIGHT -1 // wired to +3v3
#define TFT_MOSI 26  
#define TFT_SCLK 27 

// this works:
ST7789_t3 display = ST7789_t3(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

// this complies but does not display anything
//ST7789_t3 display = ST7789_t3(TFT_CS, TFT_DC, TFT_RST);[CODE]

Any help would be much appreciated
 
Hi there, I'm having problems trying to use this library with hardware SPI1,
Code:
#define TFT_CS 0 
#define TFT_RST -1 //wired to +3v3
#define TFT_DC  9 
#define TFT_BACKLIGHT -1 // wired to +3v3
#define TFT_MOSI 26  
#define TFT_SCLK 27 

// this works:
ST7789_t3 display = ST7789_t3(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

// this complies but does not display anything
//ST7789_t3 display = ST7789_t3(TFT_CS, TFT_DC, TFT_RST);[CODE]

Any help would be much appreciated[/QUOTE]

Yes you need to specify the SPI1 specific pins to make it work, otherwise it does not know you are trying to use SPI1... 

Thought of adding one to be more compatible with Adafruit library: like:
[CODE]  Adafruit_ST7789(SPIClass *spiClass, int8_t cs, int8_t dc, int8_t rst);

But have not and if we did I would guess Paul would prefer we added more like: ST7789_t3(SPIClass &spiClass, int8_t cs, int8_t dc, int8_t rst);
 
Yes you need to specify the SPI1 specific pins to make it work, otherwise it does not know you are trying to use SPI1...

Thought of adding one to be more compatible with Adafruit library: like:
Code:
  Adafruit_ST7789(SPIClass *spiClass, int8_t cs, int8_t dc, int8_t rst);

But have not and if we did I would guess Paul would prefer we added more like: ST7789_t3(SPIClass &spiClass, int8_t cs, int8_t dc, int8_t rst);

and how can I do that? the defined pins are already SPI1 for Teensy4.0 (0, 26,27...1 is MISO, not used)
by modifying the library?

I've seen this on ST7735_t3.h:
Code:
#if defined(__IMXRT1062__)  // Teensy 4.x
  SPIClass *_pspi = nullptr;
  uint8_t   _spi_num = 0;          // Which buss is this spi on? 
  IMXRT_LPSPI_t *_pimxrt_spi = nullptr;
  SPIClass::SPI_Hardware_t *_spi_hardware;
also this on ST7735_t3.cpp:
Code:
#elif defined(__IMXRT1062__)  // Teensy 4.x 
	if (_sid == (uint8_t)-1) _sid = 11;
	if (_sclk == (uint8_t)-1) _sclk = 13;
	if (SPI.pinIsMOSI(_sid) && SPI.pinIsSCK(_sclk)) {
		_pspi = &SPI;
		_spi_num = 0;          // Which buss is this spi on? 
		_pimxrt_spi = &IMXRT_LPSPI4_S;  // Could hack our way to grab this from SPI object, but...

	} else if (SPI1.pinIsMOSI(_sid) && SPI1.pinIsSCK(_sclk)) {
		_pspi = &SPI1;
		_spi_num = 1;          // Which buss is this spi on? 
		_pimxrt_spi = &IMXRT_LPSPI3_S;
	} else if (SPI2.pinIsMOSI(_sid) && SPI2.pinIsSCK(_sclk)) {
		_pspi = &SPI2;
		_spi_num = 2;          // Which buss is this spi on? 
		_pimxrt_spi = &IMXRT_LPSPI1_S;
	} else _pspi = nullptr;

	if (_pspi) {
		hwSPI = true;
		_pspi->begin();
		_pending_rx_count = 0;
		_spiSettings = SPISettings(ST7735_SPICLOCK, MSBFIRST, mode);
		_pspi->beginTransaction(_spiSettings); // Should have our settings. 
		_pspi->transfer(0);	// hack to see if it will actually change then...
		_pspi->endTransaction();
		_spi_tcr_current = _pimxrt_spi->TCR; // get the current TCR value 
//		uint32_t *phack = (uint32_t* )&_spiSettings;
//		Serial.printf("SPI Settings: TCR: %x %x (%x %x)\n", _spi_tcr_current, _pimxrt_spi->TCR, phack[0], phack[1]);
		// Hack to get hold of the SPI Hardware information... 
	 	uint32_t *pa = (uint32_t*)((void*)_pspi);
		_spi_hardware = (SPIClass::SPI_Hardware_t*)(void*)pa[1];
 
Hi there, I still not being able to make the display to work with hardware SPI1, and I think the selected pins are correct,
also I would like to know which SPI configuration is the most appropriate,
using Teensy 4.0

Code:
SPISettings ADCSettings(48000000, MSBFIRST, SPI_MODE0)
#define TFT_CS 0
#define TFT_RST -1 //wired to +3v3
#define TFT_DC 9
#define TFT_BACKLIGHT -1 // wired to +3v3
#define TFT_MOSI 26
#define TFT_SCLK 27
 
I'm giving you a bump to see if you got it working. I'm in the same boat and looking for a solution. Bought two displays (always buy two) off AMZN and need to get one working on my project.
 
Hi I found an issue with this library when using it for 240x320 displays, useFrameBuffer(true) and updateScreenAsync(),
it basically makes glitches which is more noticeable with oblique lines, which are 'repeated' and doted across the display, made a very simple test (to be sure it was not the rest of my code)
without useFrameBuffer:
test2.jpg
with useFrameBuffer:
test1.jpg
could this issue be fixed easily? any recommendation?
any help would be much appreciated
also still not being able to use hardware SPI1...but that's another story

here's the test code I used:
Code:
#define TFT_CS        0 // chip select
#define TFT_RST       -1// Display reset
#define TFT_DC        9 // Display data/command select
#define TFT_BACKLIGHT -1 // Display backlight pin
#define TFT_MOSI 26  // Data out
#define TFT_SCLK 27 
#include <ST7789_t3.h>
#include <st7735_t3_font_Arial.h>
#define BLACK 0x0000
#define WHITE 0xFFFF

ST7789_t3 display = ST7789_t3(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

int x, y, x2, y2;

void setup()
{
    display.init(240, 320);
    display.useFrameBuffer(true);
    display.invertDisplay(false);
    display.setRotation(1);
    display.setTextWrap(false);
    display.fillScreen(BLACK);
    display.fillRect(0, 0, 320, 240, BLACK);
}
void loop()
{
    for(int i = 0; i < 3; i++)
    {
        x2 = random(0, 240);
        y2 = random(0, 240);
        display.drawLine(x, y, x2, y2, WHITE);
        x = x2;
        y = y2;
    }
    display.updateScreenAsync();
    delay(500);
}
 
Simple fix: in St7735_t3.h Pixel function. About line 836
Should use the variable _width and not _screenWidth.

thanks @KurtE
that solved that particular issue, but I still have lots of glitches with useFrameBuffer,
here's another example, with useFrameBuffer(false)
IMG_20221213_103828.jpg
with useFrameBuffer(true)
IMG_20221213_103745.jpg
example code:
Code:
#define TFT_CS        0 // PyBadge/PyGamer display control pins: chip select
#define TFT_RST       -1//255 // Display reset
#define TFT_DC        9 // Display data/command select
#define TFT_BACKLIGHT -1//255 // Display backlight pin
#define TFT_MOSI 26  // Data out
#define TFT_SCLK 27 
#include <ST7789_t3.h>
#include <st7735_t3_font_Arial.h>
#define BLACK 0x0000
#define WHITE 0xFFFF
ST7789_t3 display = ST7789_t3(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

void setup()
{
    display.init(240, 320);
    display.useFrameBuffer(true);
    display.invertDisplay(false);
    display.setRotation(1);
    display.setTextWrap(false);
    display.fillScreen(BLACK);
    display.setTextColor(WHITE);
    display.setFont(Arial_16);
}

void loop()
{
    char x;
    int r = 0;
    for(int i = 0; i < 200; i++) {
        r++;
        if( r == 20) {
            display.print("\n");
            r = 0;
        }
        x = i;
        display.print(x);
        display.updateScreenAsync();
    }
    display.fillRect(0, 0, 320, 240, BLACK);
    display.setCursor(0, 0);
}
 
That one is usage error! Note: I am not necessarily saying there are no other bugs.

You are writing to the frame buffer while the DMA operation is reading from the frame buffer.
And if this is a T4.x and you did not set a frame buffer, it will malloc it, which comes from RAM2
Which adds other interesting wrinkles. That is, the operations write to memory, which goes through the cache
But DMA goes to the actual memory. So if you do nothing, about synchronizing the two, you end up with
holes and bleed through. The updateScreenAsync call has code that sees the buffer is in high memory and does the call to flush
the cache, before it starts the operation. But you then muck with some of the memory.

But the biggest issue is then when you get to the end of your loop, you fill screen to black, which on my screen is white because of your invert
and don't do another update screen, so some of the physical memory is updated and some is not...

So if you wish to see if the operations are working or not when going to the cache, you typically have two choices.

1) Don't use the Async call: For example this version works for me:
Code:
#define TFT_DC 9
#define TFT_CS 32
#define TFT_RST 31
#include <ST7789_t3.h>
#include <st7735_t3_font_Arial.h>
#define BLACK 0x0000
#define WHITE 0xFFFF
ST7789_t3 display = ST7789_t3(TFT_CS, TFT_DC, TFT_RST);

void setup() {
  display.init(240, 320);
  display.useFrameBuffer(true);
  display.invertDisplay(false);
  display.setRotation(1);
  display.setTextWrap(false);
  display.fillScreen(BLACK);
  display.setTextColor(WHITE);
  display.setFont(Arial_16);
}

void loop() {
  char x;
  int r = 0;
  for (int i = 0; i < 200; i++) {
    r++;
    if (r == 20) {
      display.print("\n");
      r = 0;
    }
    x = i;
    display.print(x);
    display.updateScreen();
  }
  delay(1000);
  display.fillRect(0, 0, 320, 240, BLACK);
  display.updateScreen();
  display.setCursor(0, 0);
}

2) Wait for the Aynch operation is complete before mucking with the memory.
Like at start of loop, call: display.waitUpdateAsyncComplete();

3) Sorry could not count - if you can allocate buffer in lower memory, the issue won't show up as much, as in this case you are not mucking with what the previous frame did:
Code:
uint16_t my_frame_buffer[320*240];

void setup() {
  display.init(240, 320);
  display.setFrameBuffer(my_frame_buffer);
  display.useFrameBuffer(true);
...

4) Double buffer - Use two buffers (assuming you have enough memory), you fill one, and do the async update, while it is outputting it's frame, you fill up the second buffer... More complicated solution, requires knowing when you tell it to use a frame buffer, and when to do the next call to UpdteScreenAsync This was used in cases like movie frames, where while the screen is updating, you are loading in the next frame. There is no magic that synchronizes the two frames...

5) Sort of like 4) but with one buffer. You can turn on continuous async update: UpdteScreenAsync(true); Setup for callbacks on full and half screen: void setFrameCompleteCB(void (*pcb)(), bool fCallAlsoHalfDone = false);

You update the half screen that was just completed and know that you need to flush the cache if applicable, before the DMA operation gets back to the that portion of memory.


Hope that helps.
 
@KurtE you are my hero!
almost all issues are gone allocating the buffer with setFrameBuffer(),
thanks a lot for all the info provided.
There's a minor bug with drawRect, which I see is made with drawFastVLine and drawFastHLine so I guess the issue must be in the 'Rectangular clipping' part of the code, but no idea how to tweak that,
the rectangle should be at the right most side of the display:
IMG_20221216_140508.jpg
 
Hi @KurtE, this is just to say that the issue pointed in my last post was all my fault, drawReact works perfect.
Also I'm getting pretty good results with the frameBuffer, waiting 100 milliseconds before writing to the buffer, which is a slow refesh, but avoids all glitches.
Thanks for all the help provided!
 
I'm trying to get this working, having issues with something causing a crash after getting the message "ST7789_t3::init mode: 0" on the serial monitor
Code:
#define TFT_CS    10  // Chip select pin
#define TFT_RST   9   // Reset pin
#define TFT_DC     8   // Data/Command pin
#define TFT_SCLK     32   // TFT Clock
#define TFT_MOSI     25   // TFT Data
#define BLACK 0x0000
#define WHITE 0xFFFF

ST7789_t3 display = ST7789_t3(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
void setup() {
  // put your setup code here, to run once:
  delay(5000);

  // DISPLAY STUFF
    display.init(240, 240);
    display.useFrameBuffer(true);
    display.invertDisplay(false);
    display.setRotation(1);
    display.setTextWrap(false);
    display.fillScreen(BLACK);
    display.setTextColor(WHITE);
    display.setFont(Arial_16);

    display.print("hello world");
}
 
Back
Top