From dd15dabf166bf5698c643a8d8e6e6081b09163c2 Mon Sep 17 00:00:00 2001 From: mrfaptastic <12006953+mrfaptastic@users.noreply.github.com> Date: Thu, 17 Nov 2022 00:45:40 +0000 Subject: [PATCH] PSRAM works now on ESP32-S3 But it's pointless to use as the throughput can only be about 10Mhz. --- src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp | 36 +++++++++++++++++++ src/ESP32-HUB75-MatrixPanel-I2S-DMA.h | 10 ++++-- src/platforms/esp32s3/gdma_lcd_parallel16.cpp | 32 +++++++++++++---- src/platforms/esp32s3/gdma_lcd_parallel16.hpp | 3 +- src/platforms/platform_detect.hpp | 8 +++++ 5 files changed, 78 insertions(+), 11 deletions(-) diff --git a/src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp b/src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp index 7d6b898..fd7ae93 100644 --- a/src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp +++ b/src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp @@ -1,5 +1,11 @@ #include "ESP32-HUB75-MatrixPanel-I2S-DMA.h" +#if defined(SPIRAM_DMA_BUFFER) + // Sprite_TM saves the day again... + // https://www.esp32.com/viewtopic.php?f=2&t=30584 + #include "rom/cache.h" +#endif + static const char* TAG = "MatrixPanel"; /* This replicates same function in rowBitStruct, but due to induced inlining it might be MUCH faster @@ -249,6 +255,10 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg) bus_cfg.pin_d14 = -1; bus_cfg.pin_d15 = -1; + #if defined(SPIRAM_DMA_BUFFER) + bus_cfg.psram_clk_hack = true; + #endif + dma_bus.config(bus_cfg); dma_bus.init(); @@ -368,6 +378,10 @@ void IRAM_ATTR MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint16_t x_coord, uint p[x_coord] &= _colourbitclear; // reset RGB bits p[x_coord] |= RGB_output_bits; // set new RGB bits + #if defined(SPIRAM_DMA_BUFFER) + Cache_WriteBack_Addr((uint32_t)&p[x_coord], sizeof(ESP32_I2S_DMA_STORAGE_TYPE)) ; + #endif + } while(colour_depth_idx); // end of colour depth loop (8) } // updateMatrixDMABuffer (specific co-ords change) @@ -424,6 +438,12 @@ void MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t green, uint --x_coord; p[x_coord] &= BITMASK_RGB12_CLEAR; // reset colour bits p[x_coord] |= RGB_output_bits; // set new colour bits + + + #if defined(SPIRAM_DMA_BUFFER) + Cache_WriteBack_Addr((uint32_t)&p[x_coord], sizeof(ESP32_I2S_DMA_STORAGE_TYPE)) ; + #endif + } while(x_coord); } while(matrix_frame_parallel_row); // end row iteration @@ -557,6 +577,13 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id){ } while(colouridx); + + + #if defined(SPIRAM_DMA_BUFFER) + Cache_WriteBack_Addr((uint32_t)row, sizeof(ESP32_I2S_DMA_STORAGE_TYPE) * ((dma_buff.rowBits[row_idx]->width * dma_buff.rowBits[row_idx]->colour_depth)-1)) ; + #endif + + } while(row_idx); } @@ -630,6 +657,7 @@ void MatrixPanel_I2S_DMA::brtCtrlOE(int brt, const bool _buff_id){ */ row[ESP32_TX_FIFO_POSITION_ADJUST(0 + _blank)] |= BIT_OE; + //row[0 + _blank] |= BIT_OE; @@ -638,6 +666,14 @@ void MatrixPanel_I2S_DMA::brtCtrlOE(int brt, const bool _buff_id){ } while (_blank); } while(colouridx); + + // switch pointer to a row for a specific color index + #if defined(SPIRAM_DMA_BUFFER) + ESP32_I2S_DMA_STORAGE_TYPE* row_hack = dma_buff.rowBits[row_idx]->getDataPtr(colouridx, _buff_id); + Cache_WriteBack_Addr((uint32_t)row_hack, sizeof(ESP32_I2S_DMA_STORAGE_TYPE) * ((dma_buff.rowBits[row_idx]->width * dma_buff.rowBits[row_idx]->colour_depth)-1)) ; + #endif + + } while(row_idx); } diff --git a/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h b/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h index f8eb043..a18b6bb 100644 --- a/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h +++ b/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h @@ -142,9 +142,12 @@ struct rowBitStruct { // constructor - allocates DMA-capable memory to hold the struct data rowBitStruct(const size_t _width, const uint8_t _depth, const bool _dbuff) : width(_width), colour_depth(_depth), double_buff(_dbuff) { -#if defined(SPIRAM_FRAMEBUFFER) && defined (CONFIG_IDF_TARGET_ESP32S3) - #pragma message "Enabling PSRAM / SPIRAM for frame buffer." - data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_malloc( size()+size()*double_buff, MALLOC_CAP_SPIRAM); +//#if defined(SPIRAM_FRAMEBUFFER) && defined (CONFIG_IDF_TARGET_ESP32S3) + #if defined(SPIRAM_DMA_BUFFER) + // #pragma message "Enabling PSRAM / SPIRAM for frame buffer." + // ESP_LOGI("rowBitStruct", "Allocated DMA BitBuffer from PSRAM (SPIRAM)"); + //data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_malloc( size()+size()*double_buff, MALLOC_CAP_SPIRAM); + data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_aligned_alloc(64, size()+size()*double_buff, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); /* if (!psramFound()) { @@ -153,6 +156,7 @@ struct rowBitStruct { */ #else data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_malloc( size()+size()*double_buff, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + // ESP_LOGI("rowBitStruct", "Allocated DMA BitBuffer from regular (and limited) SRAM"); #endif } diff --git a/src/platforms/esp32s3/gdma_lcd_parallel16.cpp b/src/platforms/esp32s3/gdma_lcd_parallel16.cpp index ce41404..d9460e2 100644 --- a/src/platforms/esp32s3/gdma_lcd_parallel16.cpp +++ b/src/platforms/esp32s3/gdma_lcd_parallel16.cpp @@ -79,9 +79,12 @@ LCD_CAM.lcd_user.lcd_reset = 1; esp_rom_delay_us(100); - uint32_t lcd_clkm_div_num = ((160000000 + 1) / _cfg.bus_freq) / 2; +// uint32_t lcd_clkm_div_num = ((160000000 + 1) / _cfg.bus_freq); + ESP_LOGI(TAG, "Cpu frequecny is %d", getCpuFrequencyMhz()); - ESP_LOGI(TAG, "Clock divider is %d", lcd_clkm_div_num); + uint32_t lcd_clkm_div_num = ( ((getCpuFrequencyMhz()*1000000)+1) / _cfg.bus_freq ) / 4; + + //ESP_LOGI(TAG, "Clock divider is %d", lcd_clkm_div_num); // Configure LCD clock. Since this program generates human-perceptible // output and not data for LED matrices or NeoPixels, use almost the @@ -90,12 +93,27 @@ // is applied (250*64), yielding 2,500 Hz. Still much too fast for // human eyes, so later we set up the data to repeat each output byte // many times over. - LCD_CAM.lcd_clock.clk_en = 1; // Enable peripheral clock - LCD_CAM.lcd_clock.lcd_clk_sel = 2; // 160mhz source + //LCD_CAM.lcd_clock.clk_en = 0; // Enable peripheral clock + + // LCD_CAM_LCD_CLK_SEL Select LCD module source clock. 0: clock source is disabled. 1: XTAL_CLK. 2: PLL_D2_CLK. 3: PLL_F160M_CLK. (R/W) + LCD_CAM.lcd_clock.lcd_clk_sel = 2; LCD_CAM.lcd_clock.lcd_ck_out_edge = 0; // PCLK low in 1st half cycle LCD_CAM.lcd_clock.lcd_ck_idle_edge = 0; // PCLK low idle LCD_CAM.lcd_clock.lcd_clk_equ_sysclk = 0; // PCLK = CLK / (CLKCNT_N+1) - LCD_CAM.lcd_clock.lcd_clkm_div_num = lcd_clkm_div_num; // 1st stage 1:250 divide + + + if (_cfg.psram_clk_hack) // fastest speed I can get PSRAM to work before nothing shows + { + LCD_CAM.lcd_clock.lcd_clkm_div_num = 4; + } + else + { + //LCD_CAM.lcd_clock.lcd_clkm_div_num = lcd_clkm_div_num; + LCD_CAM.lcd_clock.lcd_clkm_div_num = 3; + } + ESP_LOGI(TAG, "Clock divider is %d", LCD_CAM.lcd_clock.lcd_clkm_div_num); + + LCD_CAM.lcd_clock.lcd_clkm_div_a = 1; // 0/1 fractional divide LCD_CAM.lcd_clock.lcd_clkm_div_b = 0; @@ -194,8 +212,8 @@ gdma_apply_strategy(dma_chan, &strategy_config); gdma_transfer_ability_t ability = { - .sram_trans_align = 0, - .psram_trans_align = 0, + .sram_trans_align = 4, + .psram_trans_align = 64, }; gdma_set_transfer_ability(dma_chan, &ability); diff --git a/src/platforms/esp32s3/gdma_lcd_parallel16.hpp b/src/platforms/esp32s3/gdma_lcd_parallel16.hpp index ac1880b..b5ef76b 100644 --- a/src/platforms/esp32s3/gdma_lcd_parallel16.hpp +++ b/src/platforms/esp32s3/gdma_lcd_parallel16.hpp @@ -101,11 +101,12 @@ //int port = 0; // max 40MHz (when in 16 bit / 2 byte mode) - uint32_t bus_freq = 20000000; + uint32_t bus_freq = 10000000; int8_t pin_wr = -1; int8_t pin_rd = -1; int8_t pin_rs = -1; // D/C bool invert_pclk = false; + bool psram_clk_hack = false; union { int8_t pin_data[16]; diff --git a/src/platforms/platform_detect.hpp b/src/platforms/platform_detect.hpp index 0adb2be..3ae7f86 100644 --- a/src/platforms/platform_detect.hpp +++ b/src/platforms/platform_detect.hpp @@ -39,6 +39,14 @@ Modified heavily for the ESP32 HUB75 DMA library by: #include "esp32s3/gdma_lcd_parallel16.hpp" #include "esp32s3/esp32s3-default-pins.hpp" + #if defined(SPIRAM_FRAMEBUFFER) && defined (CONFIG_IDF_TARGET_ESP32S3) + #pragma message "Enabling use of PSRAM/SPIRAM based DMA Buffer" + #define SPIRAM_DMA_BUFFER 1 + + // Disable fast functions because I don't understand the interaction with DMA PSRAM and the CPU->DMA->SPIRAM Cache implications.. + #define NO_FAST_FUNCTIONS 1 + #endif + #elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32H2) #error "ESP32 RISC-V devices do not have an LCD interface and are therefore not supported by this library."