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

Hi Michael,

I am not sure. Your guess is as good as mine... I think a lot of them, are probably pulled high internally.

I have found that some displays don't work reliably for me, without using the reset pin. And I have done a few boards I played with, of tying the reset pin of the display to the processors reset pin. So each time the board resets, it causes the display to reset as well, without tying up an IO Pin. If I remember correctly I first saw that on one of @Frank B's boards.

Ok. What I'm doing is soldering up a prototype board that I can plug in one or two 10 pin 5x2 IDC cables to connect to the different displays (having a different prototype board to connect to each display), and I figured I could use a 6 pin SIP resistor network to simply provide the pull-up for the CS/DC pins. I will just clip the pin for the reset, while providing the pull-up for the CS/DC & extra 2 CS pins.

 
Last edited:
@KurtE

I just ran a quick test using the following sketch that I found on the Adafruit forum for using getTextBounds. I tried it with and without using adafuit fonts. The one thing I noticed is the baseline for the two fonts is off - probably because of the drawing direction for the fonts. Going to do a little more testing and modification of your other test sketch and see what happens :)

But in the short term I think it is working fairly well and will help to position the text so going to go ahead and incorporate it into the rewrite version. This is very similar to text align stuff that I added for our fonts.
 
Hi @mjs513,

I was playing around with the ILI9341_t3n stuff and it gets sort of interesting.

Obviously if we change the text drawing code would also need to change the text bounds code as well to match.

Also I am not sure about how if ever we properly support:: Adafruit_GFX_Button button;

That is we have:
Code:
// To avoid conflict when also using Adafruit_GFX or any Adafruit library
// which depends on Adafruit_GFX, #include the Adafruit library *BEFORE*
// you #include ILI9341_t3.h.
// Warning the implemention of class needs to be here, else the code
// compiled in the c++ file will cause duplicate defines in the link phase. 
#ifndef _ADAFRUIT_GFX_H
class Adafruit_GFX_Button {
public:
	Adafruit_GFX_Button(void) { _gfx = NULL; }
	void[COLOR="#FF0000"] initButton(ILI9341_t3n *gfx,[/COLOR] int16_t x, int16_t y,
		uint8_t w, uint8_t h,
		uint16_t outline, uint16_t fill, uint16_t textcolor,
		const char *label, uint8_t textsize_x, uint8_t textsize_y)
...
But now suppose you do include Adafruit_GFX like the comments mentioned...
In Adafruit that class is defined like:
Code:
/// A simple drawn button UI element
class Adafruit_GFX_Button {

