Minor changes
* Fix double buffer example * Remove the I2S user clock config for simplicity - ESP32 turns out to be massively limited anyway to 20Mhz...
This commit is contained in:
parent
58abc5f2fb
commit
3214cd643d
4 changed files with 56 additions and 45 deletions
|
@ -100,11 +100,11 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory()
|
||||||
|
|
||||||
Serial.println(F("DMA memory blocks available before any malloc's: "));
|
Serial.println(F("DMA memory blocks available before any malloc's: "));
|
||||||
heap_caps_print_heap_info(MALLOC_CAP_DMA);
|
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("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("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.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
|
#endif
|
||||||
|
|
||||||
// Can we potentially fit the framebuffer into the DMA capable memory that's available?
|
// Can we potentially fit the framebuffer into the DMA capable memory that's available?
|
||||||
|
@ -180,11 +180,16 @@ 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);
|
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
|
#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
|
// calculate the lowest LSBMSB_TRANSITION_BIT value that will fit in memory that will meet or exceed the configured refresh rate
|
||||||
while(1) {
|
while(1) {
|
||||||
int psPerClock = 1000000000000UL/m_cfg.i2sspeed;
|
int psPerClock = 1000000000000UL/ESP32_I2S_CLOCK_SPEED;
|
||||||
int nsPerLatch = ((PIXELS_PER_ROW + CLKS_DURING_LATCH) * psPerClock) / 1000;
|
int nsPerLatch = ((PIXELS_PER_ROW + CLKS_DURING_LATCH) * psPerClock) / 1000;
|
||||||
|
|
||||||
// add time to shift out LSBs + LSB-MSB transition bit - this ignores fractions...
|
// add time to shift out LSBs + LSB-MSB transition bit - this ignores fractions...
|
||||||
|
@ -200,7 +205,7 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory()
|
||||||
|
|
||||||
#if SERIAL_DEBUG
|
#if SERIAL_DEBUG
|
||||||
Serial.printf_P(PSTR("lsbMsbTransitionBit of %d gives %d Hz refresh: \r\n"), lsbMsbTransitionBit, actualRefreshRate);
|
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
|
if (actualRefreshRate > min_refresh_rate) // HACK Hard Coded: 100
|
||||||
break;
|
break;
|
||||||
|
@ -416,7 +421,7 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
|
||||||
i2s_parallel_config_t 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_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,
|
.gpio_clk=_cfg.gpio.clk,
|
||||||
.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...
|
.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...
|
||||||
.bits=ESP32_I2S_DMA_MODE, //ESP32_I2S_DMA_MODE,
|
.bits=ESP32_I2S_DMA_MODE, //ESP32_I2S_DMA_MODE,
|
||||||
.bufa=0,
|
.bufa=0,
|
||||||
.bufb=0,
|
.bufb=0,
|
||||||
|
|
|
@ -230,11 +230,6 @@ struct HUB75_I2S_CFG {
|
||||||
*/
|
*/
|
||||||
enum shift_driver {SHIFT=0, FM6124, FM6126A, ICN2038S};
|
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
|
// Structure Variables
|
||||||
|
|
||||||
// physical width of a single matrix panel module (in pixels, usually it is 64 ;) )
|
// physical width of a single matrix panel module (in pixels, usually it is 64 ;) )
|
||||||
|
@ -252,8 +247,7 @@ struct HUB75_I2S_CFG {
|
||||||
|
|
||||||
// Matrix driver chip type - default is a plain shift register
|
// Matrix driver chip type - default is a plain shift register
|
||||||
shift_driver driver;
|
shift_driver driver;
|
||||||
// I2S clock speed
|
|
||||||
clk_speed i2sspeed;
|
|
||||||
// use DMA double buffer (twice as much RAM required)
|
// use DMA double buffer (twice as much RAM required)
|
||||||
bool double_buff;
|
bool double_buff;
|
||||||
// How many clock cycles to blank OE before/after LAT signal change, default is 1 clock
|
// How many clock cycles to blank OE before/after LAT signal change, default is 1 clock
|
||||||
|
@ -271,13 +265,12 @@ struct HUB75_I2S_CFG {
|
||||||
LAT_PIN_DEFAULT, OE_PIN_DEFAULT, CLK_PIN_DEFAULT },
|
LAT_PIN_DEFAULT, OE_PIN_DEFAULT, CLK_PIN_DEFAULT },
|
||||||
shift_driver _drv = SHIFT,
|
shift_driver _drv = SHIFT,
|
||||||
bool _dbuff = false,
|
bool _dbuff = false,
|
||||||
clk_speed _i2sspeed = HZ_10M,
|
|
||||||
uint16_t _latblk = 1
|
uint16_t _latblk = 1
|
||||||
) : mx_width(_w),
|
) : mx_width(_w),
|
||||||
mx_height(_h),
|
mx_height(_h),
|
||||||
chain_length(_chain),
|
chain_length(_chain),
|
||||||
gpio(_pinmap),
|
gpio(_pinmap),
|
||||||
driver(_drv), i2sspeed(_i2sspeed),
|
driver(_drv),
|
||||||
double_buff(_dbuff),
|
double_buff(_dbuff),
|
||||||
latch_blanking(_latblk) {}
|
latch_blanking(_latblk) {}
|
||||||
}; // end of structure HUB75_I2S_CFG
|
}; // end of structure HUB75_I2S_CFG
|
||||||
|
|
|
@ -196,12 +196,18 @@ void i2s_parallel_setup_without_malloc(i2s_dev_t *dev, const i2s_parallel_config
|
||||||
else
|
else
|
||||||
dev->sample_rate_conf.tx_bck_div_num=1; // datasheet says this must be 2 or greater (but 1 seems to work)
|
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;
|
dev->clkm_conf.val=0; // Clear the clkm_conf struct
|
||||||
dev->clkm_conf.clka_en=0;
|
dev->clkm_conf.clka_en=0; // Use the 160mhz system clock (PLL_D2_CLK) when '0'
|
||||||
dev->clkm_conf.clkm_div_a=63;
|
dev->clkm_conf.clkm_div_a=1; // Page 310 of Technical Reference Manual - Clock denominator
|
||||||
dev->clkm_conf.clkm_div_b=63;
|
dev->clkm_conf.clkm_div_b=1; // Page 310 of Technical Reference Manual - Clock numerator
|
||||||
//We ignore the possibility for fractional division here, clkspeed_hz must round up for a fractional clock speed, must result in >= 2
|
//We ignore the possibility for fractional division here, clkspeed_hz must round up for a fractional clock speed, must result in >= 2
|
||||||
dev->clkm_conf.clkm_div_num=80000000L/(cfg->clkspeed_hz + 1);
|
|
||||||
|
// 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->fifo_conf.val=0;
|
dev->fifo_conf.val=0;
|
||||||
dev->fifo_conf.rx_fifo_mod_force_en=1;
|
dev->fifo_conf.rx_fifo_mod_force_en=1;
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
* for different resolutions / panel chain lengths within the sketch 'setup()'.
|
* for different resolutions / panel chain lengths within the sketch 'setup()'.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
MatrixPanel_I2S_DMA display(true); // Note the TRUE -> Turns of secondary buffer - "double buffering"!
|
|
||||||
// Double buffering is not enabled by default with the library.
|
MatrixPanel_I2S_DMA *display = nullptr;
|
||||||
|
|
||||||
const byte row0 = 2+0*10;
|
const byte row0 = 2+0*10;
|
||||||
const byte row1 = 2+1*10;
|
const byte row1 = 2+1*10;
|
||||||
|
@ -26,30 +26,37 @@ void setup()
|
||||||
|
|
||||||
Serial.println("...Starting Display");
|
Serial.println("...Starting Display");
|
||||||
|
|
||||||
display.begin(); // setup display with pins as per defined in the library
|
HUB75_I2S_CFG mxconfig;
|
||||||
display.setTextColor(display.color565(128, 128, 128));
|
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));
|
||||||
|
|
||||||
|
|
||||||
// Buffer 0 test
|
// Buffer 0 test
|
||||||
display.fillScreen(display.color565(128, 0, 0));
|
display->fillScreen(display->color565(128, 0, 0));
|
||||||
display.setCursor(3, row0);
|
display->setCursor(3, row0);
|
||||||
display.print(F("Buffer 0"));
|
display->print(F("Buffer 0"));
|
||||||
display.setCursor(3, row1);
|
display->setCursor(3, row1);
|
||||||
display.print(F(" Buffer 0"));
|
display->print(F(" Buffer 0"));
|
||||||
Serial.println("Wrote to to Buffer 0");
|
Serial.println("Wrote to to Buffer 0");
|
||||||
display.showDMABuffer();
|
display->showDMABuffer();
|
||||||
delay(1500);
|
delay(1500);
|
||||||
|
|
||||||
// Buffer 1 test
|
// Buffer 1 test
|
||||||
display.flipDMABuffer();
|
display->flipDMABuffer();
|
||||||
display.fillScreen(display.color565(0, 128, 0)); // shouldn't see this
|
display->fillScreen(display->color565(0, 128, 0)); // shouldn't see this
|
||||||
display.setCursor(3, row0);
|
display->setCursor(3, row0);
|
||||||
display.print(F("Buffer 1"));
|
display->print(F("Buffer 1"));
|
||||||
display.setCursor(3, row2);
|
display->setCursor(3, row2);
|
||||||
display.print(F(" Buffer 1"));
|
display->print(F(" Buffer 1"));
|
||||||
|
|
||||||
Serial.println("Wrote to to Buffer 1");
|
Serial.println("Wrote to to Buffer 1");
|
||||||
display.showDMABuffer();
|
display->showDMABuffer();
|
||||||
delay(1500);
|
delay(1500);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -57,31 +64,31 @@ void setup()
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
||||||
// Flip the back buffer
|
// Flip the back buffer
|
||||||
display.flipDMABuffer();
|
display->flipDMABuffer();
|
||||||
|
|
||||||
// Write: Set bottow row to black
|
// Write: Set bottow row to black
|
||||||
for (int y=20;y<MATRIX_HEIGHT; y++)
|
for (int y=20;y<MATRIX_HEIGHT; y++)
|
||||||
for (int x=0;x<MATRIX_WIDTH; x++)
|
for (int x=0;x<MATRIX_WIDTH; x++)
|
||||||
{
|
{
|
||||||
display.drawPixelRGB888( x, y, 0, 0, 0);
|
display->drawPixelRGB888( x, y, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write: Set bottom row to blue (this is what should show)
|
// Write: Set bottom row to blue (this is what should show)
|
||||||
for (int y=20;y<MATRIX_HEIGHT; y++)
|
for (int y=20;y<MATRIX_HEIGHT; y++)
|
||||||
for (int x=0;x<MATRIX_WIDTH; x++)
|
for (int x=0;x<MATRIX_WIDTH; x++)
|
||||||
{
|
{
|
||||||
display.drawPixelRGB888( x, y, 0, 0, 64);
|
display->drawPixelRGB888( x, y, 0, 0, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now show this back buffer
|
// Now show this back buffer
|
||||||
display.showDMABuffer();
|
display->showDMABuffer();
|
||||||
delay(1000);
|
delay(1000);
|
||||||
|
|
||||||
// Flip back buffer
|
// Flip back buffer
|
||||||
display.flipDMABuffer();
|
display->flipDMABuffer();
|
||||||
|
|
||||||
// Show this buffer
|
// Show this buffer
|
||||||
display.showDMABuffer();
|
display->showDMABuffer();
|
||||||
delay(1000);
|
delay(1000);
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue