Forum Rule: Always post complete source code & details to reproduce any issue!
Page 26 of 26 FirstFirst ... 16 24 25 26
Results 626 to 647 of 647

Thread: Highly optimized ILI9341 (320x240 TFT color display) library

  1. #626
    Senior Member CorBee's Avatar
    Join Date
    Jun 2018
    Location
    Netherlands
    Posts
    531
    Hi,

    Thanks to KurtE for adding the setscrollmargins function, this works completely as planned in our TeensyBat project. I am currently looking for an example that uses this library with a framebuffer located in PSRAM.

    Looking through the examples I havent seen one (maybe missed it) but I saw the library now has a function:
    Code:
    void	setFrameBuffer(uint16_t *frame_buffer);
    Would a standard PSRAM on the T4.1 be fast enough for this purpose ? If nobody has tested this I might dive into that and see what comes up.

    regards
    Cor

  2. #627
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    16,009
    Quote Originally Posted by CorBee View Post
    Hi,

    Thanks to KurtE for adding the setscrollmargins function, this works completely as planned in our TeensyBat project. I am currently looking for an example that uses this library with a framebuffer located in PSRAM.

    Looking through the examples I havent seen one (maybe missed it) but I saw the library now has a function:
    Code:
    void	setFrameBuffer(uint16_t *frame_buffer);
    Would a standard PSRAM on the T4.1 be fast enough for this purpose ? If nobody has tested this I might dive into that and see what comes up.

    regards
    Cor
    KurtE likely to reply in hours ... but it should be worth expecting it to work.

    AFAIK - larger displays needing a buffer that fits only in PSRAM have been tested and designed to work.

    Seems there was testing or a sample on that ... though too long ago to expect to find it in context ... it may have been on MMod or other ...

  3. #628
    Senior Member CorBee's Avatar
    Join Date
    Jun 2018
    Location
    Netherlands
    Posts
    531
    Quote Originally Posted by defragster View Post
    KurtE likely to reply in hours ... but it should be worth expecting it to work.

    AFAIK - larger displays needing a buffer that fits only in PSRAM have been tested and designed to work.

    Seems there was testing or a sample on that ... though too long ago to expect to find it in context ... it may have been on MMod or other ...
    It at least seems to work from code without any problems, since I do use scrolling 1pixel lines in the code I will have to find a good way to do that in memory. The recent
    addition of setscrollmargins was not yet (as KurtE mentions on Github) tested much and scrolling in memory is another "affair". But I am sure that there can be a good
    way to achieve this.

    cheers
    Cor

  4. #629
    My app includes a filled rect which must move left and right one pixel at a time. The simplistic way to move it is to call fillRect with background color and call it again with new coordinates and foreground color. That is slow and causes flicker. A better way is to redraw only the pixels which must change. Call drawFastVLine for the leading edge in foreground color and call it again for the trailing edge in background color. It's efficient and prevents flicker. I call it differential animation.

    I also have a filled circle to move, but that's more complex. You might think to call drawCircleHelper for a semicircle at the trailing edge in background color and call it again for a shifted semicircle in foreground color. But that doesn't quite work because the trailing semicircle removes too many edge pixels in the upper and lower octants. One fix is to draw a shifted full circle in foreground color to restore the edges. That looks good but it really draws about twice as many pixels as needed. An optimal solution is to draw leading and trailing semicircles, but replace the horizontal line segments with only endpoints.

    Here's the code, adapted from drawCircleHelper. I also pulled the first segments out of the loop and combined them to cover the left and right edges completely. I hope someone will find it useful.
    Code:
    // Shift a filled circle left or right by 1 pixel. Draws only leading and trailing edge pixels.
    // Adapted from ILI9341_t3::drawCircleHelper
    void shiftCircle( int16_t x0, int16_t y0, int16_t r, uint16_t lcol, uint16_t rcol) {
      int16_t f = 1 - r;
      int16_t ddFx = 1;
      int16_t ddFy = -2 * r;
      int16_t x = 0;
      int16_t y = r;
      int xold;
    
      xold = x;
      while (f<0) {
        x++;
        ddFx += 2;
        f += ddFx;
      } // draw first line segments
      tft.drawFastVLine(x0+y+1, y0-x, x-xold+x-xold+1, rcol);
      tft.drawPixel(x0+x+1, y0+y, rcol);
      tft.drawPixel(x0+x+1, y0-y, rcol);
      tft.drawPixel(x0-x, y0+y, lcol);
      tft.drawPixel(x0-x, y0-y, lcol);
      tft.drawFastVLine(x0-y, y0-x, x-xold+x-xold+1, lcol);
      xold = x;
      while (x<y) {
        if (f >= 0) {
          y--;
          ddFy += 2;
          f += ddFy;
        }
        x++;
        ddFx += 2;
        f += ddFx;
        if (f >= 0 || x == y) { // time to draw the next line segments
          tft.drawPixel(x0+x+1, y0+y, rcol);
          tft.drawFastVLine(x0+y+1, y0+xold+1, x-xold, rcol);
          tft.drawPixel(x0+x+1, y0-y, rcol);
          tft.drawFastVLine(x0+y+1, y0-x, x-xold, rcol);
          tft.drawFastVLine(x0-y, y0+xold+1, x-xold, lcol);
          tft.drawPixel(x0-x, y0+y, lcol);
          tft.drawFastVLine(x0-y, y0-x, x-xold, lcol);
          tft.drawPixel(x0-x, y0-y, lcol);
          xold = x;
        }
      }
    }

  5. #630
    Member DIYLAB's Avatar
    Join Date
    Jun 2020
    Location
    Germany
    Posts
    64
    Hi,

    is this the right thread to talk about KurtE's ILI9341_t3n?

    I'll make it very short ;o)
    There is a "driver" optimized for the Teensy 4.x that does nothing more than get a framebuffer onto the display as fast as it can, the ILI9341_T4.
    There is an example program which is smoothly impressive at 30MHz SPI, "99 Luftballons".

    Here the test: https://youtu.be/0VGeh5ThRIw
    *It even goes much faster!

    I have now ported the program for the ILI9341_t3n and also used 30MHz SPI clock, here the result: https://youtu.be/0e9oGl-4Ht0

    What am I doing wrong?
    I would like to reach this speed with the ILI9341_t3n.

    Here the used test program for ILI9341_t3n:

    Code:
    #include "SPI.h"
    #include <ILI9341_t3n.h>
    
    // set the pins: here for SPI0 on Teensy 4.0
    // ***  Recall that DC must be on a valid cs pin !!! ***
    #define PIN_SCK         13  // (needed) SCK pin for SPI0 on Teensy 4.0
    #define PIN_MISO        12  // (needed) MISO pin for SPI0 on Teensy 4.0
    #define PIN_MOSI        11  // (needed) MOSI pin for SPI0 on Teensy 4.0
    #define PIN_DC          10  // (needed) CS pin for SPI0 on Teensy 4.0
    #define PIN_RESET        6  // (needed) any pin can be used 
    #define PIN_CS           9  // (needed) any pin can be used
    #define PIN_BACKLIGHT    5  // only required if LED pin from screen is connected to Teensy 
    #define PIN_TOUCH_IRQ  255  // 255 if touch not connected
    #define PIN_TOUCH_CS   255  // 255 if touch not connected
    
    // drawing size in portrait mode
    #define LX  240
    #define LY  320
    
    /** fill a framebuffer with a given color*/
    void clear(uint16_t* fb, uint16_t color = 0) {
        for (int i = 0; i < LX * LY; i++) fb[i] = color;
    }
    
    /** draw a disk centered at (x,y) with radius r and color col on the framebuffer fb */
    void drawDisk(uint16_t* fb, double x, double y, double r, uint16_t col) {
        int xmin = (int)(x - r);
        int xmax = (int)(x + r);
        int ymin = (int)(y - r);
        int ymax = (int)(y + r);
        if (xmin < 0) xmin = 0;
        if (xmax >= LX) xmax = LX - 1;
        if (ymin < 0) ymin = 0;
        if (ymax >= LY) ymax = LY - 1;
        const double r2 = r * r;
        for (int j = ymin; j <= ymax; j++) {
            double dy2 = (y - j) * (y - j);
            for (int i = xmin; i <= xmax; i++) {
                const double dx2 = (x - i) * (x - i);
                if (dx2 + dy2 <= r2) fb[i + (j * LX)] = col;
            }
        }
    }
    
    /** return a uniform in [0,1) */
    double unif() {
        return random(2147483647) / 2147483647.0;
    }
    
    /** a bouncing ball */
    struct Ball {
        double x, y, dirx, diry, r; // position, direction, radius. 
        uint16_t color;
    
        Ball() {
            r = unif() * 25; // random radius
            x = r; // start at the corner
            y = r; //
            dirx = unif() * 5; // direction and speed are random...
            diry = unif() * 5; // ...but not isotropic !
            color = random(65536); // random color
        }
    
        void move() {
            // move
            x += dirx;
            y += diry;
            // and bounce against border
            if (x - r < 0) { x = r;  dirx = -dirx; }
            if (y - r < 0) { y = r;  diry = -diry; }
            if (x > LX - r) { x = LX - r;  dirx = -dirx; }
            if (y > LY - r) { y = LY - r;  diry = -diry; }
        }
    
        void draw(uint16_t* fb) {
            drawDisk(fb, x, y, r, color);
        }
    };
    
    // 99 luftballons
    Ball balls[99];
    
    // Instantiate display object.
    ILI9341_t3n tft = ILI9341_t3n(PIN_CS, PIN_DC, PIN_RESET, PIN_MOSI, PIN_SCK, PIN_MISO);
    
    // Framebuffer
    DMAMEM uint16_t fb[LX * LY];
    
    void setup() {
        tft.begin(30000000);
        tft.setFrameBuffer(fb);
        tft.useFrameBuffer(true);
    
        // make sure backlight is on
        if (PIN_BACKLIGHT != 255) {
            pinMode(PIN_BACKLIGHT, OUTPUT);
            digitalWrite(PIN_BACKLIGHT, HIGH);
        }
    
        tft.setRotation(0);
    }
    
    void loop() {
        tft.fillScreen(ILI9341_BLACK);
    
        // move and then draw all the balls onto the framebuffer
        for (auto& b : balls) {
            b.move();
            b.draw(fb);
        }
    
        tft.updateScreen();
    }

  6. #631
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    8,229
    @DIYLAB
    Tried your sketch on a T4 and a teensy micro mod and worked with begin(30000000). I did use my arducam config for cs= 10. DC =9. and rat = 8. Still have to try on a t41

  7. #632
    Member DIYLAB's Avatar
    Join Date
    Jun 2020
    Location
    Germany
    Posts
    64
    Quote Originally Posted by mjs513 View Post
    Tried your sketch on a T4 and a teensy micro mod and worked with begin(30000000).
    Nice, then you can now also try the original demo from here: https://github.com/vindar/ILI9341_T4.../99luftballons
    The question is, how do you get the ILI9341_t3n just as fast?
    Please compare the two videos I made of both versions.

  8. #633
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    8,229
    Quote Originally Posted by DIYLAB View Post
    Nice, then you can now also try the original demo from here: https://github.com/vindar/ILI9341_T4.../99luftballons
    The question is, how do you get the ILI9341_t3n just as fast?
    Please compare the two videos I made of both versions.
    Well I just finished testing the T4.1 up to 50Mhz without an issue - at 60Mhz your screen stays white with your example sketch.

    As to the second part of your question as to how do you get the ILI9341_t3n just as fast that is a whole different question.

    You need to look at what that library is doing and why the author says its optimized for the T4.x only and does not support the T3.x etc. You might be able to realize faster frame rates by only updating the sections of the screen that you are changing or trying double or triple buffering as is done in the library but that will only be good for the t4.1.

  9. #634
    @KurtE @mjs513
    Hi, can someone list the color TFT libraries that use frame buffers? I am currently writing a library for a graphical user interface and would like to increase the compatibility.

    I thank you!

    https://github.com/sepp89117/Teensy_UI

  10. #635
    Hello, everyone,

    I found a way to accelerate ILI9341_t3n with a double buffer, for my purposes. Here are the results of the graphic test in three stages:
    Code:
    ----- None buffered -----
    Benchmark                Time (microseconds)
    Screen fill              205325
    Text                     10503
    Lines                    70012
    Horiz/Vert Lines         17663
    Rectangles (outline)     11341
    Rectangles (filled)      421561
    Circles (filled)         69425
    Circles (outline)        58405
    Triangles (outline)      16459
    Triangles (filled)       148537
    Rounded rects (outline)  25366
    Rounded rects (filled)   467870
    
    ---- Single buffered ----
    Benchmark                Time (microseconds)
    Screen fill              215476
    Text                     43358
    Lines                    3196949
    Horiz/Vert Lines         1411518
    Rectangles (outline)     680040
    Rectangles (filled)      2294
    Circles (filled)         428258
    Circles (outline)        409702
    Triangles (outline)      413635
    Triangles (filled)       1236
    Rounded rects (outline)  665510
    Rounded rects (filled)   661642
    
    ---- Double buffered ----
    Benchmark                Time (microseconds)
    Screen fill              176706
    Text                     24565
    Lines                    293851
    Horiz/Vert Lines         324239
    Rectangles (outline)     231521
    Rectangles (filled)      2099
    Circles (filled)         368022
    Circles (outline)        332165
    Triangles (outline)      120915
    Triangles (filled)       1238
    Rounded rects (outline)  197219
    Rounded rects (filled)   516751
    With the following code I was able to achieve significantly higher frame rates in the GameBoy emulator:
    Code:
    /*
        for double buffer
    */
    #define SCREEN_WIDTH 240
    #define SCREEN_HEIGHT 320
    #define TFT_BUFFERSIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
    #define DRAW_SCALEFACTOR 1
    #define DRAW_ON_X 0
    #define DRAW_ON_Y 0
    #define CHECK_LENGTH 14 // A value between 10 and 14 gives the best results
    //buffers
    uint16_t frame[TFT_BUFFERSIZE];
    uint16_t dblFrameBuffer[TFT_BUFFERSIZE];
    
    /*
       updateScreen for double buffer
    */
    void updateScreen()
    {
      tft.startWrite(); // Small changes to ILI9341_t3n were necessary so that the data could be written continuously
    
      uint32_t bufferIndex = 0; // Start at index 0
    
      while (bufferIndex < TFT_BUFFERSIZE)
      {
        uint32_t testIndex = bufferIndex;
        uint32_t unchangedLength = 0;
    
        // Get changed length
        while (unchangedLength < CHECK_LENGTH && testIndex < TFT_BUFFERSIZE)
        {
          if (frame[testIndex] != dblFrameBuffer[testIndex])
          {
            dblFrameBuffer[testIndex] = frame[testIndex]; //copy new byte
            unchangedLength = 0;                          //reset unchanged length to 0
          }
          else
          {
            unchangedLength++;
          }
          testIndex++;
        }
        uint32_t changedLength = testIndex - bufferIndex - unchangedLength;
    
        // If something was changed within the CHECK_LENGTH:
        if (changedLength > 0)
        {
          uint16_t currentX = bufferIndex % SCREEN_WIDTH;
          uint32_t changedEndBufferIndex = bufferIndex + changedLength - 1;
          uint16_t changedEndX = changedEndBufferIndex % SCREEN_WIDTH;
          uint16_t changedLines = (currentX + changedLength) / SCREEN_WIDTH + ((currentX + changedLength) % SCREEN_WIDTH != 0 ? 1 : 0);
          uint16_t pxW;
          uint16_t pxH;
          uint16_t ix0;
          uint16_t iy0;
          uint16_t ix1;
          uint16_t iy1;
          uint16_t oneLineLength;
    
          if (changedLines == 1) // If the changes are within a single line
          {
            //Calculate the necessary data for writing the new line
            oneLineLength = changedLength;
            pxW = changedLength * DRAW_SCALEFACTOR;
            pxH = DRAW_SCALEFACTOR;
            ix0 = currentX * DRAW_SCALEFACTOR;
            iy0 = bufferIndex / SCREEN_WIDTH * DRAW_SCALEFACTOR;
            ix1 = ix0 + pxW - 1;
            iy1 = iy0 + pxH - 1;
          }
          else // If the changes affect more than one line
          {
            uint16_t remainToFullLineEnd = SCREEN_WIDTH - 1 - changedEndX;
    
            // Copy the remaining bytes of the line in case there is something new, as we will write that too.
            for (uint16_t r = 0; r < remainToFullLineEnd; r++)
            {
              dblFrameBuffer[changedEndBufferIndex + r] = frame[changedEndBufferIndex + r];
            }
            //Calculate the necessary data for writing the new window
            oneLineLength = SCREEN_WIDTH;
            changedLength = changedLength + remainToFullLineEnd + currentX;
            bufferIndex -= currentX; //set bufferIndex to x0
            pxW = SCREEN_WIDTH * DRAW_SCALEFACTOR;
            pxH = changedLines * DRAW_SCALEFACTOR;
            ix0 = 0;
            iy0 = bufferIndex / SCREEN_WIDTH * DRAW_SCALEFACTOR;
            ix1 = pxW - 1;
            iy1 = iy0 + pxH - 1;
          }
    
          tft.setAddrWindow(DRAW_ON_X + ix0, DRAW_ON_Y + iy0, DRAW_ON_X + ix1, DRAW_ON_Y + iy1, true);
    
          // Write to SPI
          for (uint16_t iCL = 0; iCL < changedLines; iCL++) // Number of changed lines
          {
            for (uint8_t yScale = 0; yScale < DRAW_SCALEFACTOR; yScale++) // Repeat the line in the Y-direction according to the scale
            {
              for (uint32_t iLL = 0; iLL < oneLineLength; iLL++) // Number of bytes per line
              {
                for (uint8_t xScale = 0; xScale < DRAW_SCALEFACTOR; xScale++) // Repeat writing a pixel according to scale
                {
                  tft.pushColor(dblFrameBuffer[bufferIndex + iCL * oneLineLength + iLL], true);
                }
              }
            }
          }
          bufferIndex += changedLength; // Continue with bufferIndex after the changes found
        }
        else
        {
          bufferIndex += CHECK_LENGTH; // No changes within CHECK_LENGTH
        }
      }
      tft.endWrite();
    }
    @KurtE, @mjs513
    I would be happy if there is interest in it and it may be included in your libs!

  11. #636
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    I've compiled ttf2bdf for windows: https://github.com/FrankBoesing/TFT_...tf2bdf_windows

  12. #637
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    ...updated the google-fronts repo. It now contains more than 3300 converted *.ttf

    https://github.com/FrankBoesing/fonts

    Github reaches a limit here... tried to just upload a *.zip... did not work.. so back to individual directories.. but it shows max 1000
    So, only way to use it, is to download the whole repo.

    I also extended the font sizes: 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 24, 26, 28, 32, 40, 48, 60, 72, 96

    Converting took more than 3 hrs

  13. #638
    @frankB. You are my hero! Thanks for converting these fonts. I'm sure to make use of them.

  14. #639
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    You're welcome.

    Anyone can do it themselves now. Either with Linux - as described by Paul - or with Windows now. I have translated the necessary programs to windows, and written a batch that does everything.

    https://github.com/FrankBoesing/TFT_...extras/windows

    Call of the batch:
    Code:
    tftcovert.cmd filemask [-r] [sizes]
    - filemask is a (optional path +) + file(s)
    - r recourse subdirectories (optional)
    -optional sizes

    Example:
    Code:
    tftconvert e:\fonts\*.ttf -r "8,9,10"
    Converts all *.tff in e:\fonts + subdirectories with sizes 8,9,10

    Code:
    tftconvert e:\fonts\pretty.ttf
    Converts pretty.ttf only.

    Without the sizes parameter, a default is used.
    All three files (both .exe and the batch) must be in the same directory (of your choice)

    It was intended for an other library, but hey, it's useful here, too - I hope.

    Have fun,
    Frank

  15. #640
    Junior Member
    Join Date
    May 2022
    Posts
    18
    Hi
    i am using a 240x320 tft display ILI9341. I am using the optimized ILI9341 library. is there any way to turn off the backlight? i noticed there is a Display off defined in the library as 0x28. i dont have a seperate lite pin on my display to control the backlight and can't power the backlight from a teensy digital pin either
    Thanks

  16. #641
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    10,524
    My guess is probably not. That is with most of the displays you have a backlight pin, which you can feed it power. You can also hook up circuit to then control brightness using PWM pin... Some like Adafruit I think have this circuit built in.

    But without the pin, don't know any way

    Edit: out of curiosity which display are you using? Have a link to it? It might have additional information
    Last edited by KurtE; 05-27-2022 at 07:48 PM.

  17. #642
    Junior Member
    Join Date
    May 2022
    Posts
    18
    I don't have a link for the datasheet but its the same one listed in the PRJC website
    it does have a LED pin to power the backlight but I believe it needs 3.6 to 5V for normal operation and would draw like 20mA and teensy digital pin can't do that

  18. #643
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    10,524
    You are right that you could not connect it directly to an IO pin.

    The Adafruit display has stuff on it to allow it's backlight pin to be connected to IO pin... It takes the negative part of the backlight circuit through a transistor.
    Click image for larger version. 

