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

@mjs513 - I think it all has to do with the T4 memory caching stuff... There is stuff in place to try to resolve it.

For example in the ISR for the DMA frame completion, there is a check that if we are going to continue to the next frame it does:
Code:
} else {
		// maybe need to flush cache again
		if ((uint32_t)_pfbtft >= 0x20200000u)  arm_dcache_flush(_pfbtft, CBALLOC);

Which appears to mostly work, the problem is that this is going on, while for example the DMA/SPI stuff is still in a race condition, of which things are going to win...

That is, the ISR fires, when we have completed a frame, at which time, it increments the frame counter, and in the else condition, hopefully flushes stuff to memory, and then returns... The main line code then sees the frame count changed and exceeded some value and does the fillRect or the like that writes the new color out, to the ram...

Now the issue could be that some of these writes to RAM stay in the cache and others make their way through the cache to the actual RAM during that process, so that frame could be part of one and part of the other, but then the next frame it should flush all out and should show up as the new color...

Not sure how to really resolve this? I don't know anyway programmatically to say turn that blinkidy blink cache off for this memory range....

For my type of stuff I don't use the continuous updates, I am more the generate new page, output page....

But if I were doing something like video output or like, I might want some of this structured slightly different. That is I maybe would want to enable more interrupts in the code, and maybe fill sections after each section outputs...

Or if for more general case, I would hate to have to have to change all of the frame buffer code, that when you do each write to memory you either always follow it with the arm_dcache_flush or again keep track of where you are in the outputs...

SO for now I am thinking good enoug
 
@KurtE

Wow. A lot to keep track of. Like you never really use framebuffer but based on what you said its good enough for now with this display.
 
@mjs513 - I just semi vented some frustration on the T4 thread, on some of this...

I do sort of have a solution, I could use here, which would make the updateScreenAsync work sort of like the KeDei code works,
That is suppose on the T4, the st7735_t3 object would have two internal buffers, for now lets say each is 480 bytes or 240 words long.

And with this I have two DMASettings objects chained to each other. Each of which points to one of these buffers. And both of them have the interrupt on completion set.
So when you start up DMA operation, you copy the first pixels bytes into the first buffer start the DMA and copy the next 240 into second buffer, when we receive the ISR that DMA completed, it will continue to the next one, but during that ISR we copy into the buffer that completed the next portion of the screen... When we finished all of the output for a frame, if we are not doing continuous, we finish, else we copy in the beginning of the next frame...

As the memory of this object is hopefully in lower memory and not cached we ovoid the issue.
As a side benefit the sketch could know where it is within a frame...

Downside - More memory used, overhead of memory copy (but removal of flushing of cache), more interrupts.

Is it worth it?
 
@KurtE

Yep - just finished reading the post on the other thread. Memory on the T4 is challenging - that's where most of the issues I have are from I think.

Is it worth it - depends on the application I guess. But knowing you, you will go ahead and do it anyway just because the way it is now. At least the Kedei came in handy for something :)
 
@mjs513 - Actually I misspoke, it was the ILI9488 code not KeDei... Remember I set up the memory to use a pallet as we did not have enough memory until T4B2 for any device to have full FB...
 
...
I do have a second st7789 - and two POGO pins - what do I need for that beside pins #26/MOSI1 and #27/SCK1 ?
LIKE THIS ? >> ST7789_t3 tft2 = ST7789_t3(TFT_CS==-1, TFT_DC==3, TFT_MOSI==26, TFT_SCLK==27, TFT_RST==4);

...

Okay this post #45 went unanswered - stopped putting off the soldering assuming it might work …

It is working - first thing I did was just add the SPI1 as tft and commented the current tft and that worked:
Code:
ST7789_t3 tft = ST7789_t3(TFT_CS,  TFT_DC, TFT_RST);
ST7789_t3 tft2 = ST7789_t3(TFT_CS, 3, 26, 27, 4);

I put half the spew to tft2 and I duplicated the colorbar slide down the side from the one example on both - that is generally working.

Only issue I see is that on tft2 the text that does full char over write on above 'tft' - including background pixels does not do the same on tft2. The tft2 using the same test draw only write forground pixels so they just accumulate to white blobs.

Is there something I missed in init duplication or setup?

Must be a leftover from writing done during the example code included in setup?

I swapped the declaration of tft and tft2 and the problem followed to tft2 which is then SPI - where tft on SPI1 is running the other example code in setup first. Not sure what that command is missing?

