Forum Rule: Always post complete source code & details to reproduce any issue!
Page 28 of 28 FirstFirst ... 18 26 27 28
Results 676 to 696 of 696

Thread: ILI9488_t3 - Support for the ILI9488 on T3.x and beyond...

  1. #676
    Quote Originally Posted by KurtE View Post
    Thanks Mike,

    Not sure at times how much these change help or not... Often times it depends on how much time the code overhead is versus how many times it avoids with reducing the bytes sent out SPI. Example did same code change for the ST7735/89_t3 code base and tried it on T4 with ST7789 2" version... Code change:

    I tried it with and without the change:
    Code:
    #if 1
      uint16_t _previous_addr_x0 = 0xffff; 
      uint16_t _previous_addr_x1 = 0xffff; 
      uint16_t _previous_addr_y0 = 0xffff; 
      uint16_t _previous_addr_y1 = 0xffff; 
    
      void setAddr(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
        __attribute__((always_inline)) {
          if ((x0 != _previous_addr_x0) || (x1 != _previous_addr_x1)) {
            writecommand(ST7735_CASET); // Column addr set
            writedata16(x0+_xstart);   // XSTART 
            writedata16(x1+_xstart);   // XEND
            _previous_addr_x0 = x0;
            _previous_addr_x1 = x1;
          }
          if ((y0 != _previous_addr_y0) || (y1 != _previous_addr_y1)) {
            writecommand(ST7735_RASET); // Row addr set
            writedata16(y0+_ystart);   // YSTART
            writedata16(y1+_ystart);   // YEND
            _previous_addr_y0 = y0;
            _previous_addr_y1 = y1;
        }
      }
    #else
      void setAddr(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
        __attribute__((always_inline)) {
            writecommand(ST7735_CASET); // Column addr set
            writedata16(x0+_xstart);   // XSTART 
            writedata16(x1+_xstart);   // XEND
            writecommand(ST7735_RASET); // Row addr set
            writedata16(y0+_ystart);   // YSTART
            writedata16(y1+_ystart);   // YEND
      }
    #endif
    Using a version of the graphic test that works in all 4 orientations and prints out timings...
    And not much difference:

    Code:
    	BEFORE			AFTER	
    Rotations	0	1		0	1
    tftPrintTest: 	1611	1611		1610	1610
    testlines: 	536	535		535	535
    tftPrintTest: 	73	73		73	74
    testdrawrects: 	65	71		65	70
    tftPrintTest: 	593	1199		592	1199
    testfill/drawcircles: 	204	205	191	190
    testroundrects: 	124	123		121	122
    testtriangles: 	73	80		74	79
    mediabuttons: 	1115	1114		1115	1115
    Totals:	4394	5012		4376	4995
    I show two of the orientations. Find that the landscape versus portrait at least on one of the tests is a lot different in timing...
    But the before versus the later is not a big difference.
    Doesn't x change permanently and y only rarely when using the frame buffer?
    Maybe only check if x has changed if framebuffer is not active.

  2. #677
    Hello everybody,
    I have a suggestion to further reduce SPI transfer when using framebuffer. It is based on "updateChangedRange", but more efficient when used correctly. Unfortunately, more memory is required, namely an eighth of the resolution of the display. However, most people should have enough memory from current Teensy models. The CPU is also more demanding, but it is faster than SPI.
    I just put it in an example code:

    Code:
    const unsigned int _width = 320; //for debug only
    const unsigned int _height = 480; //for debug only
    
    uint8_t changesMask[_width * _height / 8]; //A mask of the changed pixels with an eighth of the resolution because we use the bits as Boolean.
    
    void setup() {
      Serial.begin(9600);
      while (!Serial) ; //wait for Arduino Serial Monitor for debug only
    
      //Change arbitrary pixels
      updateChangedPixel(1, 0);
      updateChangedPixel(7, 0);
      updateChangedPixel(3, 0);
      updateChangedPixel(36, 0);
      updateChangedPixel(41, 0);
      updateChangedPixel(47, 0);
    
      updateScreen();
    
      //feedback for debug
      Serial.println("Screen updated.");
    
      //Change pixel area
      updateChangedPixelArea(5,5,10,10);
    
      updateScreen();
    
      //feedback for debug
      Serial.println("Screen updated.");
    }
    
    void updateChangedPixelArea(unsigned int x, unsigned int y, unsigned int w, unsigned int h) {
      for(int _y = y; _y < y + h; _y++){
        for(int _x = x; _x < x + w; _x++){
          updateChangedPixel(_x, _y);
        }
      }
    }
    
    void updateChangedPixel(unsigned int x, unsigned int y) {
      if (x >= _width || y >= _height) return; //Out of bounds? We are done.
    
      int maskIndex = (y * _width + x) / 8; //An eighth of the resolution because we use the bits as Boolean.
      int bitIndex = x % 8;
      
      bitSet(changesMask[maskIndex], bitIndex);
    }
    
    void updateScreen(){
      for (int i = 0; i < _width * _height; i++){
        if (bitRead(changesMask[i/8], i % 8)){
          //Transfer the changed pixels via SPI
          //TODO in lib
          
          //Print the changed pixels for debug only
          Serial.print("bitmap byte no. ");
          Serial.print(i);
          Serial.println(" is changed");
        }
      }
      
      memset(changesMask,0,_width * _height / 8); //reset the Mask
    }
    
    void loop() {
    
    }
    Useful?

  3. #678
    Junior Member
    Join Date
    Jun 2020
    Location
    Rome, Italy
    Posts
    15
    Quote Originally Posted by sepp89117 View Post
    Hello everybody,
    I have a suggestion to further reduce SPI transfer when using framebuffer. It is based on "updateChangedRange", but more efficient when used correctly. Unfortunately, more memory is required, namely an eighth of the resolution of the display. However, most people should have enough memory from current Teensy models. The CPU is also more demanding, but it is faster than SPI.
    I just put it in an example code:

    Code:
    const unsigned int _width = 320; //for debug only
    const unsigned int _height = 480; //for debug only
    
    uint8_t changesMask[_width * _height / 8]; //A mask of the changed pixels with an eighth of the resolution because we use the bits as Boolean.
    
    void setup() {
      Serial.begin(9600);
      while (!Serial) ; //wait for Arduino Serial Monitor for debug only
    
      //Change arbitrary pixels
      updateChangedPixel(1, 0);
      updateChangedPixel(7, 0);
      updateChangedPixel(3, 0);
      updateChangedPixel(36, 0);
      updateChangedPixel(41, 0);
      updateChangedPixel(47, 0);
    
      updateScreen();
    
      //feedback for debug
      Serial.println("Screen updated.");
    
      //Change pixel area
      updateChangedPixelArea(5,5,10,10);
    
      updateScreen();
    
      //feedback for debug
      Serial.println("Screen updated.");
    }
    
    void updateChangedPixelArea(unsigned int x, unsigned int y, unsigned int w, unsigned int h) {
      for(int _y = y; _y < y + h; _y++){
        for(int _x = x; _x < x + w; _x++){
          updateChangedPixel(_x, _y);
        }
      }
    }
    
    void updateChangedPixel(unsigned int x, unsigned int y) {
      if (x >= _width || y >= _height) return; //Out of bounds? We are done.
    
      int maskIndex = (y * _width + x) / 8; //An eighth of the resolution because we use the bits as Boolean.
      int bitIndex = x % 8;
      
      bitSet(changesMask[maskIndex], bitIndex);
    }
    
    void updateScreen(){
      for (int i = 0; i < _width * _height; i++){
        if (bitRead(changesMask[i/8], i % 8)){
          //Transfer the changed pixels via SPI
          //TODO in lib
          
          //Print the changed pixels for debug only
          Serial.print("bitmap byte no. ");
          Serial.print(i);
          Serial.println(" is changed");
        }
      }
      
      memset(changesMask,0,_width * _height / 8); //reset the Mask
    }
    
    void loop() {
    
    }
    Useful?
    A "dirty rectangle" scheme would help with perf, but your implementation (1 pixel at a time) would be self defeating because of the overhead of writing/skipping individual pixels. It's not about the total data sent over SPI, but the transitions from command to data and the total sent. Please see my blog post for more info about this concept:

    https://bitbanksoftware.blogspot.com...al-i2cspi.html

    A better approach would be to find a minimum rectangle of change or divide the display into tiles (e.g. 16x16 pixels). The CPU has enough spare cycles to make checking for changes worthwhile and square tiles would allow contiguous writes of a decent sized area.

  4. #679
    Quote Originally Posted by bitbank View Post
    A "dirty rectangle" scheme would help with perf, but your implementation (1 pixel at a time) would be self defeating because of the overhead of writing/skipping individual pixels. It's not about the total data sent over SPI, but the transitions from command to data and the total sent. Please see my blog post for more info about this concept:

    https://bitbanksoftware.blogspot.com...al-i2cspi.html

    A better approach would be to find a minimum rectangle of change or divide the display into tiles (e.g. 16x16 pixels). The CPU has enough spare cycles to make checking for changes worthwhile and square tiles would allow contiguous writes of a decent sized area.
    Yes, of course, unfortunately I didn't think that far. For each pixel a "setAddr" has to be executed and a RAMWR command has to be sent ... Stupid of me.
    That with the tiles is a good idea. One could write an algorithm that calculates the optimal number of tiles. I probably cannot leave it and will try shortly.

  5. #680
    Hello everyone, the continuation of my project is almost finished. Unfortunately I still have a problem with the display. It flickers in some modes. You may have a look here: https://www.youtube.com/watch?v=Z3tFuwl-68Q
    Does anyone have a tip to get this under control?

    Thank you!

  6. #681
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,685
    I hate to say the obvious, but you need to organize your output code as to not flicker...

    If you are not, I would be using the frame buffer, so usually easy to just draw the screen and then do updateScreen to put the fully updated pixels on the screen.

    In cases like this, I often end up setting up to single step through the display process.

    I end up adding a simple function (or in line code that looks like:
    Code:
    void waitUserInput()
    {
      Serial.println("Press anykey to continue");
      while (Serial.read() == -1) ;
      while (Serial.read() != -1) ;
    }
    That for example I put in a call right after each call to updateScreen, and then step through my outputs and see if everything progresses from each display to the next. If not you have localized down to where the issue might be...
    Note: sometimes I add an optional string parameter to wait function that prints out, the string, so if things jump around you know which one... Again something like:

    extern void waitUserInput(const char *title=nullptr);
    ...

    Code:
    void waitUserInput(const char *title)
    {
      if (title) Serial.print(title);
      Serial.println("Press anykey to continue");
      while (Serial.read() == -1) ;
      while (Serial.read() != -1) ;
    }

    But again unless we see your actual code, we can only guess.
    Could be you are not use Frame buffer and have code that does: tft.fillScreen(...)
    followed by drawing of the display, which almost for sure will flicker.

    Or you are using Frame buffer and you are using clipping. Then maybe you did a lot of your updates with clip rectangle on, which implies rest of display was not updated, and then did an update without any clip rectangle and it had whatever garbage is in the buffer...

  7. #682
    Thank you for your prompt reply! Did you watch my video? The code initially runs smoothly. Only when the display gets warm, with high outside temperatures, does it start to look like in the video. I think it is due to some parameters in the initiation of the display, wrongly configured voltages? You can find the init comands at github in my repository Ili9486 if you want to see it.

  8. #683
    Quote Originally Posted by sepp89117 View Post
    Thank you for your prompt reply! Did you watch my video? The code initially runs smoothly. Only when the display gets warm, with high outside temperatures, does it start to look like in the video. I think it is due to some parameters in the initiation of the display, wrongly configured voltages? You can find the init comands at github in my repository Ili9486 if you want to see it.
    So now I had time to take care of the problem. The solution was to adjust the init_commands for Power control 1 (C0h). The standard parameters are obviously not good. I have set both parameters from 0Eh to 17h. Now it runs without flickering.

  9. #684
    Junior Member
    Join Date
    Jun 2019
    Posts
    18
    In ILI9488_t3.cpp, lines 84 and 85 are commented out which prevent code compiling on Teensy 4.1 when trying to use DMA (updateScreenAsync):
    84: //DMASetting ILI9488_t3::_dmasettings[2];
    85: //DMAChannel ILI9488_t3::_dmatx;

    Uncommenting these makes the code compile and it seems to work (though with a screen tear midway through which I have not looked into yet). Why are the lines commented out? Thanks.

  10. #685
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,685
    Which version do you have?

    That is there was a change PR that went to @mjs513 and then I believe was pulled into the recently released Teensyduino...

    The change was: DMASettings and DMAChannel were no longer static objects, but instead were members of the main tft class. So no longer needed to be defined here.

    Why? Because on T4.1 with possibility of external memory, you can have more than one of these displays and as such having it static would not work properly.

  11. #686
    Junior Member
    Join Date
    Jun 2019
    Posts
    18
    Thanks for the reply.

    Quote Originally Posted by KurtE View Post
    Which version do you have?
    I was using the default version and then I tried the GitHub version: https://github.com/mjs513/ILI9488_t3

  12. #687
    Junior Member
    Join Date
    Apr 2015
    Posts
    13
    I have an app on a Teensy4.1 that I am developing that has problems which seem to be related to the font drawing routine.

    // Tft.setTextColor(ILI9488_CYAN, ILI9488_BLACK);
    Tft.setTextColor(ILI9488_CYAN);
    Tft.setFont(ComicSansMS_20);

    If I use the commented out text color command I seem to be getting Stack corruption as my program starts doing random things and often crashes the display all together.
    I can replace the use of non opaque font over writing by just using a fillrect for that part of the display but then I get flickering.
    Has anybody else had this issue when using background colours for fonts?
    I use the Mono font elsewhere in the app and this doesn't appear to have the same issue.

  13. #688
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,685
    Quote Originally Posted by Cotman View Post
    I have an app on a Teensy4.1 that I am developing that has problems which seem to be related to the font drawing routine.

    // Tft.setTextColor(ILI9488_CYAN, ILI9488_BLACK);
    Tft.setTextColor(ILI9488_CYAN);
    Tft.setFont(ComicSansMS_20);

    If I use the commented out text color command I seem to be getting Stack corruption as my program starts doing random things and often crashes the display all together.
    I can replace the use of non opaque font over writing by just using a fillrect for that part of the display but then I get flickering.
    Has anybody else had this issue when using background colours for fonts?
    I use the Mono font elsewhere in the app and this doesn't appear to have the same issue.
    If you post a (reasonably) simple and complete sketch that reproduces this, will take a look. Without the test case it may be hard to do, but will still try to take look.

  14. #689
    Junior Member
    Join Date
    Apr 2015
    Posts
    13
    Quote Originally Posted by KurtE View Post
    If you post a (reasonably) simple and complete sketch that reproduces this, will take a look. Without the test case it may be hard to do, but will still try to take look.
    Thanks for the reply. I was planning on doing this but as the corruption was so random it may have been hard to reproduce. It was corrupting the CRC32 routine before I added the touch input check, then it was corrupting the Z value so my presumption was it was corrupting the stack.
    Anyway, I have found the issue, don't actually understand the code or interface to the TFT fully, but certainly in my case the problem has now gone. There appear to be several versions of the code on GitHub, presumably forks, but don't have the time to chase them down at the moment.

    Anyway, the fix is that I added a 'writecommand_last(ILI9488_NOP);' line in before the 'endSPITransaction' at the end of the 'drawFontChar()' function.
    So:
    3147 write16BitColor(textbgcolor);
    3148 writecommand_last(ILI9488_NOP); // Inserted Line
    3149 endSPITransaction();

    Can you explain why this would be needed? Or has the fault just moved so I am not seeing it!

  15. #690
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,685
    I think I know what is going on...

    If you would not mind, could you try a quick test for me:

    Remove your write command.
    Instead change the line above it:
    Code:
    write16BitColor(textbgcolor, true);
    What was happening is we were not telling the write code that this was the last item to be output and as such it probably had the SPI continue bit set in the TCR register.
    Which is probably what you were seeing.

  16. #691
    Junior Member
    Join Date
    Apr 2015
    Posts
    13
    Quote Originally Posted by KurtE View Post
    If you would not mind, could you try a quick test for me:
    Remove your write command.
    Instead change the line above it:
    Code:
    write16BitColor(textbgcolor, true);
    Yes, that still works perfectly. Thanks for taking the time to reply and for the speed of your response. I have used Teensy's since the original and must say I am loving the speed of the 4.1 and the USB host just wish it had another 8 I/O pins .

  17. #692
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,685
    @Cotman - helps to have good information... You led me right too the issue.

    Issued PR back to @mjs513 https://github.com/mjs513/ILI9488_t3/pull/22

    May have to check a few other libraries to see if same problem.

    As for 8 other IO pins...
    It may depend on how and how hard you need them...
    Example the bottom memory footprints, you can get 7 IO pins there.

    SDCard: you can get 6 IO pins there, by using an SD card breakout... I have played around with one from Sparfun and I have done my own. It was sort of fun with T3.5/6 to use this to be able to sometimes hook up a tft display..

  18. #693
    Junior Member
    Join Date
    Apr 2015
    Posts
    13
    Quote Originally Posted by KurtE View Post
    As for 8 other IO pins...
    It may depend on how and how hard you need them...
    Example the bottom memory footprints, you can get 7 IO pins there.
    SDCard: you can get 6 IO pins there, by using an SD card breakout... I have played around with one from Sparfun and I have done my own. It was sort of fun with T3.5/6 to use this to be able to sometimes hook up a tft display..
    Am currently using the 7 memory lines as I still want SD card access, it's just fiddly having to add the 7 wires and not so neat The project is an IC tester for up to 42 pin DIPS of all types, for some I need speed to test and others I need to simulate clocks etc which is why I haven't gone the SPI DIO route. Though I still had to add 48 DIO SPI lines for power control to combinations of the 42 pins.

  19. #694
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,685
    Quote Originally Posted by Cotman View Post
    Am currently using the 7 memory lines as I still want SD card access, it's just fiddly having to add the 7 wires and not so neat The project is an IC tester for up to 42 pin DIPS of all types, for some I need speed to test and others I need to simulate clocks etc which is why I haven't gone the SPI DIO route. Though I still had to add 48 DIO SPI lines for power control to combinations of the 42 pins.
    As for the bottom 7 pins, I did a quick and dirty castellated add on board to solder to those pins, plus the 5 internal pins: program... and brought those out to be breadboard compatible...
    I built one of them to be able to do testing using those pins.

    Click image for larger version. 

Name:	IMG_1121.jpg 
Views:	15 
Size:	77.5 KB 
ID:	21396

    Here is showing the actual small board with other T4.1 that has chips...
    Click image for larger version. 

Name:	IMG_1119.jpg 
Views:	15 
Size:	159.4 KB 
ID:	21397

    If I were to do more of these, I probably would have made the center ones line on/off with pads cut in half like the others, so that they can solder in castellated as well.
    But for my test setup works OK.

  20. #695
    Senior Member
    Join Date
    Oct 2019
    Posts
    148
    I FINALLY got to testing the buydisplay ILI9488 on the T4.1 with external PSRAM.

    Unfortunately, it does not work well at all using external PSRAM. It seem to update extremely slow when uncommenting #define ENABLE_EXT_DMA_UPDATES in the header file


    My current implementation uses tft.useFrameBuffer(true) and then using the following methods to draw onto the screen:
    Code:
    tft.setClipRect(a, b, c, d);
    tft.updateScreen();
    tft.setClipRect();

    I have ran the memory test found the PJRC website to confirm that the PSRAM is working as it should.

    Any suggestions?

  21. #696
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,685
    It is always an interesting trade off. The PSRAM is a lot slower memory than the others... But in many cases the cache can hide the differences in speed.

    In the UpdateScreen case it will likely be slower... As you are just reading and writing to the buffer and to the SPI registers... And slower memory access... Although I can not imaging that it should be that much slower as you are still dealing with SPI speeds.

    What the ENABLE_EXT_DMA_UPDATES does is to allow the code to store all of the pixels using twice as much memory per pixel (32 bits instead of 16), which implies you are touching more memory. But what it also allows is for the DMA code to work directly. That is without this, the code for doing the updateScreenAsync, uses two secondary buffers, which it uses round robin, and it would convert the 16 bit colors into 24 bit colors (in 32 bits) and then output that using DMA. When the first buffer completes outputting, it automatically goes on to start outputting the second buffer, and gives an interrupt, which the code then refills the first buffer with the next set of pixels... So there is lots of overhead going on in the background.

    With the PSRAM 32 bit buffer, you can simply startup a DMA operation to directly output from this buffer to the SPI, so you only get one interrupt per screen... And no data conversion ... But each memory access is slower...

    As for speeding it up... If you are knowing that you are going to output setClipRect(a, b, c, d) if you do this before your code actually updates the screen buffer than only those pixels (and as such 32 bit words) in memory that are within that rectangle will be touched... Which depending on how big a region you are updating, could be good win.

Posting Permissions

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