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

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
    10
    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
    6,884
    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.

Posting Permissions

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