diff --git a/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp b/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp index 5a7bf34..89f24ae 100644 --- a/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp +++ b/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp @@ -100,11 +100,11 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory() Serial.println(F("DMA memory blocks available before any malloc's: ")); heap_caps_print_heap_info(MALLOC_CAP_DMA); - Serial.println(F("******************************************************************")); + Serial.printf_P(PSTR("We're going to need %d bytes of SRAM just for the frame buffer(s).\r\n"), _frame_buffer_memory_required); Serial.printf_P(PSTR("The total amount of DMA capable SRAM memory is %d bytes.\r\n"), heap_caps_get_free_size(MALLOC_CAP_DMA)); Serial.printf_P(PSTR("Largest DMA capable SRAM memory block is %d bytes.\r\n"), heap_caps_get_largest_free_block(MALLOC_CAP_DMA)); - Serial.println(F("******************************************************************")); + #endif // Can we potentially fit the framebuffer into the DMA capable memory that's available? @@ -180,16 +180,11 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory() Serial.printf_P(PSTR("Raised lsbMsbTransitionBit to %d/%d to fit in remaining RAM\r\n"), lsbMsbTransitionBit, PIXEL_COLOR_DEPTH_BITS - 1); - //#define IGNORE_REFRESH_RATE 1 + #ifndef IGNORE_REFRESH_RATE - - #if SERIAL_DEBUG - Serial.printf_P(PSTR("Requested I2S clock / gpio output frequency is %d Mhz\r\n"), ESP32_I2S_CLOCK_SPEED/1000000); - #endif - // calculate the lowest LSBMSB_TRANSITION_BIT value that will fit in memory that will meet or exceed the configured refresh rate while(1) { - int psPerClock = 1000000000000UL/ESP32_I2S_CLOCK_SPEED; + int psPerClock = 1000000000000UL/m_cfg.i2sspeed; int nsPerLatch = ((PIXELS_PER_ROW + CLKS_DURING_LATCH) * psPerClock) / 1000; // add time to shift out LSBs + LSB-MSB transition bit - this ignores fractions... @@ -203,9 +198,9 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory() int actualRefreshRate = 1000000000UL/(nsPerFrame); calculated_refresh_rate = actualRefreshRate; - #if SERIAL_DEBUG + #if SERIAL_DEBUG Serial.printf_P(PSTR("lsbMsbTransitionBit of %d gives %d Hz refresh: \r\n"), lsbMsbTransitionBit, actualRefreshRate); - #endif + #endif if (actualRefreshRate > min_refresh_rate) // HACK Hard Coded: 100 break; @@ -421,7 +416,7 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg) i2s_parallel_config_t cfg={ .gpio_bus={_cfg.gpio.r1, _cfg.gpio.g1, _cfg.gpio.b1, _cfg.gpio.r2, _cfg.gpio.g2, _cfg.gpio.b2, _cfg.gpio.lat, _cfg.gpio.oe, _cfg.gpio.a, _cfg.gpio.b, _cfg.gpio.c, _cfg.gpio.d, _cfg.gpio.e, -1, -1, -1}, .gpio_clk=_cfg.gpio.clk, - .clkspeed_hz=ESP32_I2S_CLOCK_SPEED, //ESP32_I2S_CLOCK_SPEED, formula used is 80000000L/(cfg->clkspeed_hz + 1), must result in >=2. Acceptable values 26.67MHz, 20MHz, 16MHz, 13.34MHz... + .clkspeed_hz=_cfg.i2sspeed, //ESP32_I2S_CLOCK_SPEED, formula used is 80000000L/(cfg->clkspeed_hz + 1), must result in >=2. Acceptable values 26.67MHz, 20MHz, 16MHz, 13.34MHz... .bits=ESP32_I2S_DMA_MODE, //ESP32_I2S_DMA_MODE, .bufa=0, .bufb=0, diff --git a/ESP32-HUB75-MatrixPanel-I2S-DMA.h b/ESP32-HUB75-MatrixPanel-I2S-DMA.h index 57a79fb..e1c1067 100644 --- a/ESP32-HUB75-MatrixPanel-I2S-DMA.h +++ b/ESP32-HUB75-MatrixPanel-I2S-DMA.h @@ -230,6 +230,11 @@ struct HUB75_I2S_CFG { */ enum shift_driver {SHIFT=0, FM6124, FM6126A, ICN2038S}; + /** + * I2S clock speed selector + */ + enum clk_speed {HZ_10M=10000000, HZ_13340K=13340000, HZ_16M=16000000, HZ_20M=20000000, HZ_26670K=26670000}; + // Structure Variables // physical width of a single matrix panel module (in pixels, usually it is 64 ;) ) @@ -247,7 +252,8 @@ struct HUB75_I2S_CFG { // Matrix driver chip type - default is a plain shift register shift_driver driver; - + // I2S clock speed + clk_speed i2sspeed; // use DMA double buffer (twice as much RAM required) bool double_buff; // How many clock cycles to blank OE before/after LAT signal change, default is 1 clock @@ -265,12 +271,13 @@ struct HUB75_I2S_CFG { LAT_PIN_DEFAULT, OE_PIN_DEFAULT, CLK_PIN_DEFAULT }, shift_driver _drv = SHIFT, bool _dbuff = false, + clk_speed _i2sspeed = HZ_10M, uint16_t _latblk = 1 ) : mx_width(_w), mx_height(_h), chain_length(_chain), gpio(_pinmap), - driver(_drv), + driver(_drv), i2sspeed(_i2sspeed), double_buff(_dbuff), latch_blanking(_latblk) {} }; // end of structure HUB75_I2S_CFG diff --git a/esp32_i2s_parallel.c b/esp32_i2s_parallel.c index 58cd7fe..d29b771 100644 --- a/esp32_i2s_parallel.c +++ b/esp32_i2s_parallel.c @@ -196,18 +196,12 @@ void i2s_parallel_setup_without_malloc(i2s_dev_t *dev, const i2s_parallel_config else dev->sample_rate_conf.tx_bck_div_num=1; // datasheet says this must be 2 or greater (but 1 seems to work) - dev->clkm_conf.val=0; // Clear the clkm_conf struct - dev->clkm_conf.clka_en=0; // Use the 160mhz system clock (PLL_D2_CLK) when '0' - dev->clkm_conf.clkm_div_a=1; // Page 310 of Technical Reference Manual - Clock denominator - dev->clkm_conf.clkm_div_b=1; // Page 310 of Technical Reference Manual - Clock numerator + dev->clkm_conf.val=0; + dev->clkm_conf.clka_en=0; + dev->clkm_conf.clkm_div_a=63; + dev->clkm_conf.clkm_div_b=63; //We ignore the possibility for fractional division here, clkspeed_hz must round up for a fractional clock speed, must result in >= 2 - - // It's confusing, but the max output the ESP32 can pump out when using I2S *parallel* output is 20Mhz. - // https://easyvolts.com/2018/08/14/esp32-40msps-oscilloscope-project-is-closed-and-here-is-why/ - // and https://github.com/espressif/esp-idf/issues/2251 - // Igor - "Frequencies above 20MHz do not work in I2S mode." - dev->clkm_conf.clkm_div_num=80000000L/(cfg->clkspeed_hz + 1); // combination of this and tx_bck_div_num - + dev->clkm_conf.clkm_div_num=80000000L/(cfg->clkspeed_hz + 1); dev->fifo_conf.val=0; dev->fifo_conf.rx_fifo_mod_force_en=1; diff --git a/examples/DoubleBufferSwap/DoubleBufferSwap.ino b/examples/DoubleBufferSwap/DoubleBufferSwap.ino index 76e2ea2..81e116d 100644 --- a/examples/DoubleBufferSwap/DoubleBufferSwap.ino +++ b/examples/DoubleBufferSwap/DoubleBufferSwap.ino @@ -10,8 +10,8 @@ * for different resolutions / panel chain lengths within the sketch 'setup()'. * */ - -MatrixPanel_I2S_DMA *display = nullptr; +MatrixPanel_I2S_DMA display(true); // Note the TRUE -> Turns of secondary buffer - "double buffering"! + // Double buffering is not enabled by default with the library. const byte row0 = 2+0*10; const byte row1 = 2+1*10; @@ -26,37 +26,30 @@ void setup() Serial.println("...Starting Display"); - HUB75_I2S_CFG mxconfig; - mxconfig.double_buff = true; // Turn of double buffer - - // OK, now we can create our matrix object - display = new MatrixPanel_I2S_DMA(mxconfig); - - - display->begin(); // setup display with pins as per defined in the library - display->setTextColor(display->color565(255, 255, 255)); + display.begin(); // setup display with pins as per defined in the library + 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")); + 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(); + 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")); + 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(); + display.showDMABuffer(); delay(1500); } @@ -64,31 +57,31 @@ void setup() void loop() { // Flip the back buffer - display->flipDMABuffer(); + display.flipDMABuffer(); // Write: Set bottow row to black for (int y=20;ydrawPixelRGB888( x, y, 0, 0, 0); + display.drawPixelRGB888( x, y, 0, 0, 0); } // Write: Set bottom row to blue (this is what should show) for (int y=20;ydrawPixelRGB888( x, y, 0, 0, 64); + display.drawPixelRGB888( x, y, 0, 0, 64); } // Now show this back buffer - display->showDMABuffer(); + display.showDMABuffer(); delay(1000); // Flip back buffer - display->flipDMABuffer(); + display.flipDMABuffer(); // Show this buffer - display->showDMABuffer(); + display.showDMABuffer(); delay(1000); -} \ No newline at end of file +}