Best practice printing a field on a graphics display or spoiled by 4d Systems........

Status
Not open for further replies.

cartere

Well-known member
Trying to print a numeric field on display

Code:
#include "SPI.h"
#include "ILI9341_t3.h"

// For the Adafruit shield, these are the default.
#define TFT_DC  9
#define TFT_CS 10

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

void setup() {
 
  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(0, 30);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(3);
  tft.println("Hello World!");
  delay(2000);
  tft.setCursor(0,30);
  tft.setTextColor(ILI9341_BLACK);
  tft.println("Hello World!");
  
}

void loop(void) {
  int i;
  
  for(i=0;i<100;i++){
    tft.setTextColor(ILI9341_WHITE);
    tft.setCursor(0,30);
    tft.println(i);
    delay(200);
    tft.setCursor(0,30);
    tft.setTextColor(ILI9341_BLACK);
    tft.println(i);
  }
}

Is there a better way? A library that encapsulates some of this?
 
There is not much, but there are a few things. First the setTextColor member can take a 2nd color (background), so instead of leaving the 0 pixels of the char as it was, it sets it to background color, and the print class on the Teensy has printf method, so your loop could look something like:
Code:
  for(i=0;i<100;i++){
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
    tft.setCursor(0,30);
    tft.printf("%2d", i);
    delay(200);
  }

If you don't wish to use printf, you can also either print out a leading or trailing blank (potentially optionally if I < 10), like:
Code:
  for(i=0;i<100;i++){
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
    tft.setCursor(0,30);
    tft.print( i, DEC);
    tft.print(" ");
    delay(200);
  }
 
Big jump in program size with printf! Also top line of text missing using tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK)
 
Sounds like maybe a bug in drawChar... Which I can see, especially since I made a version of the program that outputs the characters with only setting one color and also setting a 2nd color.

There are at least 3 code paths in drawChar. Two when only one color specified, where it diverges if text size is 1 or not, and then a third when two color specified.

Yep printf probably ads size, but so far I have not come close to running out on the Teensy...
 
Starting to think along the line of adding perhaps a txtBox or numBox object to the library with methods to handle their contents.
 
Yes, I was going to mention, if you are doing this in multiple places, you can add a function that takes the position and number, and does all of the necessary low level calls.
 
Code:
void loop(void) {
  int i;
  
  for(i=0;i<100;i++){
    tft.setTextColor(ILI9341_WHITE);
    tft.setCursor(0,30);
    tft.println(i);
    delay(200);
    tft.fillRect(0,30,100,50,ILI9341_BLACK);
   
  }

Should be faster, now to figure out character size to pixel width and height.
 
Yep, but I still prefer to fix the bugs...

As I mentioned in previous post, there is an issue in the drawChar when solid color background and size > 1. The issue is that it sets up rectangle of memory to output data to, which is either too small or we are writing too much data.

In particular, at the end of the loop, we output one blank logical row (9th pixel) as the background color. But the height we set up is 8*size+1 pixels and we are outputting 9*size rows of data.
The fix I did was to:
Code:
	} else {
		// This solid background approach is about 5 time faster
		SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0));
(line changed)		setAddr(x, y, x + 6 * size - 1, y + 8 * size);
(to)		setAddr(x, y, x + 6 * size - 1, y + 9 * size - 1);
		writecommand_cont(ILI9341_RAMWR);
		uint8_t xr, yr;
		uint8_t mask = 0x01;
I uploaded this change to my fork of this library: https://github.com/KurtE/ILI9341_t3

The other option would be to modify the loop that is outputting stuff at the end of the char:
Code:
		uint32_t n = 6 * size * size;
		do {
			writedata16_cont(bgcolor);
			n--;
		} while (n > 1);
example could change n to be only 6*size which would match what size was setup. In this case there would only be one actual blank pixel at bottom of each char.

Kurt
 
Hi Kurt,

Thanks for your message in the other thread. I went back and looked at the code again, and then looked at the Adafruit_GFX library.

I don't think the original library is treating this as a 6x9 character cell. That is, when you say:

But the height we set up is 8*size+1 pixels and we are outputting 9*size rows of data.

I don't think that's right (or at least it changes the semantics from the original Adafruit library). I read this to say that you're drawing a 6x9 character cell (5x8 character dots, plus one row and one column of background as spacing between glyphs). But I checked the original code and the pixels on the display, and I think it outputs a 6x8 cell (5x8 character dots, plus just the blank column to the right of the glyph, not a blank row below it).

The glcdfont.c file says it's a 5x7 font, and maybe it was originally, but it's stored and drawn as a 5x8 font (and the font currently contains descenders into the 8th row). Adafruit_GFX doesn't draw a 9th blank row, it just butts the lines against each other vertically. If you have descenders and full-height characters on consecutive lines, they do touch. This might not be ideal, but it's the way the original library appears to work.

Adafruit_GFX.cpp and ILI9341_t3.cpp both contain this in the write( uint8_t c ) method to process a newline:

Code:
  if (c == '\n') {
    cursor_y += textsize*8;
    cursor_x  = 0;
  }

I've confirmed this in the original code and by counting pixels on the LCD. Maybe when you have a moment you could take a look and see if you disagree.

I'm using the following code for the last part of drawChar() for the moment. I don't know enough about the SPI code to understand the implications, but I wanted to ensure that the data was all written using writedata16_cont() except the last, and write that out with writedata16_last(), since the code implies that that's important. This code still might be bugged... I am only writing to a single display at the moment, not using anything else on the SPI bus, and not reading from the display either. I suspect those scenarios are where the problems will come up if this code is incorrect.

This code draws the same pixels to the screen as the Adafruit code does when drawing multiple lines of text.

Code:
	} else {
		// This solid background approach is about 5 time faster
		SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0));
		setAddr(x, y, x + 6 * size - 1, y + 8 * size - 1);
		writecommand_cont(ILI9341_RAMWR);
		uint8_t xr, yr;
		uint8_t mask = 0x01;
		uint16_t color;
		for (y=0; y < 8; y++) {
			for (yr=0; yr < size; yr++) {
				for (x=0; x < 5; x++) {
					if (font[c * 5 + x] & mask) {
						color = fgcolor;
					} else {
						color = bgcolor;
					}
					for (xr=0; xr < size; xr++) {
						writedata16_cont(color);
					}
				}
				for (xr=0; xr < size-1; xr++) {
					writedata16_cont(bgcolor);
				}
				if ( y == 7 && yr == size - 1 ) {
					// this is the last pixel on the last line
					writedata16_last(bgcolor);
				} else {
					writedata16_cont(bgcolor);
				}
			}
			mask = mask << 1;
		}
		SPI.endTransaction();
	}
}

Cheers,
Dave
 
Hi Dave,

Yes it appears that this branch of the code is the only one that added in drawing a background color band at the bottom of the character, which is probably not correct. As I mentioned in my delta and comments I fixed the issue of overwriting the pixels of the first row of pixels of the char due to wrapping back around.

I think what you propose is valid. The idea about the CONT is to tell SPI to continue to hold the chip select to go into the next byte, which we don't need for the last byte... The only other way would be to generate a counter that we decrement in this loop insted of doing a couple of tests, but not sure worth the effort...

I will try it out more tomorrow and delta it into my branch.

Thanks
Kurt
 
Decided to do a quick and dirty test program to see the differences, so here is the bad version...
ILI9341-drawText-Bad.jpg
The first part uses just setting one color so it uses the background color(transparent), the second part sets both fg and bg colors, which is faster. You can see on the 2nd line of each size, the first row overwrites by one logical scan line, which is noticable after the last character of the 2nd line.

Changed code like you mentioned. (I put in a few more unnecessary ()s Now looks better.
ILI9341-drawText-Better.jpg

I uploaded the change to my fork of the library.

Kurt
 
Sweet. I'll grab your version. I should finally sign up on GitHub and learn how to use it.

Cheers,
Dave
 
Status
Not open for further replies.
Back
Top