So added POGO's to 26 and 27 and wired them to the end of breakout Serial 6 and 7 rows to get MOSI1 and SCK1. Then used other pins as declared above and soldered pins in GND and 3.3V on the end row to feed display #2. So this is running the 5X Serial# loop test and FreqCnt still showing 7M loop() cycles per second with all working - except pixel overwrite.

<EDIT>: Found It :: A version of this is done one in the test code that forces background color writing:>> tft2.setTextColor(ST7735_BLUE, RGB(0, 0, 0));
 
Last edited:
FrameBuffer question for AsyncUpdate: With two displays if I enable it does it make two buffers - or one buffer used for one or the other or one buffer for both?

Perhaps the answer is in the example I just saw - at least it shows doing async:: ...\libraries\ST7735_t3\examples\ST7735_t3_multiple\ST7735_t3_multiple.ino
 
@defragster @mjs513 ...

Good Morning....

For the fun of it, I just pushed up a new temporary branch (https://github.com/KurtE/ST7735_t3/tree/writeRect_T4_buffer_DMA) based off of my PR branch...

That for T4 uses two internal buffers that it uses for DMA updates to the display... It configures two DMAChannels for each to use one of these buffers. When it finishes sending one of these buffers, it grabs the next part from frame buffer...

You might grab it and give it a try. And for example see the difference from previous version for the continuous update example...
 
@defragster - Forgot to answer questions...

Each display holds (allocates) it's own buffer. You can set them your self by using the set buffer function (up to you to make sure right size...) or if you don't set it, it mallocs the display memory.
 
@defragster @mjs513 ...

Good Morning....

For the fun of it, I just pushed up a new temporary branch (https://github.com/KurtE/ST7735_t3/tree/writeRect_T4_buffer_DMA) based off of my PR branch...

That for T4 uses two internal buffers that it uses for DMA updates to the display... It configures two DMAChannels for each to use one of these buffers. When it finishes sending one of these buffers, it grabs the next part from frame buffer...

You might grab it and give it a try. And for example see the difference from previous version for the continuous update example...

Just gave your new changes a test run on the T4 and the T3.6 using your simpleTest_FB sketch. Works like a charm for both boards - no more splotches on the T4. Knew you weren't going to leave it be :)

Looked at the changes = a lot of added tests on DMA to get it to work right. Looks good on the 240x320 display :)
 
@mjs513 - So if we think it is working well enough, I will probably remove the #if doing it the other way and then merge it back into the main branch which still has an outstanding PR on it...

I have also made a copy of the same test program showing this for ili9341_t3n which I will post on T4 thread... As an example of issues with frame buffer and continuous updates...
 
@KurtE

I just finished reading the post on the other thread, think that pretty much sums it up. Using the ILI9341 to illustrate the problem was good but now you have to update that library as well.

As for updating the St77xx library I would say go ahead and do the update. When I tested I rotated the screen in each direction and did the "continuous update". In all rotations the framebuffer changes you made worked and I didn't see any of the splotches that we saw before.
 
@mjs513 - Yep I just removed the old version, and now about to merge it back in to the other branch...

I put up the stuff about ILI9341 as a way to illustrate the issue... And so far I am not seeing any other approaches suggested, so will probably migrate that change also into the ili9341_t3n library. Should not be hard as this code as the ST... code was originally derived from ILI...
 
@KurtE

Cool on the changes.. Guess have to download latest copy.

Don't think you will hear anything back until tonight. Noticed the forum gets busy in the evening :)
 
Impressive Work KurtE !!!! - on T4 - twin 1.3" 240x240 ST7789's::

Cool, github zip from earlier :: \libraries\ST7735_t3\examples\ST7735_t3_multiple\ST7735_t3_multiple.ino

IT WORKS !!!

Code:
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)  // Teensy 4.x
#define SPI_INTERFACES_COUNT 2  // only do 1 to start testing
//...
ST7789_t3 tft = ST7789_t3(-1,  10, 12);
#if SPI_INTERFACES_COUNT > 1
// Again only one
ST7789_t3 tft1 = ST7789_t3(-1, 3, 26, 27, 4);
#endif
#endif

//...
  tft.init(240,240, SPI_MODE2) ;  // use for ST7789 without CS)
//...
  tft1.init(240,240, SPI_MODE2) ;  // use for ST7789 without CS)
//...

