Merge pull request #657 from mrcodetastic/dev

Better align clocks across SoCs
This commit is contained in:
mrcodetastic 2024-07-22 00:21:52 +01:00 committed by GitHub
commit 1cccb7f3a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 33 additions and 61 deletions

View file

@ -47,9 +47,6 @@ 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>
@ -238,8 +235,8 @@ Modified heavily for the ESP32 HUB75 DMA library by:
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
unsigned int _div_num = (freq > 8000000) ? 3:5; // 8 mhz or 13mhz (eventual output after factoring in tx_bck_div_num) // Output Frequency = (160Mhz / clkm_div_num) / (tx_bck_div_num*2)
// Divider of 2 works theoretically with SRAM (22mhz output rate!) unsigned int _div_num = (freq > 8000000) ? 2:4; // 20 mhz or 10mhz
/* /*
Page 675 of ESP-S2 TRM. Page 675 of ESP-S2 TRM.
@ -276,7 +273,7 @@ Modified heavily for the ESP32 HUB75 DMA library by:
dev->sample_rate_conf.rx_bck_div_num = 2; 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." // 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. // Testing has revealed that setting it to 1 causes problems on S2.
dev->sample_rate_conf.tx_bck_div_num = 2; dev->sample_rate_conf.tx_bck_div_num = 2;
// Output Frequency is now // Output Frequency is now
@ -286,48 +283,29 @@ Modified heavily for the ESP32 HUB75 DMA library by:
// 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!
// On original ESP32, max I2S DMA parallel speed is 20Mhz.
// 160Mhz is only assured when the CPU clock is 240Mhz on the ESP32...
// [esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
//static uint32_t pll_d2_clock = (source_freq/2) * 1000 * 1000 >> 1;
// 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 The clock configuration of the LCD master transmitting mode is identical to I2S clock configuration.
if(_div_num < 2 || _div_num > 0xFF) { In the LCD mode, the frequency of WS is half of f-bck
// return ESP_ERR_INVALID_ARG;
_div_num = 4;
}
*/ */
unsigned int _div_num = (freq > 8000000) ? 5:10; // 8 mhz or 16mhz // 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.tx_bck_div_num = 2;
dev->sample_rate_conf.rx_bck_div_num = 2;
ESP_LOGD("ESP32", "i2s pll_d2_clock clkm_div_num is: %u", _div_num); dev->clkm_conf.clka_en = 0; // 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
unsigned int _div_num = (freq > 8000000) ? 2:4; // 20 mhz or 10mhz
ESP_LOGD("ESP32", "i2s pll_d2_clock clkm_div_num is: %u", _div_num);
// Frequency will be (80Mhz / clkm_div_num / tx_bck_div_num (2))
dev->clkm_conf.clkm_div_num = _div_num; dev->clkm_conf.clkm_div_num = _div_num;
// dev->clkm_conf.clk_en=1;
// Note tx_bck_div_num value of 2 will further divide clock rate // Note tx_bck_div_num value of 2 will further divide clock rate
#endif #endif
////////////////////////////// END CLOCK CONFIGURATION ///////////////////////////////// ////////////////////////////// END CLOCK CONFIGURATION /////////////////////////////////
// I2S conf2 reg // I2S conf2 reg

View file