Name:	screenshot.jpg 
Views:	3 
Size:	349.7 KB 
ID:	28493

    Earlier I did a board based off of stuff I saw on FrankB's board, using two transitors.
    Click image for larger version. 

Name:	screenshot2.jpg 
Views:	2 
Size:	58.8 KB 
ID:	28494
    Where at the time (a few years ago Q1/2 were:
    1 BC850CLT1GOSCT-ND Q2 BC850C SOT23 3
    1 BSS138CT-ND Q1 MOSFET-NCHANNELBSS138 SOT23-3 3

    But these days don't have clue what things are available and/or others may have easier/better circuits.

  19. #644
    Hi,

    In my experience, some *red ili9341*screens have a transistor already attached to the LED pin in which case you can directly PWM the backlight from a teensy pin… you can probably check on the PCB if that is the case for your screen.

  20. #645
    More details here on how to check if your screen has a transistor attached to the led pin: https://github.com/ThingPulse/esp826...color/issues/6

  21. #646
    Junior Member
    Join Date
    May 2022
    Posts
    18
    thanks for the replies!
    yes my screen does have that transistor Q1. My screen is the same one that is in the github link that you posted. Is there any command that I can send to the ILI9341 to control this transistor? I don't see a way to directly connect a teensy pin to this transistor
    Thanks again

  22. #647
    If you have the transistor on the board, then you can directly connect the LED pin from your screen to any digital pin of the Teensy without any additional circuitry. Then, you can PWM the pin to dim the screen as you wish...

    With the transistor in place, the LED pin will only draw a few mA of current. However, jut to be on the safe side, you can check that this is the case before connecting it to the Teensy: just wire the VCC and LED pin to +5V and GND to ground and measure the current flowing respectively through VCC and LED with a multi-meter. You should get something like 50mA for VCC but only maybe 5mA for LED...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •