clock speed fixes

This commit is contained in:
mrcodetastic 2024-07-17 23:15:56 +01:00
parent e8d92c3ff8
commit cee3dca28c
3 changed files with 95 additions and 57 deletions

View file

@ -254,9 +254,10 @@ struct HUB75_I2S_CFG
enum clk_speed enum clk_speed
{ {
HZ_8M = 8000000, HZ_8M = 8000000,
HZ_10M = 10000000, HZ_10M = 8000000,
HZ_15M = 15000000, HZ_15M = 16000000, // for compatability
HZ_20M = 20000000 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, 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, A_PIN_DEFAULT, B_PIN_DEFAULT, C_PIN_DEFAULT, D_PIN_DEFAULT, E_PIN_DEFAULT,
LAT_PIN_DEFAULT, OE_PIN_DEFAULT, CLK_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 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); setPixelColorDepthBits(_pixel_color_depth_bits);
} }

View file

@ -47,6 +47,9 @@ Modified heavily for the ESP32 HUB75 DMA library by:
#include <esp_err.h> #include <esp_err.h>
#include <esp_log.h> #include <esp_log.h>
// Get current frequecny
#include "esp_clk_tree.h"
// Get CPU freq function. // Get CPU freq function.
#include <soc/rtc.h> #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"); ESP_LOGI("ESP32/S2", "Performing DMA bus init() for ESP32 or ESP32-S2");
/*
if(_cfg.parallel_width < 8 || _cfg.parallel_width >= 24) { if(_cfg.parallel_width < 8 || _cfg.parallel_width >= 24) {
return false; return false;
} }
*/
// Only 16 bit mode used for this library
if(_cfg.parallel_width != 16) {
return false;
}
auto dev = _dev; auto dev = _dev;
volatile int iomux_signal_base; volatile int iomux_signal_base;
@ -209,46 +219,60 @@ Modified heavily for the ESP32 HUB75 DMA library by:
} }
////////////////////////////// Clock configuration ////////////////////////////// ////////////////////////////// Clock configuration //////////////////////////////
unsigned int freq = (_cfg.bus_freq); // requested freq
unsigned int freq = (_cfg.bus_freq); // Setup i2s clock (sample rate)
ESP_LOGD("ESP32/S2", "Requested output clock frequency: %u Mhz", (unsigned int)(freq/1000000)); dev->sample_rate_conf.val = 0;
// What is the current CPU frequency? // 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)
// Calculate clock divider for ESP32-S2 // I2S_CLK_SEL Set this bit to select I2S module clock source.
#if defined (CONFIG_IDF_TARGET_ESP32S2) // 0: No clock. 1: APLL_CLK. 2: PLL_160M_CLK. 3: No clock. (R/W)
dev->clkm_conf.clk_sel = 2; // 160 Mhz
// 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_a = 1; // Clock denominator
dev->clkm_conf.clkm_div_b = 0; // Clock numerator
//static uint32_t pll_160M_clock_d2 = 160 * 1000 * 1000 >> 1; dev->clkm_conf.clkm_div_num = 5; // 160 / 5 = 32 Mhz ('fi2s')
dev->clkm_conf.clk_en = 1;
// I2S_CLKM_DIV_NUM 2=40MHz / 3=27MHz / 4=20MHz / 5=16MHz / 8=10MHz / 10=8MHz // Binary clock
//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 In LCD mode, WS clock frequency is:
fWS = fi2s / W 2
if(_div_num < 2 || _div_num > 0xFF) {
// return ESP_ERR_INVALID_ARG; 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
_div_num = 8; 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
ESP_LOGD("ESP32", "i2s pll_160M_clock_d2 clkm_div_num is: %u", _div_num); */
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 // Calculate clock divider for Original ESP32
#else #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! // 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. // 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 // 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))); //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 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) { if(_div_num < 2 || _div_num > 0xFF) {
// return ESP_ERR_INVALID_ARG; // return ESP_ERR_INVALID_ARG;
_div_num = 4; _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); 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_a = 1; // Clock denominator
dev->clkm_conf.clkm_div_b = 0; // Clock numerator dev->clkm_conf.clkm_div_b = 0; // Clock numerator
dev->clkm_conf.clkm_div_num = _div_num; dev->clkm_conf.clkm_div_num = _div_num;
// dev->clkm_conf.clk_en=1;
unsigned int output_freq = (unsigned int)(80000000L/_div_num);
// Note tx_bck_div_num value of 2 will further divide clock rate
#endif #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 ///////////////////////////////// ////////////////////////////// END CLOCK CONFIGURATION /////////////////////////////////
// I2S conf2 reg // I2S conf2 reg

View file

@ -58,6 +58,16 @@
return true; 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() lcd_cam_dev_t* getDev()
{ {
return &LCD_CAM; return &LCD_CAM;
@ -259,11 +269,21 @@
gdma_set_transfer_ability(dma_chan, &ability); gdma_set_transfer_ability(dma_chan, &ability);
// Enable DMA transfer callback // Enable DMA transfer callback
/*
static gdma_tx_event_callbacks_t tx_cbs = { static gdma_tx_event_callbacks_t tx_cbs = {
// .on_trans_eof is literally the only gdma tx event type available // .on_trans_eof is literally the only gdma tx event type available
.on_trans_eof = gdma_on_trans_eof_callback .on_trans_eof = gdma_on_trans_eof_callback
}; };
gdma_register_tx_event_callbacks(dma_chan, &tx_cbs, NULL); 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... // This uses a busy loop to wait for each DMA transfer to complete...