ILI9225 driver problem with drawing arcs...

Hi all,

I jave a particular problem with a ILI9225 display I am using.

My goal is to make a ringmeter (circular ring that counts the time back). the display is working like charm on my NanoV3.0 except when drawing arcs.

Some hardware details:

Ok, the code I am using:

#include <SPI.h>
#include <TFT_22_ILI9225.h>


// **** declaration of LCD TFT variables ****

#define TFT_LED 0   // 0 if wired to +5V directly
#define TFT_RST 8
#define TFT_CS  10  // CS
#define TFT_RS  9
#define TFT_CLK 13  // SCK
#define TFT_SDI 11  // MOSI
TFT_22_ILI9225 tft = TFT_22_ILI9225(TFT_RST, TFT_RS, TFT_CS, TFT_LED, 0);
void setup(){
  Serial.begin(9600);

// Turn on TFT screen

  tft.begin();
  tft.setOrientation(3);
  tft.setBackgroundColor(COLOR_BLACK);

  #define DEG2RAD 0.0174532925

// #########################################################################
// Draw a circular or elliptical arc with a defined thickness
// #########################################################################

// x,y == coords of centre of arc
// start_angle = 0 - 359
// seg_count = number of 3 degree segments to draw (120 => 360 degree arc)
// rx = x axis radius
// yx = y axis radius
// w  = width (thickness) of arc in pixels
// colour = 16 bit colour value
// Note if rx and ry are the same then an arc of a circle is drawn
}
void loop() {

  int w = 8;
  int rx =88;
  int ry = 88;
  
  for (int n = 0; n < 5; n++) {
    fillArc2(88, 110, 0, 100, rx-n*w, ry-n*w, w, 80-n*6);
  }

  while(1);
}

int fillArc2(int x, int y, int start_angle, int seg_count, int rx, int ry, int w, unsigned int colour)
{

  byte seg = 12; // Segments are 3 degrees wide = 120 segments for 360 degrees
  byte inc = 12; // Draw segments every 3 degrees, increase to 6 for segmented ring

    // Calculate first pair of coordinates for segment start
    float sx = cos((start_angle - 90) * DEG2RAD);
    float sy = sin((start_angle - 90) * DEG2RAD);
    uint16_t x0 = sx * (rx - w) + x;
    uint16_t y0 = sy * (ry - w) + y;
    uint16_t x1 = sx * rx + x;
    uint16_t y1 = sy * ry + y;

  // Draw colour blocks every inc degrees
  for (int i = start_angle; i < start_angle + seg * seg_count; i += inc) {

    // Calculate pair of coordinates for segment end
    float sx2 = cos((i + seg - 90) * DEG2RAD);
    float sy2 = sin((i + seg - 90) * DEG2RAD);
    int x2 = sx2 * (rx - w) + x;
    int y2 = sy2 * (ry - w) + y;
    int x3 = sx2 * rx + x;
    int y3 = sy2 * ry + y;

    tft.fillTriangle(x0, y0, x1, y1, x2, y2, colour);
    tft.fillTriangle(x1, y1, x2, y2, x3, y3, colour);

    // Copy segment end to sgement start for next segment
    x0 = x2;
    y0 = y2;
    x1 = x3;
    y1 = y3;
  }
}

I have tried several libraries, also not made for the ILI9225, modified them, but they all give the same annoying result. What is actually interesting is that the bottom and top of the ringis glitch-free. So, something keeps me wondering what is different in the algorhytm for the sides that this display can't handle....

I am quite out of options, and hoping someone could help me out?

Another, but very extensive way is to divide the ring in 60 blocks and switch them on and off pixel by pixel, but this is a lot of programming... :frowning:

BTW, changing the orientation doesn't work either...

I tried your sketch. Yes, it misbehaves on my screen too.

Since the function only depends on fillTriangle(), it should work on any GFX style library.

Yes, it works fine with MCUFRIEND_kbv. GFX style libraries inherit from Adafruit_GFX class.
It looks as if TFT_22_ILI9225 attempts to do its own graphics.

You can try my ILI9225_kbv library if you want from GitHub

David.

You need to change constructor for hardware SPI (and your pins)

#include <SPI.h>
#include <ILI9225_kbv.h>


// **** declaration of LCD TFT variables ****

#define TFT_LED A0 //0   // 0 if wired to +5V directly
#define TFT_RST A4 //8
#define TFT_CS  A5 //10  // CS
#define TFT_RS  A3 //9
#define TFT_CLK A1 //13  // SCK
#define TFT_SDI A2 //11  // MOSI