 public:
  Adafruit_GFX_Button(void);
  // "Classic" initButton() uses center & size
  void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y,
   uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
   uint16_t textcolor, char *label, uint8_t textsize);
  void[COLOR="#FF0000"] initButton(Adafruit_GFX *gfx[/COLOR], int16_t x, int16_t y,
   uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
   uint16_t textcolor, char *label, uint8_t textsize_x, uint8_t textsize_y);
Then in our code we do something like:
Code:
  button.initButton(&tft, 200, 125, 100, 40, ILI9341_GREEN, ILI9341_YELLOW, ILI9341_RED, "UP", 1, 1);
Which compiles fine if Adafruit_GFX is not included. But if it is included. This will fail to compile as there is no way to cast TFT to Adafruit_GFX class...

This issue is not new, probably has happened for a long time with ili9341_t3 library... Just not sure how best to resolve...
Probably the simplest is to simply change names of the class?

Currently in the FB test program, I commented out the use of the buttons, until I figure out what to do...
Also had the bounds function draw the rectangle around calculated rect to see how far off... St

Code:
void printTextSizes(const char *sz) {
  Serial.printf("%s(%d,%d): SPL:%u ", sz, tft.getCursorX(), tft.getCursorY(), tft.strPixelLen(sz));
  int16_t x, y;
  uint16_t w, h;
  tft.getTextBounds(sz, tft.getCursorX(), tft.getCursorY(), &x, &y, &w, &h);
  Serial.printf(" Rect(%d, %d, %u %u)\n", x, y, w, h);  
  tft.drawRect(x, y, w, h, ILI9341_GREEN);
}


void drawTextScreen(bool fOpaque) {
  SetupOrClearClipRectAndOffsets();
  tft.setTextSize(1);
  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 0
  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.setFont(&FreeMonoBoldOblique12pt7b);
  printTextSizes("AdaFruit");
  tft.println("AdaFruit");
  tft.setFont(&FreeSerif12pt7b);
  printTextSizes("FreeSan12");
  tft.println("FreeSan12");
  tft.setFont();
  tft.setTextSize(1,2);
  printTextSizes("Sys(1,2)");
  tft.println("Sys(1,2)");
  tft.setTextSize(1);
  printTextSizes("System");
  tft.println("System");
  tft.setTextSize(1);
 

  tft.updateScreen();
  DBGSerial.printf("Use FB: %d OP: %d, DT: %d OR: %d\n", use_fb, fOpaque, use_set_origin, millis() - start_time);
}
 
Hi @KurtE

You must be reading my mind I just tried to implement Adafruit Buttons within a sample sketch and got the error: no known conversion for argument 1 from 'ILI9341_t3n*' to 'Adafruit_GFX*' and was just going to post when I read your post. I know this is going sound funny but why can't we just incorporate the two Button functions and key pressed directly into our code base? Don't know what the impact would be?

Obviously if we change the text drawing code would also need to change the text bounds code as well to match.

Also I am not sure about how if ever we properly support:: Adafruit_GFX_Button button;
I tried the simple example with that one change I mentioned and the effect is just to move it down in the box - lowers the baseline. That was why I trying to implement adafruit button example to see what it does.

EDIT> almost forgot st7789 code runs the ILI9341 display as well but its mirrored from what it should be - did it by accident as I was changing setups on the same t4 for the display. :)
 
You must be reading my mind I just tried to implement Adafruit Buttons within a sample sketch and got the error: no known conversion for argument 1 from 'ILI9341_t3n*' to 'Adafruit_GFX*' and was just going to post when I read your post. I know this is going sound funny but why can't we just incorporate the two Button functions and key pressed directly into our code base? Don't know what the impact would be?

Yep - We already implement the button code. The issue is that the buttons we define in our libraries has the same class name as the ones defined in Adafruit_GFX. We don't define it if we find it was already defined.

And since our class is not derived from Adafruit_GFX, it won't cast down. And if it did, it would blow up as, it would try to call virtual functions which may or may not be in same... Or use member variables that are not there...

I just put a hack in for ILI9341_t3n my Adafruit_font, which looks like it might sort of work...

I defined the button as a different class and then added a #define of the Adafruit_gfx_button to define the new one... Sort of crude, may not catch everything, but test app now compiles with a button...
 
@KurtE

You mean like this:
Code:
#ifdef _ADAFRUIT_GFX_H
class Display_GFX_Button {
public:
	Display_GFX_Button(void) { _gfx = NULL; }
I should just wait for you :)
 
@mjs513 - sort of, I got rid of the #ifdef...
Code:
//#ifndef _ADAFRUIT_GFX_H
#define Adafruit_GFX_Button ILI9341_Button
class ILI9341_Button {
public:
	ILI9341_Button(void) { _gfx = NULL; }
	void initButton(ILI9341_t3n *gfx, int16_t x, int16_t y,
		uint8_t w, uint8_t h,
...

So far the #define worked and did not interfere that I could tell...
 
Going to give your version a test and see what happens. Yours seem to work better than mine anyway.
 
@KurtE

Ok - it seems to be working - didn't initial touch screen - just wanted to test Adafruit fonts. I did add my change for yo to the attached sketch. It does 2 things add a 'b' to draw GFX buttons and 'g' to draw just a simple gettextbonds example options. Not too bad.... I stole the draw function from a HX display example - I hate reinventing the wheel if I have an example.
 

Attachments

  • Adafruit_gfx_font_test.zip
    3 KB · Views: 66
Looks good. Think it is getting pretty good.

May call it good, or may play some and see how bad opaque text, might be...
 
Agreed - I know you are going to try opaque so lets hope its not too bad. In the meantime tomorrow I am going to clean up the example.
 
@mjs513 - Yep I have taken a look at the GFX font output stuff, to see if I can hack up some form of Opaque.

As you know, their fonts are sort of setup to have the setCursor to be at the start of the character at the base line. They then have an X and Y offset to where they start to draw stuff (Upper left corner) as well as width and height that they output from the UL corner... And they have an XOffset to where the cursor should advance to next.

So first pass was to output some debug data in drawGFXFontChar:
Code:
    Serial.printf("DGFX_char: %c %u %u %u %u %d %d\n", c, w, h,  glyph->xAdvance, gfxFont->yAdvance, xo, yo);
You get some output like:
Code:
DGFX_char: F 14 16 14 29 0 -15
DGFX_char: r 8 11 8 29 0 -10
DGFX_char: e 10 11 11 29 1 -10
DGFX_char: e 10 11 11 29 1 -10
DGFX_char: S 11 16 13 29 0 -15
DGFX_char: a 10 11 10 29 1 -10
DGFX_char: n 11 11 12 29 0 -10
DGFX_char: 1 6 17 12 29 3 -16
DGFX_char: 2 10 15 12 29 1 -14

So for example the F we move up 15 pixels (0,-15) for UL, we then output 14 columns of 16 rows. So the Y extent goes +1 below the base line (-15+16)
And if we get a CR we advance by 29 pixels....

So I was then curious about with these fonts what is the farthest up we went and the farthest down we went in our drawing... So hacked into the setFont (GFX font version)
Code:
void ILI9341_t3n::setFont(const GFXfont *f) {
	font = NULL;	// turn off the other font... 
    if(f) {            // Font struct pointer passed in?
        if(!gfxFont) { // And no current font struct?
            // Switching from classic to new font behavior.
            // Move cursor pos down 6 pixels so it's on baseline.
            cursor_y += 6;
        }

        // Test wondering high and low of Ys here... 
        int8_t miny_offset = 0;
        int max_delta = 0;
        uint8_t index_min = 0;
        uint8_t index_max = 0;
        for (uint8_t i=0; i <= (f->last - f->first); i++) {
        	if (f->glyph[i].yOffset < miny_offset) {
        		miny_offset = f->glyph[i].yOffset;
        		index_min = i;
        	}
        	if ( (f->glyph[i].yOffset + f->glyph[i].height) > max_delta) {
        		max_delta = (f->glyph[i].yOffset + f->glyph[i].height);
        		index_max = i;
        	}
        }
        Serial.printf("Set GFX Font(%x): Y %d %d(%c) %d(%c)\n", (uint32_t)f, f->yAdvance, miny_offset, index_min + f->first, 
        	max_delta, index_max + f->first);
    } else if(gfxFont) { // NULL passed.  Current font struct defined?
...

And for this font I see:
Code:
Set GFX Font(600012f0): Y 29 -16($) 6(g)

So the logical question is, what Y range should I use to start the Opaque drawing in? Again the X is easy...
One Guess in this case: Should start at the MinY I detected. So this case -16 and maybe go to +13? (f->yAdvance + min_y) ?

At least that is my first guess... Wonder how bad it would be to compute the MIN value each time we call setFont here? Could also maybe cache a couple...
 
@KurtE

When I was playing around yesterday with adjusting the yo base I did notice that you may also have to check letters like q and y, since these have tails below the baseline - that may already be accounted for using your method of going from -16 to +13. I didn't save the data but you might want to see what happens if you do FreeSans12qy as a double check.
 
Hi @mjs513 (and others)

I put up a first pass at allowing Opaque GFX Font text output, in the ili9341_t3n library Adafruit_Fonts branch.

It appears to be sort of working. There is an issue that I may not fully deal with.

That is for example in the one font: FreeMonoBoldOblique12pt7b
When you output the String like: AdaFruit
The font is setup that it says the letter F is (width) is > xAdvance... So it overlaps the next character by a bit or so... Probably where the upper Horizontal line of the F
When the r is then output it may set to Background color that bit or two...

Could maybe put in hack to remember that the previous character overflowed, by N pixels and if nothing else changed (like set new cursor..) it would not necessarily set the background color for those first columns... Easyish for Frame buffer code as I just don't update those... As for Non-frame buffer, the code is working like the other fonts, where I setup an updatedate rectangle and output all of the colors, like as if we are doing a writeRect... So would need to maybe remember those bits and/or remember the last character that was output and recompute those bits...

Also I have not put in the stuff yet for handling offset and clip rectangle stuff...
 
Hi @KurtE, etal.

I just downloaded and gave it a try. Works ok for adafruit fonts except when you make the textsize > 1 for an Adafruit font. Then it starts overlapping with the previous line whether its an Adafruit font or not - looks like its drawing up instead of down.

Just as another note - that hack I put in to adjust starting point so the lines are a bit more center " int16_t yo = glyph->yOffset+gfxFont->yAdvance/2;" messes up the fonts.

This is what I am using for testing with the drawTextScreen:
Code:
void drawTextScreen(bool fOpaque) {
  tft.fillScreen(ILI9341_RED);
  if (fOpaque)
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK );
  else
    tft.setTextColor(ILI9341_WHITE);
  tft.setFont();
  tft.setTextSize(1);
  tft.setCursor(0, 5);
  Serial.printf("ASC: %d %d\n", tft.getCursorX(), tft.getCursorY());
  tft.println("AbCdEf");
  //tft.println();
  Serial.printf("A Abcd: %d %d\n", tft.getCursorX(), tft.getCursorY());
  tft.setTextSize(2);
  tft.println("0123456789");
  tft.println();
  Serial.printf("A 01234: %d %d\n", tft.getCursorX(), tft.getCursorY());
  tft.setFont(&FreeMonoBoldOblique12pt7b);
  Serial.printf("A SF: %d %d\n", tft.getCursorX(), tft.getCursorY());
  tft.setTextSize(1);
  tft.println("AdaFruitqy");
  
  Serial.printf("A Adafruit: %d %d\n", tft.getCursorX(), tft.getCursorY());
  tft.setFont(&FreeSerif12pt7b);
    tft.setTextSize(2);
  Serial.printf("A SF: %d %d\n", tft.getCursorX(), tft.getCursorY());
  tft.println("FreeSan12");
  Serial.printf("A FreeSans: %d %d\n", tft.getCursorX(), tft.getCursorY());
}
 
@mjs513 - Yep, the code I believe works the same as on Adafruit GFX library, in that the setCursor(x, y) for these fonts is the base line, and so everything above the baseline scales up farther and everything below the baseline well goes down... We could maybe change... But not sure to what...

Just took another pass and added in the libraries Offset and clipping support to the opaque text output. I think it is sort of working OK...

Here is the slightly updated version of my Frame buffer test...
View attachment Kurts_ILI9341_t3n_FB_and_clip_tests-191002a.zip

In particular here are the two Adafruit fonts being output again with the:
t and o commands.

If you do a straight: <cr> command it toggles display code to go between use frame buffer and not use frame buffer. So I can see if both cases are working.

Also if you use the: c<cmd>
command it toggles on and off a clipping rectangle.

Which appears to be working...

There is still some cleanup that could be done, like, I can update some of the variables like if my calculated y_end > _displayclipy2, could update the
y_end to be the _displayclipy2... Then I don't have to check for both...

Now back to playing
 
@KurtE
Seems to work ok as long as you keep Adafruit font text sizes set to 1 (or y=1). For instance if you set:
Code:
  tft.setTextSize(1,3);
  printTextSizes("FreeSan12");[CODE] in your sketch the background box is way off.  So if you do "o" w/o frame buffer you get this:
[ATTACH=CONFIG]17768._xfImport[/ATTACH]

with this output:
[CODE]1
Set GFX Font(60001290): Y 24 -16($) 6(_)
AdaFruit(0,115): SPL:110  Rect(0, 101, 110 15)
Set GFX Font(6000129c): Y 29 -16($) 6(g)
FreeSan12(0,139): SPL:102  Rect(0, 91, 102 51)
Sys(1,2)(0,220): SPL:48  Rect(0, 220, 48 16)
System(0,236): SPL:36  Rect(0, 236, 36 8)
Use FB: 1 OP: 1, DT: 0 OR: 37

If I do my "yo" change it makes it more of a mess so can't use that with opaque yet. Looking at the code now.
 
@mjs513 Good Morning

Will take a look.
Maybe one of the scale factors was wrong... Maybe used X instead of Y or ...

Just pushed up an update to cleanup some of the end of line and end of character testing in opaque mode...
 
@KurtE

Just downloaded the latest and greatest and looks like its working both with and without FrameBuffer.
 
Sounds good - I decided to go ahead and I merged all of this back into my master branch...

Question is, should I try to merge this back into st7735_t3? Or would you like to have the fun.

Not sure yet if I will "Fix" the overlap opaque text issue or not...

Might be trivial to fix in Frame buffer mode. That is if I know that lets say the first 2 pixels on the left hand edge were output by the previous char.

The output code in that left band not output the new value if it is not going to be the text color. Although I suppose there could be a question of which background color should win if someone does something like:
Code:
tft.setCursor(0, 50);
tft.setTextColor(ILI9341_WHITE, ILI9341_RED);
tft.print("F");
tft.setTextColor(ILI9341_WHITE, ILI9341_GREEN);
tft.print("x");
Should the overlap background color be Red or Green?

We could also fix it in the non frame buffer mode, by remembering a few things like in the above case:
That the previous character output was (an X at position 0, 50, and that there was an overlap). And FG color was ...

With this suppose that the x starts at something like 12, 50 and there was a 2 pixel overlap...

It would not be hard to logically rerun output of previous character and for example logically ask/deduce
What would the previous writeGFXChar function would output at position (12,40)... If it is FG color and we are going to output a BG color for that pixel we use the previous FG color...

Question is, is it worth it?
 
@KurtE

Was going to merge it with the ILI9488 code first and if you want will do the ST7735_t3 code next. Was just waiting until the bugs were worked out.

As for the overlap since the fonts get drawn up - I was working on my yo kludge and almost got it working but ran into problems. Figured out the bounding box and that looked I got that working ok but it would shift the chars down from where drawn if opaque wasn't used:

20191003_134027.jpg

If opaque wasn't used the char position would be higher by the yAdvance/2 which is what I am adding to yo.
 
Looks like you are getting close...

I was/am sort of torn between leaving it with Adafruit setup or fix it to logically feel better...

I am sort of hacking up the function to look into previous char output to see how bad it would be.

I have started to hack up function that looks like:
Code:
// some member variables I will set when I detect a character draws larger than its character offset...
	unsigned int _gfx_c_last;
	int16_t   _gfx_last_cursor_x, _gfx_last_cursor_y;
	int16_t	 _gfx_last_x_overlap = 0;
	
bool ILI9341_t3n::gfxFontLastCharPosFG(int16_t x, int16_t y) {
    GFXglyph *glyph  = gfxFont->glyph + (_gfx_c_last -  gfxFont->first);

    uint8_t   w     = glyph->width,
              h     = glyph->height;


    int16_t xo = glyph->xOffset; // sic
    int16_t yo = glyph->yOffset;
    
    if (y < (_gfx_last_cursor_y + (yo*textsize_y)))  return false;  // above
    if (y >= (_gfx_last_cursor_y + (yo+h)*textsize_y)) return false; // below


    // Lets compute which Row this y is in the bitmap
    int16_t y_bitmap = (y - ((_gfx_last_cursor_y + (yo*textsize_y))) + textsize_y - 1) / textsize_y;
    int16_t x_bitmap = (x - ((_gfx_last_cursor_x + (xo*textsize_x))) + textsize_x - 1) / textsize_x;
    uint16_t  pixel_bit_offset = y_bitmap * w + x_bitmap;

    return ((gfxFont->bitmap[glyph->bitmapOffset + (pixel_bit_offset >> 3)]) & (0x80 >> (pixel_bit_offset & 0x7)));
}
 
Back
Top