PSRAM works now on ESP32-S3
But it's pointless to use as the throughput can only be about 10Mhz.
This commit is contained in:
parent
f47b7f5723
commit
dd15dabf16
5 changed files with 78 additions and 11 deletions
|
@ -1,5 +1,11 @@
|
||||||
#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h"
|
#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";
|
static const char* TAG = "MatrixPanel";
|
||||||
|
|
||||||
/* This replicates same function in rowBitStruct, but due to induced inlining it might be MUCH faster
|
/* 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_d14 = -1;
|
||||||
bus_cfg.pin_d15 = -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.config(bus_cfg);
|
||||||
|
|
||||||
dma_bus.init();
|
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] &= _colourbitclear; // reset RGB bits
|
||||||
p[x_coord] |= RGB_output_bits; // set new 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)
|
} while(colour_depth_idx); // end of colour depth loop (8)
|
||||||
} // updateMatrixDMABuffer (specific co-ords change)
|
} // updateMatrixDMABuffer (specific co-ords change)
|
||||||
|
|
||||||
|
@ -424,6 +438,12 @@ void MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t green, uint
|
||||||
--x_coord;
|
--x_coord;
|
||||||
p[x_coord] &= BITMASK_RGB12_CLEAR; // reset colour bits
|
p[x_coord] &= BITMASK_RGB12_CLEAR; // reset colour bits
|
||||||
p[x_coord] |= RGB_output_bits; // set new 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(x_coord);
|
||||||
|
|
||||||
} while(matrix_frame_parallel_row); // end row iteration
|
} while(matrix_frame_parallel_row); // end row iteration
|
||||||
|
@ -557,6 +577,13 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id){
|
||||||
|
|
||||||
} while(colouridx);
|
} 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);
|
} while(row_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,12 +659,21 @@ void MatrixPanel_I2S_DMA::brtCtrlOE(int brt, const bool _buff_id){
|
||||||
row[ESP32_TX_FIFO_POSITION_ADJUST(0 + _blank)] |= BIT_OE;
|
row[ESP32_TX_FIFO_POSITION_ADJUST(0 + _blank)] |= BIT_OE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//row[0 + _blank] |= BIT_OE;
|
//row[0 + _blank] |= BIT_OE;
|
||||||
// no need, has been done already
|
// no need, has been done already
|
||||||
//row[dma_buff.rowBits[row_idx]->width - _blank - 3 ] |= BIT_OE; // (LAT pulse is (width-2) -1 pixel to compensate array index starting at 0
|
//row[dma_buff.rowBits[row_idx]->width - _blank - 3 ] |= BIT_OE; // (LAT pulse is (width-2) -1 pixel to compensate array index starting at 0
|
||||||
} while (_blank);
|
} while (_blank);
|
||||||
|
|
||||||
} while(colouridx);
|
} 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);
|
} while(row_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,9 +142,12 @@ struct rowBitStruct {
|
||||||
// constructor - allocates DMA-capable memory to hold the struct data
|
// 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) {
|
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)
|
//#if defined(SPIRAM_FRAMEBUFFER) && defined (CONFIG_IDF_TARGET_ESP32S3)
|
||||||
#pragma message "Enabling PSRAM / SPIRAM for frame buffer."
|
#if defined(SPIRAM_DMA_BUFFER)
|
||||||
data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_malloc( size()+size()*double_buff, MALLOC_CAP_SPIRAM);
|
// #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())
|
if (!psramFound())
|
||||||
{
|
{
|
||||||
|
@ -153,6 +156,7 @@ struct rowBitStruct {
|
||||||
*/
|
*/
|
||||||
#else
|
#else
|
||||||
data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_malloc( size()+size()*double_buff, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
|
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
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,9 +79,12 @@
|
||||||
LCD_CAM.lcd_user.lcd_reset = 1;
|
LCD_CAM.lcd_user.lcd_reset = 1;
|
||||||
esp_rom_delay_us(100);
|
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
|
// Configure LCD clock. Since this program generates human-perceptible
|
||||||
// output and not data for LED matrices or NeoPixels, use almost the
|
// 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
|
// 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
|
// human eyes, so later we set up the data to repeat each output byte
|
||||||
// many times over.
|
// many times over.
|
||||||
LCD_CAM.lcd_clock.clk_en = 1; // Enable peripheral clock
|
//LCD_CAM.lcd_clock.clk_en = 0; // Enable peripheral clock
|
||||||
LCD_CAM.lcd_clock.lcd_clk_sel = 2; // 160mhz source
|
|
||||||
|
// 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_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_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_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_a = 1; // 0/1 fractional divide
|
||||||
LCD_CAM.lcd_clock.lcd_clkm_div_b = 0;
|
LCD_CAM.lcd_clock.lcd_clkm_div_b = 0;
|
||||||
|
|
||||||
|
@ -194,8 +212,8 @@
|
||||||
gdma_apply_strategy(dma_chan, &strategy_config);
|
gdma_apply_strategy(dma_chan, &strategy_config);
|
||||||
|
|
||||||
gdma_transfer_ability_t ability = {
|
gdma_transfer_ability_t ability = {
|
||||||
.sram_trans_align = 0,
|
.sram_trans_align = 4,
|
||||||
.psram_trans_align = 0,
|
.psram_trans_align = 64,
|
||||||
};
|
};
|
||||||
gdma_set_transfer_ability(dma_chan, &ability);
|
gdma_set_transfer_ability(dma_chan, &ability);
|
||||||
|
|
||||||
|
|
|
@ -101,11 +101,12 @@
|
||||||
//int port = 0;
|
//int port = 0;
|
||||||
|
|
||||||
// max 40MHz (when in 16 bit / 2 byte mode)
|
// 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_wr = -1;
|
||||||
int8_t pin_rd = -1;
|
int8_t pin_rd = -1;
|
||||||
int8_t pin_rs = -1; // D/C
|
int8_t pin_rs = -1; // D/C
|
||||||
bool invert_pclk = false;
|
bool invert_pclk = false;
|
||||||
|
bool psram_clk_hack = false;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
int8_t pin_data[16];
|
int8_t pin_data[16];
|
||||||
|
|
|
@ -39,6 +39,14 @@ Modified heavily for the ESP32 HUB75 DMA library by:
|
||||||
#include "esp32s3/gdma_lcd_parallel16.hpp"
|
#include "esp32s3/gdma_lcd_parallel16.hpp"
|
||||||
#include "esp32s3/esp32s3-default-pins.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)
|
#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."
|
#error "ESP32 RISC-V devices do not have an LCD interface and are therefore not supported by this library."
|
||||||
|
|
Loading…
Reference in a new issue