@ -1,7 +1,10 @@
#include "dma_parallel_io.hpp" #include "dma_parallel_io.hpp"
#include <Arduino.h>
#ifdef CONFIG_IDF_TARGET_ESP32C6 #ifdef CONFIG_IDF_TARGET_ESP32C6
#pragma message "Compiling for ESP32-C6"
//First implementation might have a lot of bugs, especially on deleting and reloading //First implementation might have a lot of bugs, especially on deleting and reloading
//major test setup: //major test setup:
@ -33,8 +36,6 @@
// for a view clocks // for a view clocks
// limitation of parlio interface // limitation of parlio interface
// PARLIO_LL_TX_MAX_BITS_PER_FRAME = (PARLIO_LL_TX_MAX_BYTES_PER_FRAME * 8) // PARLIO_LL_TX_MAX_BITS_PER_FRAME = (PARLIO_LL_TX_MAX_BYTES_PER_FRAME * 8)
// PARLIO_LL_TX_MAX_BYTES_PER_FRAME = 0xFFFF // PARLIO_LL_TX_MAX_BYTES_PER_FRAME = 0xFFFF
@ -53,8 +54,6 @@
// I don't get it // I don't get it
#pragma message "Compiling for ESP32-C6" #pragma message "Compiling for ESP32-C6"
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
@ -81,19 +80,14 @@ DRAM_ATTR volatile bool previousBufferFree = true;
IRAM_ATTR bool gdma_on_trans_eof_callback(gdma_channel_handle_t dma_chan, IRAM_ATTR bool gdma_on_trans_eof_callback(gdma_channel_handle_t dma_chan,
gdma_event_data_t *event_data, void *user_data) gdma_event_data_t *event_data, void *user_data)
{ {
//esp_rom_delay_us(100); //esp_rom_delay_us(100);
previousBufferFree = true; previousBufferFree = true;
//parlio_ll_tx_reset_fifo(&PARL_IO); //parlio_ll_tx_reset_fifo(&PARL_IO);
parlio_ll_tx_reset_clock(&PARL_IO); parlio_ll_tx_reset_clock(&PARL_IO);
//gdma_start(dma_chan, (intptr_t)&_dmadesc_a[0]); //gdma_start(dma_chan, (intptr_t)&_dmadesc_a[0]);
//while (parlio_ll_tx_is_ready(&PARL_IO) == false); //while (parlio_ll_tx_is_ready(&PARL_IO) == false);
//parlio_ll_tx_start(&PARL_IO, true); //parlio_ll_tx_start(&PARL_IO, true);
//parlio_ll_tx_enable_clock(&PARL_IO, true); //parlio_ll_tx_enable_clock(&PARL_IO, true);
@ -110,9 +104,10 @@ void Bus_Parallel16::config(const config_t &cfg)
bool Bus_Parallel16::init(void) bool Bus_Parallel16::init(void)
{ {
ESP_LOGI("ESP32-C6", "Performing DMA bus init() for ESP-C6");
periph_module_enable(PERIPH_PARLIO_MODULE); periph_module_enable(PERIPH_PARLIO_MODULE);
periph_module_reset(PERIPH_PARLIO_MODULE); periph_module_reset (PERIPH_PARLIO_MODULE);
// Reset LCD bus // Reset LCD bus
parlio_ll_tx_reset_fifo(&PARL_IO); parlio_ll_tx_reset_fifo(&PARL_IO);
@ -120,19 +115,18 @@ bool Bus_Parallel16::init(void)
parlio_ll_clock_source_t clk_src = (parlio_ll_clock_source_t)PARLIO_CLK_SRC_DEFAULT; parlio_ll_clock_source_t clk_src = (parlio_ll_clock_source_t)PARLIO_CLK_SRC_DEFAULT;
uint32_t periph_src_clk_hz = 0; uint32_t periph_src_clk_hz = 0;
esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &periph_src_clk_hz); esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &periph_src_clk_hz);
parlio_ll_tx_set_clock_source(&PARL_IO, clk_src); parlio_ll_tx_set_clock_source(&PARL_IO, clk_src);
uint32_t div = (periph_src_clk_hz + _cfg.bus_freq - 1) / _cfg.bus_freq; uint32_t div = (periph_src_clk_hz + _cfg.bus_freq - 1) / _cfg.bus_freq;
parlio_ll_tx_set_clock_div(&PARL_IO, div); parlio_ll_tx_set_clock_div(&PARL_IO, div);
_cfg.bus_freq = periph_src_clk_hz / div; _cfg.bus_freq = periph_src_clk_hz / div;
ESP_LOGI("C6", "Clock divider is %d", (int)div); ESP_LOGI("C6", "Clock divider is %d", (int)div);
ESP_LOGD("C6", "Resulting output clock frequency: %d Mhz", (int)(160000000L / _cfg.bus_freq)); ESP_LOGD("C6", "Resulting output clock frequency: %d Mhz", (int)(160000000L / _cfg.bus_freq));
// Allocate DMA channel and connect it to the LCD peripheral // Allocate DMA channel and connect it to the LCD peripheral
static gdma_channel_alloc_config_t dma_chan_config = { static gdma_channel_alloc_config_t dma_chan_config = {
.sibling_chan = NULL, .sibling_chan = NULL,

View file

@ -99,7 +99,7 @@
//LCD_CAM.lcd_clock.clk_en = 0; // Enable peripheral clock //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_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 = 3; // Use 160Mhz Clock Source LCD_CAM.lcd_clock.lcd_clk_sel = 3; // Use 160Mhz Clock Source -> PLL_F160M_CLK
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
@ -127,21 +127,21 @@
//LCD_CAM.lcd_clock.lcd_clkm_div_num = 10; //16mhz is the fasted the Octal PSRAM can support it seems from faptastic's testing using an N8R8 variant (Octal SPI PSRAM). //LCD_CAM.lcd_clock.lcd_clkm_div_num = 10; //16mhz is the fasted the Octal PSRAM can support it seems from faptastic's testing using an N8R8 variant (Octal SPI PSRAM).
// https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/issues/441#issuecomment-1513631890 // https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/issues/441#issuecomment-1513631890
LCD_CAM.lcd_clock.lcd_clkm_div_num = 12; // 13Mhz is the fastest when the DMA memory is needed to service other peripherals as well. LCD_CAM.lcd_clock.lcd_clkm_div_num = 12; // 13Mhz is about the fastest output from PSRAM if we want to be able to service other peripherals as well.
} }
else else
{ {
auto freq = (_cfg.bus_freq); auto freq = (_cfg.bus_freq);
auto _div_num = 20; // 8Mhzhz
auto _div_num = 8; // 20Mhz
if (freq < 20000000L) { if (freq < 20000000L) {
_div_num = 12; // 13Mhz _div_num = 10; // 16Mhz
} } else {
else if (freq > 20000000L) { _div_num = 7; // 22Mhz --- likely to have noise without a good connection
_div_num = 6; // 26Mhz --- likely to have noise without a good connection
} }
_div_num = 6;
//LCD_CAM.lcd_clock.lcd_clkm_div_num = lcd_clkm_div_num; //LCD_CAM.lcd_clock.lcd_clkm_div_num = lcd_clkm_div_num;
LCD_CAM.lcd_clock.lcd_clkm_div_num = _div_num; //3; LCD_CAM.lcd_clock.lcd_clkm_div_num = _div_num; //3;