//ILI9225_kbv tft(TFT_CS, TFT_RS, TFT_RST);
ILI9225_kbv tft(TFT_CS, TFT_RS, TFT_SDI, TFT_CLK, TFT_RST, TFT_LED);

extern int fillArc2(int x, int y, int start_angle, int seg_count, int rx, int ry, int w, unsigned int colour);

void setup() {
    Serial.begin(9600);

    // Turn on TFT screen

    tft.begin();
//    tft.setOrientation(3);
//    tft.setBackgroundColor(COLOR_BLACK);
    tft.setRotation(3);
    tft.fillScreen(0x0000);

#define DEG2RAD 0.0174532925

    // #########################################################################
    // Draw a circular or elliptical arc with a defined thickness
    // #########################################################################

    // x,y == coords of centre of arc
    // start_angle = 0 - 359
    // seg_count = number of 3 degree segments to draw (120 => 360 degree arc)
    // rx = x axis radius
    // yx = y axis radius
    // w  = width (thickness) of arc in pixels
    // colour = 16 bit colour value
    // Note if rx and ry are the same then an arc of a circle is drawn
}
void loop() {

    int w = 8;
    int rx = 88;
    int ry = 88;

    for (int n = 0; n < 5; n++) {
        fillArc2(88, 110, 0, 100, rx - n * w, ry - n * w, w, 80 - n * 6);
    }

    while (1);
}

int fillArc2(int x, int y, int start_angle, int seg_count, int rx, int ry, int w, unsigned int colour)
{

    byte seg = 12; // Segments are 3 degrees wide = 120 segments for 360 degrees
    byte inc = 12; // Draw segments every 3 degrees, increase to 6 for segmented ring

    // Calculate first pair of coordinates for segment start
    float sx = cos((start_angle - 90) * DEG2RAD);
    float sy = sin((start_angle - 90) * DEG2RAD);
    uint16_t x0 = sx * (rx - w) + x;
    uint16_t y0 = sy * (ry - w) + y;
    uint16_t x1 = sx * rx + x;
    uint16_t y1 = sy * ry + y;

    // Draw colour blocks every inc degrees
    for (int i = start_angle; i < start_angle + seg * seg_count; i += inc) {

        // Calculate pair of coordinates for segment end
        float sx2 = cos((i + seg - 90) * DEG2RAD);
        float sy2 = sin((i + seg - 90) * DEG2RAD);
        int x2 = sx2 * (rx - w) + x;
        int y2 = sy2 * (ry - w) + y;
        int x3 = sx2 * rx + x;
        int y3 = sy2 * ry + y;

        tft.fillTriangle(x0, y0, x1, y1, x2, y2, colour);
        tft.fillTriangle(x1, y1, x2, y2, x3, y3, colour);

        // Copy segment end to sgement start for next segment
        x0 = x2;
        y0 = y2;
        x1 = x3;
        y1 = y3;
    }
}

Thanks David, I'll give it a try!

And it works! Thank you so much, this topic can be closed..

ehm, David, one thing though: You told about inheriting the functions of the Adafruit GFX library. How do I implement that?

You don't do anything. That is the way that C++ works.

All the methods from Print.h and all the methods from Adafruit_GFX.h work with libraries like MCUFRIEND_kbv, Adafruit_ILI9341, ILI9225_kbv, ...

So if you want to print a float with 3 decimal places, you can say:
Serial.print(123.456, 3)
lcd.print(234.567, 3)
tft.print(345.678, 3)

In other words, anything that you can use with Serial will work with other libraries too.
Likewise, if you want to draw a circle on a GLCD, OLED, TFT, ... you can use the same GFX method.

A graphics program that draws a circle on ILI9225 can work on ILI9341, HX8357, ... i.e. different TFT hardware.

It also makes it easier to write libraries in the first place. I do not need to worry about graphics. I just concentrate on the specific hardware features.

Note that Adafruit_GFX can draw lines, circles, triangles, ...
It can also draw Buttons, draw different Free Fonts, draw bitmaps, ...
Every library that "inherits", gets all these methods automatically.

Drawing a filled triangle is actually one of the hardest graphics function to write. Adafruit have an excellent library in Adafruit_GFX. Since so many people use it, it is well tested and proven.
Some libraries e.g. UTFT do every method without inheritance. Yes, UTFT works well but I am sure that it did not get everything 100% at first attempt.

David.

Got it! Just learned something useful :slight_smile: