From 5f8388eac9191ae359e746582282b8976429f1b8 Mon Sep 17 00:00:00 2001 From: mrfaptastic Date: Sat, 12 Jan 2019 17:20:49 +0000 Subject: [PATCH] Added double buffering / back buffer example Current implementation simply write to the active DMA buffer, but you might want to use both buffers and do off-screen writes. --- ESP32-RGB64x32MatrixPanel-I2S-DMA.cpp | 37 ++---- ESP32-RGB64x32MatrixPanel-I2S-DMA.h | 74 +++++++----- .../Buffer_Swap_Test/Buffer_Swap_Test.ino | 110 ++++++++++++++++++ 3 files changed, 166 insertions(+), 55 deletions(-) create mode 100644 examples/Buffer_Swap_Test/Buffer_Swap_Test.ino diff --git a/ESP32-RGB64x32MatrixPanel-I2S-DMA.cpp b/ESP32-RGB64x32MatrixPanel-I2S-DMA.cpp index a9e53e8..34b286d 100644 --- a/ESP32-RGB64x32MatrixPanel-I2S-DMA.cpp +++ b/ESP32-RGB64x32MatrixPanel-I2S-DMA.cpp @@ -199,7 +199,7 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t return; } - // What half of the HUB75 panel are we painting too? + // What half of the HUB75 panel are we painting to? bool paint_top_half = true; if ( y_coord > ROWS_PER_FRAME-1) // co-ords start at zero, y_coord = 15 = 16 (rows per frame) { @@ -257,7 +257,7 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t * Need to be smart and check the DMA buffer to see what the other half thinks (pun intended) * and persist this when we refresh. * - * The DMA buffer order has also been reversed (fer to the last code in this function) + * The DMA buffer order has also been reversed (refer to the last code in this function) * so we have to check for this and check the correct position of the MATRIX_DATA_STORAGE_TYPE * data. */ @@ -323,20 +323,13 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t } // end reordering } // color depth loop (8) - - - - //Show our work! - if (immediateUpdate) - refreshDMAOutput(); - //i2s_parallel_flip_to_buffer(&I2S1, backbuf_id); - /* + //Show our work! + //i2s_parallel_flip_to_buffer(&I2S1, backbuf_id); + + // If we've linked the DMA output to the same backbuf_id that this function is + // currently writing too, then the output will be immediate. Else: flipDMABuffer(), then showDMABuffer() - // There's no reason you'd want to do this in the draw pixel routine. - if (autoBackBufferFlip) - swapBuffer(); - */ } // updateDMABuffer @@ -424,23 +417,13 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t gre } // colour depth loop (8) } // end row iteration - - if (immediateUpdate) - refreshDMAOutput(); - //i2s_parallel_flip_to_buffer(&I2S1, backbuf_id); - - /* - - // There's no reason you'd want to do this here either to be honest - if (autoBackBufferFlip) - swapBuffer(); - */ + //Show our work! //i2s_parallel_flip_to_buffer(&I2S1, backbuf_id); - - //swapBuffer(); + // If we've linked the DMA output to the same backbuf_id that this function is + // currently writing too, then the output will be immediate. Else: flipDMABuffer(), then showDMABuffer() } // updateDMABuffer diff --git a/ESP32-RGB64x32MatrixPanel-I2S-DMA.h b/ESP32-RGB64x32MatrixPanel-I2S-DMA.h index 7f66870..74cfc46 100644 --- a/ESP32-RGB64x32MatrixPanel-I2S-DMA.h +++ b/ESP32-RGB64x32MatrixPanel-I2S-DMA.h @@ -11,6 +11,8 @@ #include "Adafruit_GFX.h" +#define SERIAL_DEBUG_OUTPUT 1 + /* This is example code to driver a p3(2121)64*32 -style RGB LED display. These types of displays do not have memory and need to be refreshed @@ -88,10 +90,10 @@ #define B2_PIN_DEFAULT 13 #define A_PIN_DEFAULT 23 -#define B_PIN_DEFAULT 22 +#define B_PIN_DEFAULT 19 #define C_PIN_DEFAULT 5 #define D_PIN_DEFAULT 17 -#define E_PIN_DEFAULT -1 +#define E_PIN_DEFAULT -1 // Change to a valid pin if using a 64 pixel row panel. #define LAT_PIN_DEFAULT 4 #define OE_PIN_DEFAULT 15 @@ -175,11 +177,11 @@ typedef struct rgb_24 { class RGB64x32MatrixPanel_I2S_DMA : public Adafruit_GFX { // ------- PUBLIC ------- public: - RGB64x32MatrixPanel_I2S_DMA(bool _immediateUpdate = true, bool _autoBackBufferFlip = false) // Refer to commentary in the private: section - : Adafruit_GFX(MATRIX_WIDTH, MATRIX_HEIGHT), immediateUpdate(_immediateUpdate), autoBackBufferFlip(_autoBackBufferFlip) { + RGB64x32MatrixPanel_I2S_DMA(bool _doubleBuffer = false) // Double buffer is disabled by default. Any change will display next active DMA buffer output (very quickly). NOTE: Not Implemented + : Adafruit_GFX(MATRIX_WIDTH, MATRIX_HEIGHT), doubleBuffer(_doubleBuffer) { backbuf_id = 0; - brightness = 32; // default to max brightness, wear sunglasses when looking directly at panel. + brightness = 64; // default to max brightness, wear sunglasses when looking directly at panel. } @@ -190,10 +192,10 @@ class RGB64x32MatrixPanel_I2S_DMA : public Adafruit_GFX { /* As DMA buffers are dynamically allocated, we must allocated in begin() * Ref: https://github.com/espressif/arduino-esp32/issues/831 */ - allocateDMAbuffers(); + allocateDMAbuffers(); // Change 'if' to '1' to enable, 0 to not include this Serial output in compiled program -#if 1 +#if SERIAL_DEBUG_OUTPUT Serial.printf("Using pin %d for the R1_PIN\n", dma_r1_pin); Serial.printf("Using pin %d for the G1_PIN\n", dma_g1_pin); Serial.printf("Using pin %d for the B1_PIN\n", dma_b1_pin); @@ -210,13 +212,19 @@ class RGB64x32MatrixPanel_I2S_DMA : public Adafruit_GFX { Serial.printf("Using pin %d for the OE_PIN\n", dma_oe_pin); Serial.printf("Using pin %d for the CLK_PIN\n", dma_clk_pin); #endif - + + + // Flush the DMA buffers prior to configuring DMA - Avoid visual artefacts on boot. + flushDMAbuffer(); + flipDMABuffer(); // flip to backbuffer 1 + flushDMAbuffer(); + flipDMABuffer(); // backbuffer 0 + + // Setup the ESP32 DMA Engine. Sprite_TM built this stuff. configureDMA(dma_r1_pin, dma_g1_pin, dma_b1_pin, dma_r2_pin, dma_g2_pin, dma_b2_pin, dma_a_pin, dma_b_pin, dma_c_pin, dma_d_pin, dma_e_pin, dma_lat_pin, dma_oe_pin, dma_clk_pin ); //DMA and I2S configuration and setup - flushDMAbuffer(); - swapBuffer(); - flushDMAbuffer(); - swapBuffer(); + showDMABuffer(); // show 0 + } // TODO: Disable/Enable auto buffer flipping (useful for lots of drawPixel usage)... @@ -241,15 +249,27 @@ class RGB64x32MatrixPanel_I2S_DMA : public Adafruit_GFX { // Converts RGB888 to RGB565 uint16_t color565(uint8_t r, uint8_t g, uint8_t b); // This is what is used by Adafruit GFX! - void swapBuffer() { - backbuf_id ^=1; + void flipDMABuffer() + { + // Step 1. Bring backbuffer to the foreground (i.e. show it) + //showDMABuffer(); + + // Step 2. Copy foreground to backbuffer + //matrixUpdateFrames[backbuf_id ^ 1] = matrixUpdateFrames[backbuf_id]; // copy currently being displayed buffer to backbuffer + + // Step 3. Change to this new buffer as the backbuffer + backbuf_id ^=1; // set this now to the back_buffer to update (not displayed yet though) + +#if SERIAL_DEBUG_OUTPUT + Serial.printf("Set back buffer to: %d\n", backbuf_id); +#endif } - void refreshDMAOutput() + void showDMABuffer() { i2s_parallel_flip_to_buffer(&I2S1, backbuf_id); } - + void setBrightness(int _brightness) { // Change to set the brightness of the display, range of 1 to matrixWidth (i.e. 1 - 64) @@ -269,7 +289,7 @@ class RGB64x32MatrixPanel_I2S_DMA : public Adafruit_GFX { void flushDMAbuffer() { - Serial.printf("Flushing buffer %d", backbuf_id); + Serial.printf("Flushing buffer %d\n", backbuf_id); // Need to wipe the contents of the matrix buffers or weird things happen. for (int y=0;y + +RGB64x32MatrixPanel_I2S_DMA display; // RGB Panel + +const byte row0 = 2+0*10; +const byte row1 = 2+1*10; +const byte row2 = 2+2*10; + + +void setup() +{ + + // put your setup code here, to run once: + delay(1000); Serial.begin(115200); delay(200); + + Serial.println("...Starting Display"); + display.begin(); // setup the display with no double buffering + display.setTextColor(display.color565(128, 128, 128)); + + + // Buffer 0 test + display.fillScreen(display.color565(128, 0, 0)); + display.setCursor(3, row0); + display.print(F("Buffer 0")); + display.setCursor(3, row1); + display.print(F(" Buffer 0")); + Serial.println("Wrote to to Buffer 0"); + display.showDMABuffer(); + delay(1500); + + // Buffer 1 test + display.flipDMABuffer(); + display.fillScreen(display.color565(0, 128, 0)); // shouldn't see this + display.setCursor(3, row0); + display.print(F("Buffer 1")); + display.setCursor(3, row2); + display.print(F(" Buffer 1")); + + Serial.println("Wrote to to Buffer 1"); + display.showDMABuffer(); + delay(1500); + /* + delay(500); + display.fillScreen(display.color565(0, 0, 128)); + delay(1000); + display.flipDMABuffer(); + delay(1000); + + display.flipDMABuffer(); + */ + +} + +void loop() { + + // Flip the back buffer + display.flipDMABuffer(); + + // Write: Set bottow row to black + for (int y=20;y