209 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			209 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
| // This sketch is for the RP2040 and ILI9341 TFT display.
 | |
| // Other processors may work if they have sufficient RAM for
 | |
| // a full screen buffer (240 x 320 x 2 = 153,600 bytes).
 | |
| 
 | |
| // In this example 2 sprites are used to create DMA toggle
 | |
| // buffers. Each sprite is half the screen size, this allows
 | |
| // graphics to be rendered in one sprite at the same time
 | |
| // as the other sprite is being sent to the screen.
 | |
| 
 | |
| // RP2040 typically runs at 45-48 fps
 | |
| 
 | |
| // Created by Bodmer 20/04/2021 as an example for:
 | |
| // https://github.com/Bodmer/TFT_eSPI
 | |
| 
 | |
| // Number of circles to draw
 | |
| #define CNUMBER 42
 | |
| 
 | |
| // Define the width and height according to the TFT and the
 | |
| // available memory. The sprites will require:
 | |
| //     DWIDTH * DHEIGHT * 2 bytes of RAM
 | |
| // Note: for a 240 * 320 area this is 150 Kbytes!
 | |
| #define DWIDTH  240
 | |
| #define DHEIGHT 320
 | |
| 
 | |
| #include <TFT_eSPI.h>
 | |
| 
 | |
| // Library instance
 | |
| TFT_eSPI    tft = TFT_eSPI();
 | |
| 
 | |
| // Create two sprites for a DMA toggle buffer
 | |
| TFT_eSprite spr[2] = {TFT_eSprite(&tft), TFT_eSprite(&tft)};
 | |
| 
 | |
| // Pointers to start of Sprites in RAM (these are then "image" pointers)
 | |
| uint16_t* sprPtr[2];
 | |
| 
 | |
| // Used for fps measuring
 | |
| uint16_t counter = 0;
 | |
| int32_t startMillis = millis();
 | |
| uint16_t interval = 100;
 | |
| String fps = "xx.xx fps";
 | |
| 
 | |
| // Structure to hold circle plotting parameters
 | |
| typedef struct circle_t {
 | |
|   int16_t   cx[CNUMBER] = { 0 }; // x coordinate of centre
 | |
|   int16_t   cy[CNUMBER] = { 0 }; // y coordinate of centre
 | |
|   int16_t   cr[CNUMBER] = { 0 }; // radius
 | |
|   uint16_t col[CNUMBER] = { 0 }; // colour
 | |
|   int16_t   dx[CNUMBER] = { 0 }; // x movement & direction
 | |
|   int16_t   dy[CNUMBER] = { 0 }; // y movement & direction
 | |
| } circle_param;
 | |
| 
 | |
| // Create the structure and get a pointer to it
 | |
| circle_t *circle = new circle_param;
 | |
| 
 | |
| // #########################################################################
 | |
| // Setup
 | |
| // #########################################################################
 | |
| void setup() {
 | |
|   Serial.begin(115200);
 | |
| 
 | |
|   tft.init();
 | |
|   tft.initDMA();
 | |
|   tft.fillScreen(TFT_BLACK);
 | |
| 
 | |
|   // Create the 2 sprites, each is half the size of the screen
 | |
|   sprPtr[0] = (uint16_t*)spr[0].createSprite(DWIDTH, DHEIGHT / 2);
 | |
|   sprPtr[1] = (uint16_t*)spr[1].createSprite(DWIDTH, DHEIGHT / 2);
 | |
| 
 | |
|   // Move the sprite 1 coordinate datum upwards half the screen height
 | |
|   // so from coordinate point of view it occupies the bottom of screen
 | |
|   spr[1].setViewport(0, -DHEIGHT / 2, DWIDTH, DHEIGHT);
 | |
| 
 | |
|   // Define text datum for each Sprite
 | |
|   spr[0].setTextDatum(MC_DATUM);
 | |
|   spr[1].setTextDatum(MC_DATUM);
 | |
| 
 | |
|   // Seed the random number generator
 | |
|   randomSeed(analogRead(A0));
 | |
| 
 | |
|   // Initialise circle parameters
 | |
|   for (uint16_t i = 0; i < CNUMBER; i++) {
 | |
|     circle->cr[i] = random(12, 24);
 | |
|     circle->cx[i] = random(circle->cr[i], DWIDTH - circle->cr[i]);
 | |
|     circle->cy[i] = random(circle->cr[i], DHEIGHT - circle->cr[i]);
 | |
|     
 | |
|     circle->col[i] = rainbow(4 * i);
 | |
|     circle->dx[i] = random(1, 5);
 | |
|     if (random(2)) circle->dx[i] = -circle->dx[i];
 | |
|     circle->dy[i] = random(1, 5);
 | |
|     if (random(2)) circle->dy[i] = -circle->dy[i];
 | |
|   }
 | |
| 
 | |
|   tft.startWrite(); // TFT chip select held low permanently
 | |
| 
 | |
|   startMillis = millis();
 | |
| }
 | |
| 
 | |
| // #########################################################################
 | |
| // Loop
 | |
| // #########################################################################
 | |
| void loop() {
 | |
|   drawUpdate(0); // Update top half
 | |
|   drawUpdate(1); // Update bottom half
 | |
| 
 | |
|   // Calculate the fps every <interval> iterations.
 | |
|   counter++;  
 | |
|   if (counter % interval == 0) {
 | |
|     long millisSinceUpdate = millis() - startMillis;
 | |
|     fps = String((interval * 1000.0 / (millisSinceUpdate))) + " fps";
 | |
|     Serial.println(fps);
 | |
|     startMillis = millis();
 | |
|   }
 | |
| }
 | |
| 
 | |
| // #########################################################################
 | |
| // Render circles to sprite 0 or 1 and initiate DMA
 | |
| // #########################################################################
 | |
| void drawUpdate (bool sel) {
 | |
|   spr[sel].fillSprite(TFT_BLACK);
 | |
|   for (uint16_t i = 0; i < CNUMBER; i++) {
 | |
|     // Draw (Note sprite 1 datum was moved, so coordinates do not need to be adjusted
 | |
|     spr[sel].fillCircle(circle->cx[i], circle->cy[i], circle->cr[i], circle->col[i]);
 | |
|     spr[sel].drawCircle(circle->cx[i], circle->cy[i], circle->cr[i], TFT_WHITE);
 | |
|     spr[sel].setTextColor(TFT_BLACK, circle->col[i]);
 | |
|     spr[sel].drawNumber(i + 1, 1 + circle->cx[i], circle->cy[i], 2);
 | |
|   }
 | |
| 
 | |
|   tft.pushImageDMA(0, sel * DHEIGHT / 2, DWIDTH, DHEIGHT / 2, sprPtr[sel]);
 | |
| 
 | |
|   // Update circle positions after bottom half has been drawn
 | |
|   if (sel) {
 | |
|     for (uint16_t i = 0; i < CNUMBER; i++) {
 | |
|       circle->cx[i] += circle->dx[i];
 | |
|       circle->cy[i] += circle->dy[i];
 | |
|       if (circle->cx[i] <= circle->cr[i]) {
 | |
|         circle->cx[i] = circle->cr[i];
 | |
|         circle->dx[i] = -circle->dx[i];
 | |
|       }
 | |
|       else if (circle->cx[i] + circle->cr[i] >= DWIDTH - 1) {
 | |
|         circle->cx[i] = DWIDTH - circle->cr[i] - 1;
 | |
|         circle->dx[i] = -circle->dx[i];
 | |
|       }
 | |
|       if (circle->cy[i] <= circle->cr[i]) {
 | |
|         circle->cy[i] = circle->cr[i];
 | |
|         circle->dy[i] = -circle->dy[i];
 | |
|       }
 | |
|       else if (circle->cy[i] + circle->cr[i] >= DHEIGHT - 1) {
 | |
|         circle->cy[i] = DHEIGHT - circle->cr[i] - 1;
 | |
|         circle->dy[i] = -circle->dy[i];
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| // #########################################################################
 | |
| // Return a 16 bit rainbow colour
 | |
| // #########################################################################
 | |
| uint16_t rainbow(byte value)
 | |
| {
 | |
|   // If 'value' is in the range 0-159 it is converted to a spectrum colour
 | |
|   // from 0 = red through to 127 = blue to 159 = violet
 | |
|   // Extending the range to 0-191 adds a further violet to red band
 | |
| 
 | |
|   value = value % 192;
 | |
| 
 | |
|   byte red   = 0; // Red is the top 5 bits of a 16 bit colour value
 | |
|   byte green = 0; // Green is the middle 6 bits, but only top 5 bits used here
 | |
|   byte blue  = 0; // Blue is the bottom 5 bits
 | |
| 
 | |
|   byte sector = value >> 5;
 | |
|   byte amplit = value & 0x1F;
 | |
| 
 | |
|   switch (sector)
 | |
|   {
 | |
|     case 0:
 | |
|       red   = 0x1F;
 | |
|       green = amplit; // Green ramps up
 | |
|       blue  = 0;
 | |
|       break;
 | |
|     case 1:
 | |
|       red   = 0x1F - amplit; // Red ramps down
 | |
|       green = 0x1F;
 | |
|       blue  = 0;
 | |
|       break;
 | |
|     case 2:
 | |
|       red   = 0;
 | |
|       green = 0x1F;
 | |
|       blue  = amplit; // Blue ramps up
 | |
|       break;
 | |
|     case 3:
 | |
|       red   = 0;
 | |
|       green = 0x1F - amplit; // Green ramps down
 | |
|       blue  = 0x1F;
 | |
|       break;
 | |
|     case 4:
 | |
|       red   = amplit; // Red ramps up
 | |
|       green = 0;
 | |
|       blue  = 0x1F;
 | |
|       break;
 | |
|     case 5:
 | |
|       red   = 0x1F;
 | |
|       green = 0;
 | |
|       blue  = 0x1F - amplit; // Blue ramps down
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   return red << 11 | green << 6 | blue;
 | |
| }
 |