aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormrcodetastic <12006953+mrcodetastic@users.noreply.github.com>2024-07-17 23:15:56 +0100
committermrcodetastic <12006953+mrcodetastic@users.noreply.github.com>2024-07-17 23:15:56 +0100
commitcee3dca28c72c4d57f4e741c8d170b2e8a2822c9 (patch)
tree706955af030ad4062c325d19893805d2f45c748b
parente8d92c3ff8215eaee872105984620357577ad693 (diff)
clock speed fixes
-rw-r--r--src/ESP32-HUB75-MatrixPanel-I2S-DMA.h16
-rw-r--r--src/platforms/esp32/esp32_i2s_parallel_dma.cpp116
-rw-r--r--src/platforms/esp32s3/gdma_lcd_parallel16.cpp20
3 files changed, 95 insertions, 57 deletions
diff --git a/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h b/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h
index 675a105..8e113fa 100644
--- a/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h
+++ b/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h
@@ -254,9 +254,10 @@ struct HUB75_I2S_CFG
enum clk_speed
{
HZ_8M = 8000000,
- HZ_10M = 10000000,
- HZ_15M = 15000000,
- HZ_20M = 20000000
+ HZ_10M = 8000000,
+ HZ_15M = 16000000, // for compatability
+ HZ_16M = 16000000,
+ HZ_20M = 16000000 // for compatability
};
//
@@ -318,9 +319,14 @@ struct HUB75_I2S_CFG
R1_PIN_DEFAULT, G1_PIN_DEFAULT, B1_PIN_DEFAULT, R2_PIN_DEFAULT, G2_PIN_DEFAULT, B2_PIN_DEFAULT,
A_PIN_DEFAULT, B_PIN_DEFAULT, C_PIN_DEFAULT, D_PIN_DEFAULT, E_PIN_DEFAULT,
LAT_PIN_DEFAULT, OE_PIN_DEFAULT, CLK_PIN_DEFAULT},
- shift_driver _drv = SHIFTREG, bool _dbuff = false, clk_speed _i2sspeed = HZ_15M,
+ shift_driver _drv = SHIFTREG,
+ bool _dbuff = false,
+ clk_speed _i2sspeed = HZ_8M,
uint8_t _latblk = DEFAULT_LAT_BLANKING, // Anything > 1 seems to cause artefacts on ICS panels
- bool _clockphase = true, uint16_t _min_refresh_rate = 60, uint8_t _pixel_color_depth_bits = PIXEL_COLOR_DEPTH_BITS_DEFAULT) : mx_width(_w), mx_height(_h), chain_length(_chain), gpio(_pinmap), driver(_drv), double_buff(_dbuff), i2sspeed(_i2sspeed), latch_blanking(_latblk), clkphase(_clockphase), min_refresh_rate(_min_refresh_rate)
+ bool _clockphase = true,
+ uint16_t _min_refresh_rate = 60,
+ uint8_t _pixel_color_depth_bits = PIXEL_COLOR_DEPTH_BITS_DEFAULT)
+ : mx_width(_w), mx_height(_h), chain_length(_chain), gpio(_pinmap), driver(_drv), double_buff(_dbuff), i2sspeed(_i2sspeed), latch_blanking(_latblk), clkphase(_clockphase), min_refresh_rate(_min_refresh_rate)
{
setPixelColorDepthBits(_pixel_color_depth_bits);
}
diff --git a/src/platforms/esp32/esp32_i2s_parallel_dma.cpp b/src/platforms/esp32/esp32_i2s_parallel_dma.cpp
index e9d45d3..ed0e6c9 100644
--- a/src/platforms/esp32/esp32_i2s_parallel_dma.cpp
+++ b/src/platforms/esp32/esp32_i2s_parallel_dma.cpp
@@ -47,6 +47,9 @@ Modified heavily for the ESP32 HUB75 DMA library by:
#include <esp_err.h>
#include <esp_log.h>
+// Get current frequecny
+#include "esp_clk_tree.h"
+
// Get CPU freq function.
#include <soc/rtc.h>
@@ -131,9 +134,16 @@ Modified heavily for the ESP32 HUB75 DMA library by:
{
ESP_LOGI("ESP32/S2", "Performing DMA bus init() for ESP32 or ESP32-S2");
+ /*
if(_cfg.parallel_width < 8 || _cfg.parallel_width >= 24) {
return false;
}
+ */
+
+ // Only 16 bit mode used for this library
+ if(_cfg.parallel_width != 16) {
+ return false;
+ }
auto dev = _dev;
volatile int iomux_signal_base;
@@ -209,46 +219,60 @@ Modified heavily for the ESP32 HUB75 DMA library by:
}
////////////////////////////// Clock configuration //////////////////////////////
+ unsigned int freq = (_cfg.bus_freq); // requested freq
+
+ // Setup i2s clock (sample rate)
+ dev->sample_rate_conf.val = 0;
+
+ // Third stage config, width of data to be written to IO (I think this should always be the actual data width?)
+ dev->sample_rate_conf.rx_bits_mod = bus_width;
+ dev->sample_rate_conf.tx_bits_mod = bus_width;
+
+ // Hard-code clock divider for ESP32-S2 to 8Mhz
+ #if defined (CONFIG_IDF_TARGET_ESP32S2)
- unsigned int freq = (_cfg.bus_freq);
- ESP_LOGD("ESP32/S2", "Requested output clock frequency: %u Mhz", (unsigned int)(freq/1000000));
-
- // What is the current CPU frequency?
+ // I2S_CLK_SEL Set this bit to select I2S module clock source.
+ // 0: No clock. 1: APLL_CLK. 2: PLL_160M_CLK. 3: No clock. (R/W)
+ dev->clkm_conf.clk_sel = 2; // 160 Mhz
+
+ dev->clkm_conf.clkm_div_a = 1; // Clock denominator
+ dev->clkm_conf.clkm_div_b = 0; // Clock numerator
- // Calculate clock divider for ESP32-S2
- #if defined (CONFIG_IDF_TARGET_ESP32S2)
-
- // Right shift (>> 1) and divide 160mhz in half to 80Mhz for the calc due to the fact
- // that later we must have tx_bck_div_num = 2 for both esp32 and esp32-s2
+ dev->clkm_conf.clkm_div_num = 5; // 160 / 5 = 32 Mhz ('fi2s')
+ dev->clkm_conf.clk_en = 1;
- //static uint32_t pll_160M_clock_d2 = 160 * 1000 * 1000 >> 1;
+ // Binary clock
+ /*
+ In LCD mode, WS clock frequency is:
+ fWS = fi2s / W ∗ 2
- // I2S_CLKM_DIV_NUM 2=40MHz / 3=27MHz / 4=20MHz / 5=16MHz / 8=10MHz / 10=8MHz
- //auto _div_num = std::min(255u, 1 + ((pll_160M_clock_d2) / (1 + freq)));
- unsigned int _div_num = (unsigned int) (160000000L / freq / i2s_parallel_get_memory_width(ESP32_I2S_DEVICE, 16)); // 16 bits in parallel
-
- if(_div_num < 2 || _div_num > 0xFF) {
- // return ESP_ERR_INVALID_ARG;
- _div_num = 8;
- }
-
-
- ESP_LOGD("ESP32", "i2s pll_160M_clock_d2 clkm_div_num is: %u", _div_num);
+ W is an integer in the range 1 to 64. W corresponds to the value of I2S_TX_BCK_DIV_NUM[5:0] in register
+ I2S_SAMPLE_RATE_CONF_REG as follows.
+ • When I2S_TX_BCK_DIV_NUM[5:0] = 0, W = 64.
+ • When I2S_TX_BCK_DIV_NUM[5:0] is set to other values, W = I2S_TX_BCK_DIV_NUM[5:0
+
+ */
+
+ dev->sample_rate_conf.rx_bck_div_num = 2;
+
+ // ESP32 and ESP32-S2 TRM clearly say that "Note that I2S_TX_BCK_DIV_NUM[5:0] must not be configured as 1."
+ // Testing has revealed that setting it to 1 causes problems.
+ dev->sample_rate_conf.tx_bck_div_num = 2;
+
+ // Output Frequency is now
+ //160 / 5 / (2*2) = 8Mhz
- // I2S_CLK_SEL Set this bit to select I2S module clock source.
- // 0: No clock. 1: APLL_CLK. 2: PLL_160M_CLK. 3: No clock. (R/W)
- dev->clkm_conf.clk_sel = 2;
- dev->clkm_conf.clkm_div_a = 1; // Clock denominator
- dev->clkm_conf.clkm_div_b = 0; // Clock numerator
- dev->clkm_conf.clkm_div_num = _div_num;
- dev->clkm_conf.clk_en = 1;
-
- // Calc
- unsigned int output_freq = (unsigned int)(160000000L/_div_num);
// Calculate clock divider for Original ESP32
#else
+ dev->sample_rate_conf.rx_bck_div_num = 1;
+
+ // ESP32 and ESP32-S2 TRM clearly say that "Note that I2S_TX_BCK_DIV_NUM[5:0] must not be configured as 1."
+ // Testing has revealed that setting it to 1 causes problems.
+ dev->sample_rate_conf.tx_bck_div_num = 1;
+
+
// Note: clkm_div_num must only be set here AFTER clkm_div_b, clkm_div_a, etc. Or weird things happen!
// On original ESP32, max I2S DMA parallel speed is 20Mhz.
@@ -260,42 +284,30 @@ Modified heavily for the ESP32 HUB75 DMA library by:
// I2S_CLKM_DIV_NUM 2=40MHz / 3=27MHz / 4=20MHz / 5=16MHz / 8=10MHz / 10=8MHz
//auto _div_num = std::min(255u, 1 + ((pll_d2_clock) / (1 + freq)));
+ /*
unsigned int _div_num = (unsigned int) (80000000L / freq / i2s_parallel_get_memory_width(ESP32_I2S_DEVICE, 16)); // 16 bits in parallel
if(_div_num < 2 || _div_num > 0xFF) {
// return ESP_ERR_INVALID_ARG;
_div_num = 4;
}
-
- ///auto _div_num = 80000000L/freq;
+ */
+
+ unsigned int _div_num = (freq > 8000000) ? 5:10; // 8 mhz or 16mhz
ESP_LOGD("ESP32", "i2s pll_d2_clock clkm_div_num is: %u", _div_num);
- dev->clkm_conf.clka_en=1; // Use the 80mhz system clock (PLL_D2_CLK) when '0'
+ dev->clkm_conf.clka_en=0; // Use the 80mhz system clock (PLL_D2_CLK) when '0'
dev->clkm_conf.clkm_div_a = 1; // Clock denominator
dev->clkm_conf.clkm_div_b = 0; // Clock numerator
dev->clkm_conf.clkm_div_num = _div_num;
-
- unsigned int output_freq = (unsigned int)(80000000L/_div_num);
+ // dev->clkm_conf.clk_en=1;
+
+ // Note tx_bck_div_num value of 2 will further divide clock rate
#endif
- output_freq = output_freq + 0; // work around arudino 'unused var' issue if debug isn't enabled.
- ESP_LOGI("ESP32/S2", "Output frequency is %u Mhz??", (unsigned int)(output_freq/1000000/i2s_parallel_get_memory_width(ESP32_I2S_DEVICE, 16)));
-
-
- // Setup i2s clock
- dev->sample_rate_conf.val = 0;
-
- // Third stage config, width of data to be written to IO (I think this should always be the actual data width?)
- dev->sample_rate_conf.rx_bits_mod = bus_width;
- dev->sample_rate_conf.tx_bits_mod = bus_width;
-
- // Serial clock
- // ESP32 and ESP32-S2 TRM clearly say that "Note that I2S_TX_BCK_DIV_NUM[5:0] must not be configured as 1."
- dev->sample_rate_conf.rx_bck_div_num = 2;
- dev->sample_rate_conf.tx_bck_div_num = 2;
-
+
////////////////////////////// END CLOCK CONFIGURATION /////////////////////////////////
// I2S conf2 reg
diff --git a/src/platforms/esp32s3/gdma_lcd_parallel16.cpp b/src/platforms/esp32s3/gdma_lcd_parallel16.cpp
index 7bb390d..93969ed 100644
--- a/src/platforms/esp32s3/gdma_lcd_parallel16.cpp
+++ b/src/platforms/esp32s3/gdma_lcd_parallel16.cpp
@@ -58,6 +58,16 @@
return true;
}
+ // LCD end of transaction interrupt
+ static void IRAM_ATTR lcd_isr(void* arg) {
+
+ LCD_CAM.lc_dma_int_clr.lcd_trans_done_int_clr = 1;
+
+ previousBufferFree = true;
+
+ }
+
+
lcd_cam_dev_t* getDev()
{
return &LCD_CAM;
@@ -259,11 +269,21 @@
gdma_set_transfer_ability(dma_chan, &ability);
// Enable DMA transfer callback
+ /*
static gdma_tx_event_callbacks_t tx_cbs = {
// .on_trans_eof is literally the only gdma tx event type available
.on_trans_eof = gdma_on_trans_eof_callback
};
gdma_register_tx_event_callbacks(dma_chan, &tx_cbs, NULL);
+ */
+
+ //
+ // Enable Transaction Done interrupt
+ LCD_CAM.lc_dma_int_ena.lcd_trans_done_int_ena = 1;
+
+ // Allocate a level 1 intterupt: lowest priority, as ISR isn't urgent and may take a long time to complete
+ esp_intr_alloc(ETS_LCD_CAM_INTR_SOURCE, (int)(ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1), lcd_isr, NULL, NULL);
+
// This uses a busy loop to wait for each DMA transfer to complete...