SerMon shows this:
600000000
ST7789_t3::init mode: 8
tft displayed
ST7789_t3::init mode: 8
tft1 displayed
DMA Init buf size: 480 sub frames:120
DMA Init buf size: 480 sub frames:120

Restored this and BOTH working :: #define ST7735_SPICLOCK 48000000
It does run faster and looks like one or two less 'block refresh flashes' . I see 2 lines between 3 blocks instead of 4 or 5 block groups.

Changed this and it is running with asyncUpdateActive() test - though a bit too fast to see ... :) ... and expectedly lots of drawing during refresh :)
next_test_start_time = millis() + 1;


A bit of code could track the test and update times ...
 
Last edited:
@defragster - did you expect anything less :)

Any I was doing a little googling looking for examples of data graphing using displays and came across something Kris Kasprzak put together in 2015: https://www.youtube.com/watch?v=YejRbIKe6e0. So I downloaded the code - single ino file, and setup up to run on the ST7789 240x320 display that I have. All I can say is nice for such a small display. Here is the sketch for the ST7789:

View attachment GraphLibrary.zip

Have fun.
 
@mjs513, @defragster @PaulStoffregen - Received the Adafruit mini display: 160x80, and verified that it runs using this library code... I did push up the displays constant to keywords.txt, plus added it as one of the possible lines to uncomment...

So think we are sort of done here. Hopefully all of it will be pulled back into master...
IMG_0841.jpg
 
@KurtE - @defragster @PaulStoffregen -

Nice job Kurt pulling all the different displays together and then getting them working on different SPI buses. And you can mix and match to boot :)
 
I'll update to the latest to make sure my system works - but the twin 240x240 non_CS st7789's have been ticking away continuously for over a day except for tweak uploads where I slowed down the spaz rates I had and did the variable rate updates as it switches between the two test loops on SPI0 and SPI1 displays. If the others are working as well as what I can see here on the T4 it is good and impressive work. And to cover display variations and multiple displays and multiple SPI seems a good update for a usable range of displays - in my case they were under $5.
 
Great News. Just downloaded the latest - just in case. Also updated my copies of the ILI9341_t3n and SPIN libraries.
 
Have other stuff going on today as well...

Been playing arround with the uncanny eyes with one display on SPI and the other on SPI1... Plus trying to use the DMA code to update both eyes at same time...

When I turn on the DMA, stuff the EYE on SPI0 does not normally display...

If I trun off DMA usage, both eyes draw, but often USB is corrupted???

Current debug version of the code (again using my DMA... branch)

View attachment uncannyEyes_async_st7735-190817a.zip
 
UncannyEyes Hints on maybe why not working correctly on T4???

I think the USB not working a lot of the time and the like is probably due to differences on how memory is allocated/used on T4. In this case on how variables are allocated in memory when the array is defined as const.

To show this, I modified my "Foo" program from before that printed out where some memory was allocated, to print out also the locations of the unCannyEye data that comes in from the eye file selected in their config data. In particular the defaulteye header file. I just copied that file into my sketch folder and changed the sketch to:

Code:
uint8_t lower_buffer[32];
uint8_t upper_buffer[32] DMAMEM;
#define DEFAULT_EYE
#include "defaultEye.h"

void setup() {
  uint8_t stack_buffer[32];
  uint8_t *heap_buffer = malloc(32);

  while (!Serial && millis() < 4000) ;
  Serial.begin(115200);
  delay(500);
  Serial.printf("Lower_Buffer: %x\n", (uint32_t)lower_buffer);
  Serial.printf("upper_buffer: %x\n", (uint32_t)upper_buffer);
  Serial.printf("stack buffer: %x\n", (uint32_t)stack_buffer);
  Serial.printf("Heap Buffer: %x\n", (uint32_t)heap_buffer);
  Serial.printf("Setup: %x\n", (uint32_t)&setup);
#if defined(DEFAULT_EYE)
  Serial.printf("UncannyEye sclera: %x(%d)\n", (uint32_t)sclera, (uint32_t)sizeof(sclera));
  Serial.printf("           iris: %x(%d)\n", (uint32_t)iris, (uint32_t)sizeof(iris));
  Serial.printf("          upper: %x(%d)\n", (uint32_t)upper, (uint32_t)sizeof(upper));
  Serial.printf("          lower: %x(%d)\n", (uint32_t)lower, (uint32_t)sizeof(lower));
  Serial.printf("          polar: %x(%d)\n", (uint32_t)polar, (uint32_t)sizeof(polar));
  Serial.printf("  Total: %d\n", sizeof(sclera)+sizeof(iris)+sizeof(upper)+sizeof(lower)+sizeof(polar));
#endif
  pinMode(13, OUTPUT);
}

