Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 12 of 12

Thread: Teensy 4 - analog vu meter on ILI9341 tft display to slow

  1. #1
    Junior Member
    Join Date
    Jun 2020
    Posts
    8

    Teensy 4 - analog vu meter on ILI9341 tft display to slow

    Hello, everyone,

    for a project i am developing a VU-meter which imitates the original analog displays on a 2.8" display with ILI9341 controller.
    The SPI clock is 40MHz and the Teensy 4.0 with 600MHz is used.

    A frame buffer is used and as data I take automatically generated values between 0 and 100 and back.
    The main loop should be run through as fast as possible for testing.

    Unfortunately the needles don't move nearly as fast as hoped ;o(
    And the lower part of the Peak-LED is cut off and I don't know why yet.

    What am I doing wrong?
    And how do I get more speed of the needles?

    The project is pinned up here.

    Best regards
    Bruno

    Click image for larger version. 

Name:	revox_vu.jpg 
Views:	17 
Size:	140.2 KB 
ID:	20725

    https://youtu.be/GqF0ofbNNc0

    Code:
    #include "SPI.h"
    #include <ILI9341_t3n.h>
    #include "analog_leftside.c"
    #include "analog_leftside_led.c"
    #include "analog_rightside.c"
    #include "analog_rightside_led.c"
    
    #define TFT_RST 8
    #define TFT_DC  9
    #define TFT_CS  10
    
    ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST);
    
    int16_t leftNeedleRectMinX, rightNeedleRectMinX;
    int16_t leftNeedleRectMinY, rightNeedleRectMinY;
    int16_t leftNeedleRectMaxX, rightNeedleRectMaxX;
    int16_t leftNeedleRectMaxY, rightNeedleRectMaxY;
    
    int16_t workCounter;
    uint8_t pastLeft, pastRight;
    boolean direction;
    
    void setup() {
    	tft.begin(40000000);
    	tft.useFrameBuffer(true);
    	tft.setRotation(2);
    	tft.fillScreen(ILI9341_WHITE);
    	tft.writeRect(0, 0, 120, 320, (uint16_t*)analog_leftside);
    	tft.writeRect(120, 0, 120, 320, (uint16_t*)analog_rightside);
    	tft.updateScreen();
    }
    
    void loop(void) {
    	(!direction) ? workCounter++ : workCounter--;
    	if (workCounter > 100) {
    		workCounter = 100;
    		direction = true;
    	}
    	if (workCounter < 0) {
    		workCounter = 0;
    		direction = false;
    	}
    
    	drawNeedleLeft(workCounter);
    	drawNeedleRight(workCounter);
    }
    
    void drawNeedleLeft(uint8_t percent) {
    	if (percent != pastLeft) {
    		pastLeft = percent;
    
    		double scale = map(percent, 0, 100, 57, 123);
    		int16_t x0 = -115; // Start-X
    		int16_t y0 = 160;  // Start-Y
    		int16_t x1 = -115 + 193 * sin(scale * 0.0174532925); // End-X
    		int16_t y1 = 160 + 193 * cos(scale * 0.0174532925);  // End-Y
    
    		int16_t left_min_x = leftNeedleRectMinX;
    		int16_t left_min_y = leftNeedleRectMinY;
    		int16_t left_max_x = leftNeedleRectMaxX;
    		int16_t left_max_y = leftNeedleRectMaxY;
    
    		leftNeedleRectMinX = min(x0, x1);
    		leftNeedleRectMinY = min(y0, y1);
    		leftNeedleRectMaxX = max(x0, x1);
    		leftNeedleRectMaxY = max(y0, y1);
    
    		left_min_x = min(left_min_x, leftNeedleRectMinX);
    		left_min_y = min(left_min_y, leftNeedleRectMinY);
    		left_max_x = max(left_max_x, leftNeedleRectMaxX);
    		left_max_y = max(left_max_y, leftNeedleRectMaxY);
    
    		tft.setClipRect(0, 0, 120, 320);
    		tft.writeRect(0, 0, 120, 320, (percent >= 79) ? (uint16_t*)analog_leftside_led : (uint16_t*)analog_leftside);
    		tft.setClipRect(left_min_x, left_min_y, left_max_x - left_min_x + 1, left_max_y - left_min_y + 1);
    		tft.drawLine(x0, y0, x1, y1, ILI9341_BLACK);
    		tft.updateScreen();
    	}
    }
    
    void drawNeedleRight(uint8_t percent) {
    	if (percent != pastRight) {
    		pastRight = percent;
    
    		double scale = map(100 - percent, 0, 100, 57, 123);
    		int16_t x0 = 355; // Start-X
    		int16_t y0 = 160; // Start-Y
    		int16_t x1 = 355 - 193 * sin(scale * 0.0174532925); // End-X
    		int16_t y1 = 160 - 193 * cos(scale * 0.0174532925); // End-Y
    
    		int16_t right_min_x = rightNeedleRectMinX;
    		int16_t right_min_y = rightNeedleRectMinY;
    		int16_t right_max_x = rightNeedleRectMaxX;
    		int16_t right_max_y = rightNeedleRectMaxY;
    
    		rightNeedleRectMinX = min(x0, x1);
    		rightNeedleRectMinY = min(y0, y1);
    		rightNeedleRectMaxX = max(x0, x1);
    		rightNeedleRectMaxY = max(y0, y1);
    
    		right_min_x = min(right_min_x, rightNeedleRectMinX);
    		right_min_y = min(right_min_y, rightNeedleRectMinY);
    		right_max_x = max(right_max_x, rightNeedleRectMaxX);
    		right_max_y = max(right_max_y, rightNeedleRectMaxY);
    
    		tft.setClipRect(120, 0, 120, 320);
    		tft.writeRect(120, 0, 120, 320, (percent >= 79) ? (uint16_t*)analog_rightside_led : (uint16_t*)analog_rightside);
    		tft.setClipRect(right_min_x, right_min_y, right_max_x - right_min_x + 1, right_max_y - right_min_y + 1);
    		tft.drawLine(x0, y0, x1, y1, ILI9341_BLACK);
    		tft.updateScreen();
    	}
    }
    Attached Files Attached Files
    Last edited by DIYLAB; 06-25-2020 at 11:27 AM.

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,108
    I think some of the speed issue is due to the math on setting up your bounding rectangles...

    That is I added Serial.printf to your output of one meter and only when percent is multiple of 16...
    This is right after the updateScreen:
    Code:
        if (!(percent & 0xf)) Serial.printf("%d (%d %d)-(%d %d)\n",
            percent, left_min_x, left_min_y, left_max_x, left_max_y);
    The output looks like:
    Code:
    0 (-115 160)-(46 265)
    16 (-115 160)-(62 238)
    32 (-115 160)-(73 203)
    48 (-115 160)-(77 166)
    64 (-115 129)-(76 160)
    80 (-115 93)-(67 160)
    96 (-115 63)-(52 160)
    96 (-115 60)-(52 160)
    80 (-115 93)-(66 160)
    64 (-115 126)-(75 160)
    48 (-115 160)-(77 166)
    32 (-115 160)-(73 200)
    16 (-115 160)-(63 235)
    0 (-115 160)-(46 265)
    That is you start drawing the needle starting at position:
    Code:
    		int16_t x0 = -115; // Start-X
    		int16_t y0 = 160;  // Start-Y
    So your bounding rectangle will start somewhere out in large area. Maybe what you should do is to compute a bound rectangle for where the needles y is when X=0 if that makes sense...

    And then the only reason any of your LED shows up at all is because due to the negative position, some of it will be in that rectangle... But if you correct like I mention, probably none will be, so you may need to draw that area separately.

  3. #3
    Junior Member
    Join Date
    Jun 2020
    Posts
    8
    Dear Kurt, hello everyone,

    Thank you very much for the valuable suggestions!
    I am in the process of greatly simplifying the code, but I still have a problem with the calculation of the intersection point where the pointer enters the display.
    Unfortunately I am a bit overtaxed with trigonometry.

    How could I calculate the point of intersection or the height 'h'?

    Click image for larger version. 

