Clean up clock logic
This commit is contained in:
parent
997f3840ba
commit
be2102c3bc
2 changed files with 116 additions and 90 deletions
|
@ -2,13 +2,12 @@
|
||||||
|
|
||||||
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 when used in tight loops
|
/* This replicates same function in rowBitStruct, but due to induced inlining it might be MUCH faster
|
||||||
* while method from struct could be flushed out of instruction cache between loop cycles
|
* when used in tight loops while method from struct could be flushed out of instruction cache between
|
||||||
* do NOT forget about buff_id param if using this
|
* loop cycles do NOT forget about buff_id param if using this.
|
||||||
*
|
|
||||||
* faptastic note oct22: struct call is not inlined... commenting out this additional compile declaration
|
|
||||||
*/
|
*/
|
||||||
//#define getRowDataPtr(row, _dpth, buff_id) &(dma_buff.rowBits[row]->data[_dpth * dma_buff.rowBits[row]->width + buff_id*(dma_buff.rowBits[row]->width * dma_buff.rowBits[row]->color_depth)])
|
#define getRowDataPtr(row, _dpth, buff_id) &(dma_buff.rowBits[row]->data[_dpth * dma_buff.rowBits[row]->width + buff_id*(dma_buff.rowBits[row]->width * dma_buff.rowBits[row]->colour_depth)])
|
||||||
|
|
||||||
|
|
||||||
bool MatrixPanel_I2S_DMA::allocateDMAmemory()
|
bool MatrixPanel_I2S_DMA::allocateDMAmemory()
|
||||||
{
|
{
|
||||||
|
@ -316,8 +315,7 @@ void IRAM_ATTR MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16
|
||||||
|
|
||||||
// Get the contents at this address,
|
// Get the contents at this address,
|
||||||
// it would represent a vector pointing to the full row of pixels for the specified color depth bit at Y coordinate
|
// it would represent a vector pointing to the full row of pixels for the specified color depth bit at Y coordinate
|
||||||
//ESP32_I2S_DMA_STORAGE_TYPE *p = getRowDataPtr(y_coord, colour_depth_idx, back_buffer_id);
|
ESP32_I2S_DMA_STORAGE_TYPE *p = getRowDataPtr(y_coord, colour_depth_idx, back_buffer_id);
|
||||||
ESP32_I2S_DMA_STORAGE_TYPE *p = dma_buff.rowBits[y_coord]->getDataPtr(colour_depth_idx, back_buffer_id);
|
|
||||||
|
|
||||||
|
|
||||||
// We need to update the correct uint16_t word in the rowBitStruct array pointing to a specific pixel at X - coordinate
|
// We need to update the correct uint16_t word in the rowBitStruct array pointing to a specific pixel at X - coordinate
|
||||||
|
@ -370,8 +368,7 @@ void MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t green, uint
|
||||||
--matrix_frame_parallel_row;
|
--matrix_frame_parallel_row;
|
||||||
|
|
||||||
// The destination for the pixel row bitstream
|
// The destination for the pixel row bitstream
|
||||||
//ESP32_I2S_DMA_STORAGE_TYPE *p = getRowDataPtr(matrix_frame_parallel_row, colour_depth_idx, back_buffer_id);
|
ESP32_I2S_DMA_STORAGE_TYPE *p = getRowDataPtr(matrix_frame_parallel_row, colour_depth_idx, back_buffer_id);
|
||||||
ESP32_I2S_DMA_STORAGE_TYPE *p = dma_buff.rowBits[matrix_frame_parallel_row]->getDataPtr(colour_depth_idx, back_buffer_id);
|
|
||||||
|
|
||||||
// iterate pixels in a row
|
// iterate pixels in a row
|
||||||
int x_coord=dma_buff.rowBits[matrix_frame_parallel_row]->width;
|
int x_coord=dma_buff.rowBits[matrix_frame_parallel_row]->width;
|
||||||
|
@ -422,8 +419,8 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id){
|
||||||
} else {
|
} else {
|
||||||
row[x_pixel] = abcde;
|
row[x_pixel] = abcde;
|
||||||
}
|
}
|
||||||
|
// ESP_LOGI(TAG, "x pixel 1: %d", x_pixel);
|
||||||
} while(x_pixel!=dma_buff.rowBits[row_idx]->width);
|
} while(x_pixel!=dma_buff.rowBits[row_idx]->width && x_pixel);
|
||||||
|
|
||||||
// colour_index[0] (LSB) x_pixels must be "marked" with a previous's row address, 'cause it is used to display
|
// colour_index[0] (LSB) x_pixels must be "marked" with a previous's row address, 'cause it is used to display
|
||||||
// previous row while we pump in LSB's for a new row
|
// previous row while we pump in LSB's for a new row
|
||||||
|
@ -439,6 +436,7 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id){
|
||||||
row[x_pixel] = abcde;
|
row[x_pixel] = abcde;
|
||||||
}
|
}
|
||||||
//row[x_pixel] = abcde;
|
//row[x_pixel] = abcde;
|
||||||
|
// ESP_LOGI(TAG, "x pixel 2: %d", x_pixel);
|
||||||
} while(x_pixel);
|
} while(x_pixel);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ static const char* TAG = "esp32_i2s_parallel_dma";
|
||||||
#include <driver/periph_ctrl.h>
|
#include <driver/periph_ctrl.h>
|
||||||
#include <soc/gpio_sig_map.h>
|
#include <soc/gpio_sig_map.h>
|
||||||
|
|
||||||
|
#include <Arduino.h> // Need to uncomment this to get ESP_LOG output on the Arduino Serial!!!!
|
||||||
#include <esp_err.h>
|
#include <esp_err.h>
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
} // end irq_hndlr
|
} // end irq_hndlr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Static
|
||||||
static i2s_dev_t* getDev(int port)
|
static i2s_dev_t* getDev(int port)
|
||||||
{
|
{
|
||||||
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
||||||
|
@ -64,18 +65,8 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
return (port == 0) ? &I2S0 : &I2S1;
|
return (port == 0) ? &I2S0 : &I2S1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bus_Parallel16::config(const config_t& cfg)
|
// Static
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Performing config for ESP32 or ESP32-S2");
|
|
||||||
_cfg = cfg;
|
|
||||||
auto port = cfg.port;
|
|
||||||
_dev = getDev(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
|
||||||
|
|
||||||
static void _gpio_pin_init(int pin)
|
static void _gpio_pin_init(int pin)
|
||||||
{
|
{
|
||||||
if (pin >= 0)
|
if (pin >= 0)
|
||||||
|
@ -87,13 +78,20 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Bus_Parallel16::config(const config_t& cfg)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Performing config for ESP32 or ESP32-S2");
|
||||||
|
_cfg = cfg;
|
||||||
|
auto port = cfg.port;
|
||||||
|
_dev = getDev(port);
|
||||||
|
}
|
||||||
|
|
||||||
bool Bus_Parallel16::init(void) // The big one that gets everything setup.
|
bool Bus_Parallel16::init(void) // The big one that gets everything setup.
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "Performing DMA bus init() for ESP32 or ESP32-S2");
|
ESP_LOGI(TAG, "Performing DMA bus init() for ESP32 or ESP32-S2");
|
||||||
|
|
||||||
if(_cfg.port < I2S_NUM_0 || _cfg.port >= I2S_NUM_MAX) {
|
if(_cfg.port < I2S_NUM_0 || _cfg.port >= I2S_NUM_MAX) {
|
||||||
//return ESP_ERR_INVALID_ARG;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,49 +99,6 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//auto freq = (_cfg.freq_write, 50000000u); // ?
|
|
||||||
auto freq = (_cfg.bus_freq);
|
|
||||||
|
|
||||||
uint32_t _clkdiv_write = 0;
|
|
||||||
size_t _div_num = 10;
|
|
||||||
|
|
||||||
// Calculate clock divider for ESP32-S2
|
|
||||||
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
|
||||||
|
|
||||||
static constexpr uint32_t pll_160M_clock_d2 = 160 * 1000 * 1000 >> 1;
|
|
||||||
|
|
||||||
// I2S_CLKM_DIV_NUM 2=40MHz / 3=27MHz / 4=20MHz / 5=16MHz / 8=10MHz / 10=8MHz
|
|
||||||
_div_num = std::min(255u, 1 + ((pll_160M_clock_d2) / (1 + _cfg.freq_write)));
|
|
||||||
|
|
||||||
_clkdiv_write = I2S_CLK_160M_PLL << I2S_CLK_SEL_S
|
|
||||||
| I2S_CLK_EN
|
|
||||||
| 1 << I2S_CLKM_DIV_A_S
|
|
||||||
| 0 << I2S_CLKM_DIV_B_S
|
|
||||||
| _div_num << I2S_CLKM_DIV_NUM_S
|
|
||||||
;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
|
|
||||||
// clock = 80MHz(PLL_D2_CLK)
|
|
||||||
static constexpr uint32_t pll_d2_clock = 80 * 1000 * 1000;
|
|
||||||
|
|
||||||
// I2S_CLKM_DIV_NUM 4=20MHz / 5=16MHz / 8=10MHz / 10=8MHz
|
|
||||||
_div_num = std::min(255u, std::max(3u, 1 + (pll_d2_clock / (1 + freq))));
|
|
||||||
|
|
||||||
_clkdiv_write = I2S_CLK_EN
|
|
||||||
| 1 << I2S_CLKM_DIV_A_S
|
|
||||||
| 0 << I2S_CLKM_DIV_B_S
|
|
||||||
| _div_num << I2S_CLKM_DIV_NUM_S
|
|
||||||
;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(_div_num < 2 || _div_num > 16) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//ESP_LOGI(TAG, "i2s pll clk_div_main is: %d", _div_num);
|
|
||||||
|
|
||||||
auto dev = _dev;
|
auto dev = _dev;
|
||||||
volatile int iomux_signal_base;
|
volatile int iomux_signal_base;
|
||||||
volatile int iomux_clock;
|
volatile int iomux_clock;
|
||||||
|
@ -152,7 +107,6 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
// Initialize I2S0 peripheral
|
// Initialize I2S0 peripheral
|
||||||
if (_cfg.port == 0)
|
if (_cfg.port == 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
periph_module_reset(PERIPH_I2S0_MODULE);
|
periph_module_reset(PERIPH_I2S0_MODULE);
|
||||||
periph_module_enable(PERIPH_I2S0_MODULE);
|
periph_module_enable(PERIPH_I2S0_MODULE);
|
||||||
|
|
||||||
|
@ -217,21 +171,71 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
gpio_matrix_out(pins[i], iomux_signal_base + i, false, false);
|
gpio_matrix_out(pins[i], iomux_signal_base + i, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////// Clock configuration //////////////////////////////
|
||||||
|
|
||||||
|
//auto freq = (_cfg.freq_write, 50000000u); // ?
|
||||||
|
auto freq = (_cfg.bus_freq);
|
||||||
|
|
||||||
|
uint32_t _clkdiv_write = 0;
|
||||||
|
size_t _div_num = 10;
|
||||||
|
|
||||||
|
// Calculate clock divider for ESP32-S2
|
||||||
|
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
||||||
|
|
||||||
|
static constexpr uint32_t pll_160M_clock_d2 = 160 * 1000 * 1000 >> 1;
|
||||||
|
|
||||||
|
// I2S_CLKM_DIV_NUM 2=40MHz / 3=27MHz / 4=20MHz / 5=16MHz / 8=10MHz / 10=8MHz
|
||||||
|
_div_num = std::min(255u, 1 + ((pll_160M_clock_d2) / (1 + _cfg.freq_write)));
|
||||||
|
/*
|
||||||
|
_clkdiv_write = I2S_CLK_160M_PLL << I2S_CLK_SEL_S
|
||||||
|
| I2S_CLK_EN
|
||||||
|
| 1 << I2S_CLKM_DIV_A_S
|
||||||
|
| 0 << I2S_CLKM_DIV_B_S
|
||||||
|
| _div_num << I2S_CLKM_DIV_NUM_S
|
||||||
|
;
|
||||||
|
*/
|
||||||
|
#else
|
||||||
|
|
||||||
|
|
||||||
|
// clock = 80MHz(PLL_D2_CLK)
|
||||||
|
static constexpr uint32_t pll_d2_clock = 80 * 1000 * 1000;
|
||||||
|
|
||||||
|
// I2S_CLKM_DIV_NUM 4=20MHz / 5=16MHz / 8=10MHz / 10=8MHz
|
||||||
|
_div_num = std::min(255u, std::max(3u, 1 + (pll_d2_clock / (1 + freq))));
|
||||||
|
/*
|
||||||
|
_clkdiv_write = I2S_CLK_EN
|
||||||
|
| 1 << I2S_CLKM_DIV_A_S
|
||||||
|
| 0 << I2S_CLKM_DIV_B_S
|
||||||
|
| _div_num << I2S_CLKM_DIV_NUM_S
|
||||||
|
;
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
|
||||||
// Setup i2s clock
|
if(_div_num < 2 || _div_num > 16) {
|
||||||
dev->sample_rate_conf.val = 0;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "i2s pll clk_div_main is: %d", _div_num);
|
||||||
|
|
||||||
|
|
||||||
|
dev->clkm_conf.clkm_div_b = 0; // Clock numerator
|
||||||
|
dev->clkm_conf.clkm_div_a = 1; // Clock denominator
|
||||||
|
|
||||||
|
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
||||||
|
dev->clkm_conf.clk_sel = 2; // 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_en = 1;
|
||||||
|
dev->clkm_conf.clkm_div_num = _div_num;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Must be ESP32 original
|
||||||
|
#if !defined (CONFIG_IDF_TARGET_ESP32S2)
|
||||||
|
dev->clkm_conf.clka_en=0; // Use the 80mhz system clock (PLL_D2_CLK) when '0'
|
||||||
|
dev->clkm_conf.clkm_div_num = 3; // Hard code to whatever frequency this is. 26Mhz?
|
||||||
|
#endif
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
dev->sample_rate_conf.rx_bck_div_num = 2;
|
|
||||||
dev->sample_rate_conf.tx_bck_div_num = 2;
|
|
||||||
|
|
||||||
// Clock configuration
|
|
||||||
// dev->clkm_conf.val=0; // Clear the clkm_conf struct
|
|
||||||
/*
|
|
||||||
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
||||||
dev->clkm_conf.clk_sel = 2; // esp32-s2 only
|
dev->clkm_conf.clk_sel = 2; // esp32-s2 only
|
||||||
dev->clkm_conf.clk_en = 1;
|
dev->clkm_conf.clk_en = 1;
|
||||||
|
@ -243,12 +247,27 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
|
|
||||||
dev->clkm_conf.clkm_div_b=0; // Clock numerator
|
dev->clkm_conf.clkm_div_b=0; // Clock numerator
|
||||||
dev->clkm_conf.clkm_div_a=1; // Clock denominator
|
dev->clkm_conf.clkm_div_a=1; // Clock denominator
|
||||||
*/
|
|
||||||
|
|
||||||
// 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.
|
||||||
//dev->clkm_conf.clkm_div_num = 32;
|
dev->clkm_conf.clkm_div_num = 2;
|
||||||
dev->clkm_conf.val = _clkdiv_write;
|
*/
|
||||||
|
|
||||||
|
//dev->clkm_conf.val = _clkdiv_write;
|
||||||
|
|
||||||
|
|
||||||
|
// 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
|
||||||
|
dev->sample_rate_conf.rx_bck_div_num = 1;
|
||||||
|
dev->sample_rate_conf.tx_bck_div_num = 1;
|
||||||
|
|
||||||
|
////////////////////////////// END CLOCK CONFIGURATION /////////////////////////////////
|
||||||
|
|
||||||
// I2S conf2 reg
|
// I2S conf2 reg
|
||||||
dev->conf2.val = 0;
|
dev->conf2.val = 0;
|
||||||
|
@ -352,6 +371,15 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dev->timing.val = 0;
|
dev->timing.val = 0;
|
||||||
|
|
||||||
|
//dev->int_ena.out_eof = 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
12.6.2 DMA Interrupts
|
||||||
|
• I2S_OUT_TOTAL_EOF_INT: Triggered when all transmitting linked lists are used up.
|
||||||
|
• I2S_OUT_EOF_INT: Triggered when rxlink has finished sending a packet
|
||||||
|
|
||||||
|
*/
|
||||||
/*
|
/*
|
||||||
// We using the double buffering switch logic?
|
// We using the double buffering switch logic?
|
||||||
if (conf->int_ena_out_eof)
|
if (conf->int_ena_out_eof)
|
||||||
|
@ -455,10 +483,10 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
void Bus_Parallel16::create_dma_desc_link(void *data, size_t size, bool dmadesc_b)
|
void Bus_Parallel16::create_dma_desc_link(void *data, size_t size, bool dmadesc_b)
|
||||||
{
|
{
|
||||||
static constexpr size_t MAX_DMA_LEN = (4096-4);
|
static constexpr size_t MAX_DMA_LEN = (4096-4);
|
||||||
|
/*
|
||||||
if (dmadesc_b)
|
if (dmadesc_b)
|
||||||
ESP_LOGI(TAG, " * Double buffer descriptor.");
|
ESP_LOGI(TAG, " * Double buffer descriptor.");
|
||||||
|
*/
|
||||||
if (size > MAX_DMA_LEN)
|
if (size > MAX_DMA_LEN)
|
||||||
{
|
{
|
||||||
size = MAX_DMA_LEN;
|
size = MAX_DMA_LEN;
|
||||||
|
@ -507,7 +535,7 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
dmadesc->size = size;
|
dmadesc->size = size;
|
||||||
dmadesc->length = size;
|
dmadesc->length = size;
|
||||||
dmadesc->buf = (uint8_t*) data;
|
dmadesc->buf = (uint8_t*) data;
|
||||||
dmadesc->eof = 0;
|
dmadesc->eof = eof;
|
||||||
dmadesc->sosf = 0;
|
dmadesc->sosf = 0;
|
||||||
dmadesc->owner = 1;
|
dmadesc->owner = 1;
|
||||||
dmadesc->qe.stqe_next = (lldesc_t*) next;
|
dmadesc->qe.stqe_next = (lldesc_t*) next;
|
||||||
|
|
Loading…
Reference in a new issue