void loop() {
  digitalWrite(13, !digitalRead(13));
  delay(500);
}

Output is:
Code:
Lower_Buffer: 2003612c
upper_buffer: 20200000
stack buffer: 20077fd0
Heap Buffer: 20200028
Setup: 7d
UncannyEye sclera: 2001c0f8(51200)
           iris: 20000000(81920)
          upper: 20014000(16384)
          lower: 200180f8(16384)
          polar: 200288f8(51200)
  Total: 217088
The data in that file looks like:
Code:
#define SCLERA_WIDTH  160
#define SCLERA_HEIGHT 160

const uint16_t sclera[SCLERA_HEIGHT][SCLERA_WIDTH] = {
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
...

If you run this instead on T3.6 the output looks like:
Code:
Lower_Buffer: 1fff13b4
upper_buffer: 1fff0200
stack buffer: 2002ffc0
Heap Buffer: 1fff1848
Setup: 46d
UncannyEye sclera: 233ac(51200)
           iris: 72b4(81920)
          upper: 1b2b4(16384)
          lower: 1f3ac(16384)
          polar: 2fbac(51200)
  Total: 217088

What is interesting here is that on T4, it looks like the 200+K of data is allocated in the "Normal" data space, instead of the code space. So these tables are probably causing the lower memory areas to be overrun, probably including the USB descriptor data... And then the whole thing crashes or misbehaves in strange ways, probably depending on what things get overwritten with what...

Wonder if there is some normal way to say leave this data in normal program space? Should this not be the default? And what else on other T3.x boards that would end up in program space is now in data space? Example: Serial.println("This is text");
Where does that literal text reside?

Now more debugging
 
Quick update: If I change all of those defines to be: PROGRMEM like:
Code:
const uint16_t sclera[SCLERA_HEIGHT][SCLERA_WIDTH] PROGMEM = {

Then the output on T4 does change to:
Code:
Lower_Buffer: 2000112c
upper_buffer: 20200000
stack buffer: 20077fd0
Heap Buffer: 20200028
Setup: 7d
UncannyEye sclera: 60001268(51200)
           iris: 6000da68(81920)
          upper: 60021a68(16384)
          lower: 60025a68(16384)
          polar: 60029a68(51200)
  Total: 217088
So looks like it did move the data output of the default area...
Now to try pulling out some more hair and see if this actually helps UnCannyEyes
 
@KurtE
What is interesting here is that on T4, it looks like the 200+K of data is allocated in the "Normal" data space, instead of the code space. So these tables are probably causing the lower memory areas to be overrun, probably including the USB descriptor data... And then the whole thing crashes or misbehaves in strange ways, probably depending on what things get overwritten with what...
Good explanation on why USB might be getting trashed and why it works on the T3.6 vs the T4.

Interesting thing is that where I was looking was at those static variables in frame function:
Code:
   static boolean  eyeInMotion      = false;
   static int16_t  eyeOldX = 512, eyeOldY = 512, eyeNewX = 512, eyeNewY = 512;
   static uint32_t eyeMoveStartTime = 0L;
   static int32_t  eyeMoveDuration  = 0L;

   if(eyeMoveDuration == 0){
    Serial.printf("eyeInMotion: %x, eyeOldX: %x\n",&eyeInMotion,&eyeOldX);
    Serial.printf("eyeOldY: %x, eyeNewX: %x\n",&eyeOldY,&eyeNewX);
    Serial.printf("eyeNewY: %x\n",&eyeNewY);
    Serial.printf("eyeMoveStartTime: %x, eyeMoveDuration: %x\n",&eyeMoveStartTime,&eyeMoveDuration);
   }
Why, because if I changed them to non-static it wouldn't trash USB but also I wouldn't get any eye movement. Oh, btw, if I do the one print as above it works fine so something must be pushing the data around. Anyway what that gave me:
Code:
eyeInMotion: 2002886c, eyeOldX: 20027cb4
eyeOldY: 20027cb6, eyeNewX: 20027cba
eyeNewY: 20027cb8
eyeMoveStartTime: 20028868, eyeMoveDuration: 20028850
Just some added info if you didn't see it in the other thread.

BTW: What's "Polar" in your dump above. Geez wish there was one spot where there was a memory map - most of this is splattered around the beta thread.
 
Back
Top