Name:	intersection.jpg 
Views:	10 
Size:	87.6 KB 
ID:	20740

    Best regards
    Bruno

  4. #4
    Senior Member
    Join Date
    Oct 2019
    Posts
    134
    @KurtE shouldn't the clipping rectangle be cleared after updateScreen() (added in red)?
    Code:
    void setup() {
    	tft.begin(40000000);
    	tft.useFrameBuffer(true);
    	tft.setRotation(2);
    	tft.fillScreen(ILI9341_WHITE);
    	tft.writeRect(0, 0, 120, 320, (uint16_t*)analog_leftside);
    	tft.writeRect(120, 0, 120, 320, (uint16_t*)analog_rightside);
    	tft.updateScreen();
            tft.setClipRect();
    }
    
    void loop(void) {
    	(!direction) ? workCounter++ : workCounter--;
    	if (workCounter > 100) {
    		workCounter = 100;
    		direction = true;
    	}
    	if (workCounter < 0) {
    		workCounter = 0;
    		direction = false;
    	}
    
    	drawNeedleLeft(workCounter);
    	drawNeedleRight(workCounter);
    }
    
    void drawNeedleLeft(uint8_t percent) {
    	if (percent != pastLeft) {
    		pastLeft = percent;
    
    		double scale = map(percent, 0, 100, 57, 123);
    		int16_t x0 = -115; // Start-X
    		int16_t y0 = 160;  // Start-Y
    		int16_t x1 = -115 + 193 * sin(scale * 0.0174532925); // End-X
    		int16_t y1 = 160 + 193 * cos(scale * 0.0174532925);  // End-Y
    
    		int16_t left_min_x = leftNeedleRectMinX;
    		int16_t left_min_y = leftNeedleRectMinY;
    		int16_t left_max_x = leftNeedleRectMaxX;
    		int16_t left_max_y = leftNeedleRectMaxY;
    
    		leftNeedleRectMinX = min(x0, x1);
    		leftNeedleRectMinY = min(y0, y1);
    		leftNeedleRectMaxX = max(x0, x1);
    		leftNeedleRectMaxY = max(y0, y1);
    
    		left_min_x = min(left_min_x, leftNeedleRectMinX);
    		left_min_y = min(left_min_y, leftNeedleRectMinY);
    		left_max_x = max(left_max_x, leftNeedleRectMaxX);
    		left_max_y = max(left_max_y, leftNeedleRectMaxY);
    
    		tft.setClipRect(0, 0, 120, 320);
    		tft.writeRect(0, 0, 120, 320, (percent >= 79) ? (uint16_t*)analog_leftside_led : (uint16_t*)analog_leftside);
    		tft.setClipRect(left_min_x, left_min_y, left_max_x - left_min_x + 1, left_max_y - left_min_y + 1);
    		tft.drawLine(x0, y0, x1, y1, ILI9341_BLACK);
    		tft.updateScreen();
                    tft.setClipRect();
    	}
    }
    
    void drawNeedleRight(uint8_t percent) {
    	if (percent != pastRight) {
    		pastRight = percent;
    
    		double scale = map(100 - percent, 0, 100, 57, 123);
    		int16_t x0 = 355; // Start-X
    		int16_t y0 = 160; // Start-Y
    		int16_t x1 = 355 - 193 * sin(scale * 0.0174532925); // End-X
    		int16_t y1 = 160 - 193 * cos(scale * 0.0174532925); // End-Y
    
    		int16_t right_min_x = rightNeedleRectMinX;
    		int16_t right_min_y = rightNeedleRectMinY;
    		int16_t right_max_x = rightNeedleRectMaxX;
    		int16_t right_max_y = rightNeedleRectMaxY;
    
    		rightNeedleRectMinX = min(x0, x1);
    		rightNeedleRectMinY = min(y0, y1);
    		rightNeedleRectMaxX = max(x0, x1);
    		rightNeedleRectMaxY = max(y0, y1);
    
    		right_min_x = min(right_min_x, rightNeedleRectMinX);
    		right_min_y = min(right_min_y, rightNeedleRectMinY);
    		right_max_x = max(right_max_x, rightNeedleRectMaxX);
    		right_max_y = max(right_max_y, rightNeedleRectMaxY);
    
    		tft.setClipRect(120, 0, 120, 320);
    		tft.writeRect(120, 0, 120, 320, (percent >= 79) ? (uint16_t*)analog_rightside_led : (uint16_t*)analog_rightside);
    		tft.setClipRect(right_min_x, right_min_y, right_max_x - right_min_x + 1, right_max_y - right_min_y + 1);
    		tft.drawLine(x0, y0, x1, y1, ILI9341_BLACK);
    		tft.updateScreen();
                    tft.setClipRect();
    	}
    }

  5. #5
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,108
    @Rezo - clearing the clip rectangle is optional... That is if you ALWAYS set the new clip rectangle before your next output to frame buffer than it does not really matter...

    @DIYLAB - I totally understand, I had a minor in math when I got my BS several decades ago and I am now totally math challenged...

    But this can be thought of as simply a linear conversion so you can do the math directly or you can just use the map function...
    So for left needle you can compute something like:
    Code:
        int xEdge = 0;
        int yEdge = map(0, x0, x1, y0, y1);
    Below is my quick test of your code with out without minimizing the rectangle... Notice the #define at top, if you comment it out, it will run with your currently computed clip rectangle...
    I also added simple elapsedMillis variable which I then print out how many milliseconds it take for your code to do a complete cycle...

    Your code was taking about 1130ms to do a complete cycle up and down...
    Then using the simple mapping code, it now takes something like 770
    So a bit faster, but your LED does not show up at all... There are ways to fix that as well, you could expand the update rectangle if the LED state changes to include it to bounds, or do simple update of that area if LED changes... Could be through different Bitmaps if you like could be by fillCircle call...

    Hope this helps

    Code:
    #define USE_EDGES
    #include "SPI.h"
    #include <ILI9341_t3n.h>
    #include "analog_leftside.c"
    #include "analog_leftside_led.c"
    #include "analog_rightside.c"
    #include "analog_rightside_led.c"
    
    #define TFT_RST 8
    #define TFT_DC  9
    #define TFT_CS  10
    
    ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST);
    
    int16_t leftNeedleRectMinX, rightNeedleRectMinX;
    int16_t leftNeedleRectMinY, rightNeedleRectMinY;
    int16_t leftNeedleRectMaxX, rightNeedleRectMaxX;
    int16_t leftNeedleRectMaxY, rightNeedleRectMaxY;
    
    int16_t workCounter;
    uint8_t pastLeft, pastRight;
    boolean direction;
    elapsedMillis emCycle;
    
    void setup() {
      while (!Serial && millis() < 4000) ;
      Serial.begin(115200);
      tft.begin(40000000);
      tft.useFrameBuffer(true);
      tft.setRotation(2);
      tft.fillScreen(ILI9341_WHITE);
      tft.writeRect(0, 0, 120, 320, (uint16_t*)analog_leftside);
      tft.writeRect(120, 0, 120, 320, (uint16_t*)analog_rightside);
      tft.updateScreen();
      emCycle = 0;
    }
    
    void loop(void) {
      (!direction) ? workCounter++ : workCounter--;
      if (workCounter > 100) {
        workCounter = 100;
        direction = true;
      }
      if (workCounter < 0) {
        workCounter = 0;
        direction = false;
        Serial.println(emCycle, DEC);
        emCycle = 0;
      }
    
      drawNeedleLeft(workCounter);
      drawNeedleRight(workCounter);
    }
    
    void drawNeedleLeft(uint8_t percent) {
      if (percent != pastLeft) {
        pastLeft = percent;
    
        double scale = map(percent, 0, 100, 57, 123);
        int16_t x0 = -115; // Start-X
        int16_t y0 = 160;  // Start-Y
        int16_t x1 = -115 + 193 * sin(scale * 0.0174532925); // End-X
        int16_t y1 = 160 + 193 * cos(scale * 0.0174532925);  // End-Y
    
        int xEdge = 0;
        int yEdge = map(0, x0, x1, y0, y1);
    
        int16_t left_min_x = leftNeedleRectMinX;
        int16_t left_min_y = leftNeedleRectMinY;
        int16_t left_max_x = leftNeedleRectMaxX;
        int16_t left_max_y = leftNeedleRectMaxY;
    
    #ifdef USE_EDGES
        leftNeedleRectMinX = min(xEdge, x1);
        leftNeedleRectMinY = min(yEdge, y1);
        leftNeedleRectMaxX = max(xEdge, x1);
        leftNeedleRectMaxY = max(yEdge, y1);
    #else
        leftNeedleRectMinX = min(x0, x1);
        leftNeedleRectMinY = min(y0, y1);
        leftNeedleRectMaxX = max(x0, x1);
        leftNeedleRectMaxY = max(y0, y1);
    #endif
    
        left_min_x = min(left_min_x, leftNeedleRectMinX);
        left_min_y = min(left_min_y, leftNeedleRectMinY);
        left_max_x = max(left_max_x, leftNeedleRectMaxX);
        left_max_y = max(left_max_y, leftNeedleRectMaxY);
    
        tft.setClipRect(0, 0, 120, 320);
        tft.writeRect(0, 0, 120, 320, (percent >= 79) ? (uint16_t*)analog_leftside_led : (uint16_t*)analog_leftside);
        tft.setClipRect(left_min_x, left_min_y, left_max_x - left_min_x + 1, left_max_y - left_min_y + 1);
        tft.drawLine(x0, y0, x1, y1, ILI9341_BLACK);
        tft.updateScreen();
        //if (!(percent & 0xf)) Serial.printf("%d (%d %d)-(%d %d)\n",
        //    percent, left_min_x, left_min_y, left_max_x, left_max_y);   
      }
    }
    
    void drawNeedleRight(uint8_t percent) {
      if (percent != pastRight) {
        pastRight = percent;
    
        double scale = map(100 - percent, 0, 100, 57, 123);
        int16_t x0 = 355; // Start-X
        int16_t y0 = 160; // Start-Y
        int16_t x1 = 355 - 193 * sin(scale * 0.0174532925); // End-X
        int16_t y1 = 160 - 193 * cos(scale * 0.0174532925); // End-Y
        int xEdge = 240;
        int yEdge = map(240, x0, x1, y0, y1);
    
        int16_t right_min_x = rightNeedleRectMinX;
        int16_t right_min_y = rightNeedleRectMinY;
        int16_t right_max_x = rightNeedleRectMaxX;
        int16_t right_max_y = rightNeedleRectMaxY;
    
    #ifdef USE_EDGES
        rightNeedleRectMinX = min(xEdge, x1);
        rightNeedleRectMinY = min(yEdge, y1);
        rightNeedleRectMaxX = max(xEdge, x1);
        rightNeedleRectMaxY = max(yEdge, y1);
    #else
        rightNeedleRectMinX = min(x0, x1);
        rightNeedleRectMinY = min(y0, y1);
        rightNeedleRectMaxX = max(x0, x1);
        rightNeedleRectMaxY = max(y0, y1);
    #endif
        right_min_x = min(right_min_x, rightNeedleRectMinX);
        right_min_y = min(right_min_y, rightNeedleRectMinY);
        right_max_x = max(right_max_x, rightNeedleRectMaxX);
        right_max_y = max(right_max_y, rightNeedleRectMaxY);
    
        tft.setClipRect(120, 0, 120, 320);
        tft.writeRect(120, 0, 120, 320, (percent >= 79) ? (uint16_t*)analog_rightside_led : (uint16_t*)analog_rightside);
        tft.setClipRect(right_min_x, right_min_y, right_max_x - right_min_x + 1, right_max_y - right_min_y + 1);
        tft.drawLine(x0, y0, x1, y1, ILI9341_BLACK);
        tft.updateScreen();
      }
    }

  6. #6
    for the needle drawing, since you always start at the same location, I think you can create an equation for the needles line (i've not studied the code but it will be something like y=mx + b. So for the first point x1 = 0, then y1 is what ever the computed value is based on the equation. For x2 = NeedleRadius * cos(needleAngle), y2 = NeedleRadius * sin(NeedleAngle).

    I would do more of what CurtE did and put timers around certain areas to look for where calcs are slow. I'm 99.9999999% sure in the end you display should be super fast.

    I have a bar-chart type meter for an equalizer to control mic input--and is ripping fast--and all bands go through FFT to compute heights. Start watching around the 10 sec mark
    https://www.youtube.com/watch?v=tCUU...&index=15&t=0s

  7. #7
    Junior Member
    Join Date
    Jun 2020
    Posts
    8
    Quote Originally Posted by KurtE View Post
    Hope this helps
    Hello,

    Thank you very much for the map solution!
    The clipping is now placed correctly around the needle, the peak LED is working and the drawing is only done in the visible area.

    All fine, but unfortunately not faster than Kurt's because of these measures.

    Something brakes there - only what?

    Best regards
    Bruno

    Click image for larger version. 

Name:	clipping.jpg 
Views:	5 
Size:	309.4 KB 
ID:	20751

    https://youtu.be/X10kchVfnvA

    Code:
    #include "SPI.h"
    #include <ILI9341_t3n.h>
    #include "analog_leftside.c"
    #include "analog_rightside.c"
    
    #define DEG2RAD 0.0174532925
    
    #define TFT_RST 8
    #define TFT_DC  9
    #define TFT_CS  10
    
    ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST);
    
    int16_t leftNeedleRectMinX, rightNeedleRectMinX;
    int16_t leftNeedleRectMinY, rightNeedleRectMinY;
    int16_t leftNeedleRectMaxX, rightNeedleRectMaxX;
    int16_t leftNeedleRectMaxY, rightNeedleRectMaxY;
    uint8_t pastLeft, pastRight;
    elapsedMillis emCycle;
    
    void setup() {
    	Serial.begin(115200);
    	tft.begin(40000000);
    	tft.useFrameBuffer(true);
    	tft.setRotation(2);
    	tft.fillScreen(ILI9341_WHITE);
    	tft.writeRect(0, 0, 120, 320, (uint16_t*)analog_leftside);
    	tft.writeRect(120, 0, 120, 320, (uint16_t*)analog_rightside);
    	tft.updateScreen();
    	emCycle = 0;
    }
    
    void loop(void) {
    	for (uint8_t i = 0; i <= 100; i++) {
    		drawNeedleLeft(i);
    		drawNeedleRight(i);
    	}
    	for (uint8_t i = 99; i > 0; i--) {
    		drawNeedleLeft(i);
    		drawNeedleRight(i);
    	}
    
    	//Serial.println(emCycle, DEC);
    	emCycle = 0;
    }
    
    void drawNeedleLeft(uint8_t percent) {
    	if (percent != pastLeft) {
    		pastLeft = percent;
    
    		double scale = map(percent, 0, 100, 57, 123);
    		double arc = scale * DEG2RAD;
    		int16_t x1 = -115 + 193 * sin(arc);
    		int16_t y1 = 160 + 193 * cos(arc);
    		int yEdge = map(0, -115, x1, 160, y1);
    
    		int16_t left_min_x = leftNeedleRectMinX;
    		int16_t left_min_y = leftNeedleRectMinY;
    		int16_t left_max_x = leftNeedleRectMaxX;
    		int16_t left_max_y = leftNeedleRectMaxY;
    
    		leftNeedleRectMinX = min(0, x1);
    		leftNeedleRectMinY = min(yEdge, y1);
    		leftNeedleRectMaxX = max(0, x1);
    		leftNeedleRectMaxY = max(yEdge, y1);
    
    		left_min_x = min(left_min_x, leftNeedleRectMinX);
    		left_min_y = min(left_min_y, leftNeedleRectMinY);
    		left_max_x = max(left_max_x, leftNeedleRectMaxX);
    		left_max_y = max(left_max_y, leftNeedleRectMaxY);
    
    		// Background
    		tft.setClipRect(0, 0, 120, 320);
    		tft.writeRect(0, 0, 120, 320, (uint16_t*)analog_leftside);
    
    		// Peak LED
    		if (percent > 78) {
    			tft.setClipRect(12, 145, 17, 17);
    			tft.fillCircle(20, 153, 7, ILI9341_RED);
    			tft.updateScreen();
    		}
    
    		// Needle
    		// DEBUG: tft.drawRect(left_min_x, left_min_y, left_max_x - left_min_x + 1, left_max_y - left_min_y + 1, ILI9341_MAGENTA);
    		tft.setClipRect(left_min_x, left_min_y, left_max_x - left_min_x + 1, left_max_y - left_min_y + 1);
    		tft.drawLine(0, yEdge, x1, y1, ILI9341_BLUE);
    		tft.updateScreen();
    	}
    }
    
    void drawNeedleRight(uint8_t percent) {
    	if (percent != pastRight) {
    		pastRight = percent;
    
    		double scale = map(100 - percent, 0, 100, 57, 123);
    		double arc = scale * DEG2RAD;
    		int16_t x1 = 355 - 193 * sin(arc);
    		int16_t y1 = 160 - 193 * cos(arc);
    		int16_t yEdge = map(240, 355, x1, 160, y1);
    
    		int16_t right_min_x = rightNeedleRectMinX;
    		int16_t right_min_y = rightNeedleRectMinY;
    		int16_t right_max_x = rightNeedleRectMaxX;
    		int16_t right_max_y = rightNeedleRectMaxY;
    
    		rightNeedleRectMinX = min(240, x1);
    		rightNeedleRectMinY = min(yEdge, y1);
    		rightNeedleRectMaxX = max(240, x1);
    		rightNeedleRectMaxY = max(yEdge, y1);
    
    		right_min_x = min(right_min_x, rightNeedleRectMinX);
    		right_min_y = min(right_min_y, rightNeedleRectMinY);
    		right_max_x = max(right_max_x, rightNeedleRectMaxX);
    		right_max_y = max(right_max_y, rightNeedleRectMaxY);
    
    		// Background
    		tft.setClipRect(120, 0, 120, 320);
    		tft.writeRect(120, 0, 120, 320, (uint16_t*)analog_rightside);
    
    		// Peak LED
    		if (percent > 78) {
    			tft.setClipRect(212, 145, 17, 17);
    			tft.fillCircle(220, 153, 7, ILI9341_RED);
    			tft.updateScreen();
    		}
    
    		// Needle
    		// DEBUG: tft.drawRect(right_min_x, right_min_y, right_max_x - right_min_x, right_max_y - right_min_y + 1, ILI9341_MAGENTA);
    		tft.setClipRect(right_min_x, right_min_y, right_max_x - right_min_x, right_max_y - right_min_y + 1);
    		tft.drawLine(240, yEdge, x1, y1, ILI9341_BLUE);
    		tft.updateScreen();
    	}
    }
    Attached Files Attached Files

  8. #8
    Junior Member
    Join Date
    Jun 2020
    Posts
    8
    Quote Originally Posted by KrisKasprzak View Post
    Start watching around the 10 sec mark[/url]
    Hi Kris,

    I watched your video and I am impressed!
    You did very well, my respects.

    Best regards
    Bruno

  9. #9
    Junior Member
    Join Date
    Jun 2020
    Posts
    8
    Hello everyone,

    now the complete loop runs in 247ms
    Improvements:
    - PROGMEM removed from image files;
    - both images are no longer 120x320px but 96x224px
    - For testing, set the SPI bus to 50MHz, previously 40MHz (stable overnight)

    I noticed a strange effect:
    When I compile the code with the Arduino IDE, the loop runs in 247ms. If I use VisualStudio2019 with VisualMicro, the loop runs in 418ms. But VisualMicro is set to release and full speed.

    One more question:
    I would like to try 16 colors instead of real colors for the background images.
    There is the method writeRect4BPP - how exactly does it work?
    Is there a small example how to convert a 24Bit .PNG into the required format and then use it?

    I wish you a nice weekend
    Bruno
    Attached Files Attached Files

  10. #10
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,108
    Visual Studio/Visual Micro - I have not done much with them. In theory if your settings are setup the same as Arduino IDE, you should get the same speed (I think)... But.

    writeRect4BPP - How to convert? Not sure. You could probably write some program that runs through your array and converts it to another array where the data is packed 2 pixels per byte, plus an array of the 16 colors to use. But how you choose the 16 colors could be the interesting part.

    How it works, is each nibble (4 bits) is used as an index into the passed in color palette which is 16 bits per color. So if a nibble is a 0, it uses the first color. There is no speed up to the display as you have to send the same amount of data. The benefit is the ability for your program to pack more data, especially on boards who have more limited space.

  11. #11
    Junior Member
    Join Date
    Jun 2020
    Posts
    8
    Quote Originally Posted by KurtE View Post
    Visual Studio/Visual Micro - I have not done much with them. In theory if your settings are setup the same as Arduino IDE, you should get the same speed (I think)... But.
    Hi,
    I have found the setting in VisualStudio/VisualMicro!
    Switch off 'Gdb', then everything is as fast as with the Arduino IDE.
    Maybe the info is interesting?

    Click image for larger version. 

Name:	visualmicro01.png 
Views:	7 
Size:	34.5 KB 
ID:	20771

    Click image for larger version. 

Name:	visualmicro02.png 
Views:	9 
Size:	34.2 KB 
ID:	20772

    Best regards
    Bruno

  12. #12
    Junior Member
    Join Date
    Aug 2014
    Location
    Berlin, GERMANY
    Posts
    7
    Dear Bruno,
    the line
    int yEdge = map(0, -115, x1, 160, y1); could be written as:
    int yEdge = 160 + 115 *tan(1.57078 -x1);
    It derives from the formula:
    a = b * tan(arc); with given arc, b.
    The hard coded values are:
    1.5708 = PI/2,
    and from your setup: 160 -> y_0 and 115 -> length of x until display

Posting Permissions

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