aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLukaswnd <Lukas+git@windeln.nrw>2024-06-10 17:08:58 +0200
committerLukaswnd <Lukas+git@windeln.nrw>2024-06-10 17:08:58 +0200
commitf0b4a6d08121ddbbfa30153f073394578ba68ea3 (patch)
treeef1487d341e74ea964a87efd2513645ada051ae2 /src
parent54ef6071663325e7b8f3a9e1e0db89b0b0b7398d (diff)
add first re-try of C6
Diffstat (limited to 'src')
-rw-r--r--src/platforms/esp32c6/dma_parallel_io.cpp309
-rw-r--r--src/platforms/esp32c6/dma_parallel_io.hpp117
-rw-r--r--src/platforms/esp32c6/esp32c6-default-pins.hpp18
-rw-r--r--src/platforms/platform_detect.hpp20
4 files changed, 457 insertions, 7 deletions
diff --git a/src/platforms/esp32c6/dma_parallel_io.cpp b/src/platforms/esp32c6/dma_parallel_io.cpp
new file mode 100644
index 0000000..04c6c74
--- /dev/null
+++ b/src/platforms/esp32c6/dma_parallel_io.cpp
@@ -0,0 +1,309 @@
+#include "dma_parallel_io.hpp"
+
+#ifdef CONFIG_IDF_TARGET_ESP32C6
+
+//First implementation might have a lot of bugs, especially on deleting and reloading
+
+
+#pragma message "Compiling for ESP32-C6"
+
+#ifdef ARDUINO_ARCH_ESP32
+#include <Arduino.h>
+#endif
+
+#include "soc/parl_io_struct.h"
+#include "soc/parl_io_reg.h"
+#include "soc/parlio_periph.h"
+#include "hal/parlio_hal.h"
+#include "hal/parlio_ll.h"
+#include "hal/parlio_types.h"
+
+#include "esp_clk_tree.h"
+#include "esp_private/periph_ctrl.h"
+#include "esp_attr.h"
+#include "esp_rom_sys.h"
+#include "esp_rom_gpio.h"
+#include "driver/gpio.h"
+
+DRAM_ATTR volatile bool previousBufferFree = true;
+
+// End-of-DMA-transfer callback
+IRAM_ATTR bool gdma_on_trans_eof_callback(gdma_channel_handle_t dma_chan,
+ gdma_event_data_t *event_data, void *user_data)
+{
+
+ //esp_rom_delay_us(100);
+
+ previousBufferFree = true;
+
+ return true;
+}
+
+// ------------------------------------------------------------------------------
+
+void Bus_Parallel16::config(const config_t &cfg)
+{
+ _cfg = cfg;
+
+}
+
+bool Bus_Parallel16::init(void)
+{
+
+ periph_module_enable(PERIPH_PARLIO_MODULE);
+ periph_module_reset(PERIPH_PARLIO_MODULE);
+
+ // Reset LCD bus
+ parlio_ll_tx_reset_fifo(&PARL_IO);
+ esp_rom_delay_us(1000);
+
+
+ parlio_ll_clock_source_t clk_src = (parlio_ll_clock_source_t)PARLIO_CLK_SRC_DEFAULT;
+ 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);
+ parlio_ll_tx_set_clock_source(&PARL_IO, clk_src);
+ uint32_t div = (periph_src_clk_hz + _cfg.bus_freq - 1) / _cfg.bus_freq;
+ parlio_ll_tx_set_clock_div(&PARL_IO, div);
+ _cfg.bus_freq = periph_src_clk_hz / div;
+
+
+ ESP_LOGI("C6", "Clock divider is %d", (int)div);
+ ESP_LOGD("C6", "Resulting output clock frequency: %d Mhz", (int)(160000000L / _cfg.bus_freq));
+
+
+
+
+ // Allocate DMA channel and connect it to the LCD peripheral
+ static gdma_channel_alloc_config_t dma_chan_config = {
+ .sibling_chan = NULL,
+ .direction = GDMA_CHANNEL_DIRECTION_TX,
+ .flags = {
+ .reserve_sibling = 0}};
+ gdma_new_channel(&dma_chan_config, &dma_chan);
+ gdma_connect(dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_PARLIO, 0));
+ static gdma_strategy_config_t strategy_config = {
+ .owner_check = false,
+ .auto_update_desc = false};
+ gdma_apply_strategy(dma_chan, &strategy_config);
+
+ gdma_transfer_ability_t ability = {
+ .sram_trans_align = 32,
+ .psram_trans_align = 64,
+ };
+ gdma_set_transfer_ability(dma_chan, &ability);
+
+ // Enable DMA transfer callback
+ static gdma_tx_event_callbacks_t tx_cbs = {
+ .on_trans_eof = gdma_on_trans_eof_callback};
+ gdma_register_tx_event_callbacks(dma_chan, &tx_cbs, NULL);
+
+
+ parlio_ll_tx_reset_clock(&PARL_IO);
+ parlio_ll_tx_reset_fifo(&PARL_IO);
+ parlio_ll_tx_enable_clock(&PARL_IO, false);
+ parlio_ll_tx_enable_clock_gating(&PARL_IO, 0);
+ parlio_ll_tx_set_bus_width(&PARL_IO, 16);
+ parlio_ll_tx_treat_msb_as_valid(&PARL_IO, false);
+
+ auto sample_edge = _cfg.invert_pclk ? PARLIO_SAMPLE_EDGE_NEG : PARLIO_SAMPLE_EDGE_POS;
+ parlio_ll_tx_set_sample_clock_edge(&PARL_IO, sample_edge);
+
+ parlio_ll_clear_interrupt_status(&PARL_IO, PARLIO_LL_EVENT_TX_MASK);
+
+
+ int8_t *pins = _cfg.pin_data;
+ gpio_config_t gpio_conf = {
+ .mode = GPIO_MODE_OUTPUT,
+ .pull_up_en = GPIO_PULLUP_ENABLE,
+ .pull_down_en = GPIO_PULLDOWN_DISABLE,
+ .intr_type = GPIO_INTR_DISABLE,
+ };
+
+ for (int i = 0; i < 16; i++)
+ {
+ if (pins[i] >= 0)
+ { // -1 value will CRASH the ESP32!
+ gpio_conf.pin_bit_mask = BIT64(pins[i]);
+ gpio_config(&gpio_conf);
+ esp_rom_gpio_connect_out_signal(pins[i], parlio_periph_signals.groups[0].tx_units[0].data_sigs[i], false, false);
+ gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[pins[i]], PIN_FUNC_GPIO);
+ gpio_set_drive_capability((gpio_num_t)pins[i], (gpio_drive_cap_t)3);
+ }
+ }
+
+ // Clock
+ gpio_conf.pin_bit_mask = BIT64(_cfg.pin_wr);
+ gpio_config(&gpio_conf);
+ esp_rom_gpio_connect_out_signal(_cfg.pin_wr, parlio_periph_signals.groups[0].tx_units[0].clk_out_sig, _cfg.invert_pclk, false);
+ gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[_cfg.pin_wr], PIN_FUNC_GPIO);
+ gpio_set_drive_capability((gpio_num_t)_cfg.pin_wr, (gpio_drive_cap_t)3);
+
+ parlio_ll_tx_set_idle_data_value(&PARL_IO, 0);
+ parlio_ll_tx_set_trans_bit_len(&PARL_IO, ((1<<16) -1) * 8);
+
+ return true; // no return val = illegal instruction
+}
+
+void Bus_Parallel16::release(void)
+{
+ if (_dmadesc_a)
+ {
+ heap_caps_free(_dmadesc_a);
+ _dmadesc_a = nullptr;
+
+ }
+ if(_dmadesc_b){
+ heap_caps_free(_dmadesc_b);
+ _dmadesc_b = nullptr;
+ }
+ _dmadesc_count = 0;
+}
+
+void Bus_Parallel16::enable_double_dma_desc(void)
+{
+ ESP_LOGI("C6", "Enabled support for secondary DMA buffer.");
+ _double_dma_buffer = true;
+}
+
+// Need this to work for double buffers etc.
+bool Bus_Parallel16::allocate_dma_desc_memory(size_t len)
+{
+ if (_dmadesc_a)
+ heap_caps_free(_dmadesc_a); // free all dma descrptios previously
+ _dmadesc_count = len;
+
+ ESP_LOGD("C6", "Allocating %d bytes memory for DMA descriptors.", (int)sizeof(HUB75_DMA_DESCRIPTOR_T) * len);
+
+ _dmadesc_a = (HUB75_DMA_DESCRIPTOR_T *)heap_caps_malloc(sizeof(HUB75_DMA_DESCRIPTOR_T) * len, MALLOC_CAP_DMA);
+
+ if (_dmadesc_a == nullptr)
+ {
+ ESP_LOGE("C6", "ERROR: Couldn't malloc _dmadesc_a. Not enough memory.");
+ return false;
+ }
+
+ if (_double_dma_buffer)
+ {
+ _dmadesc_b = (HUB75_DMA_DESCRIPTOR_T *)heap_caps_malloc(sizeof(HUB75_DMA_DESCRIPTOR_T) * len, MALLOC_CAP_DMA);
+
+ if (_dmadesc_b == nullptr)
+ {
+ ESP_LOGE("C6", "ERROR: Couldn't malloc _dmadesc_b. Not enough memory.");
+ _double_dma_buffer = false;
+ }
+ }
+
+ /// override static
+ _dmadesc_a_idx = 0;
+ _dmadesc_b_idx = 0;
+
+ return true;
+}
+
+void Bus_Parallel16::create_dma_desc_link(void *data, size_t size, bool dmadesc_b)
+{
+ static constexpr size_t MAX_DMA_LEN = (4096 - 4);
+
+ if (size > MAX_DMA_LEN)
+ {
+ size = MAX_DMA_LEN;
+ ESP_LOGW("C6", "Creating DMA descriptor which links to payload with size greater than MAX_DMA_LEN!");
+ }
+
+ if (dmadesc_b == true)
+ {
+
+ _dmadesc_b[_dmadesc_b_idx].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
+ //_dmadesc_b[_dmadesc_b_idx].dw0.suc_eof = 0;
+ _dmadesc_b[_dmadesc_b_idx].dw0.suc_eof = (_dmadesc_b_idx == (_dmadesc_count - 1));
+ _dmadesc_b[_dmadesc_b_idx].dw0.size = _dmadesc_b[_dmadesc_b_idx].dw0.length = size; // sizeof(data);
+ _dmadesc_b[_dmadesc_b_idx].buffer = data; // data;
+
+ if (_dmadesc_b_idx == _dmadesc_count - 1)
+ {
+ _dmadesc_b[_dmadesc_b_idx].next = (dma_descriptor_t *)&_dmadesc_b[0];
+ }
+ else
+ {
+ _dmadesc_b[_dmadesc_b_idx].next = (dma_descriptor_t *)&_dmadesc_b[_dmadesc_b_idx + 1];
+ }
+
+ _dmadesc_b_idx++;
+ }
+ else
+ {
+
+ if (_dmadesc_a_idx >= _dmadesc_count)
+ {
+ ESP_LOGE("C6", "Attempted to create more DMA descriptors than allocated. Expecting max %u descriptors.", (unsigned int)_dmadesc_count);
+ return;
+ }
+
+ _dmadesc_a[_dmadesc_a_idx].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
+ //_dmadesc_a[_dmadesc_a_idx].dw0.suc_eof = 0;
+ _dmadesc_a[_dmadesc_a_idx].dw0.suc_eof = (_dmadesc_a_idx == (_dmadesc_count - 1));
+ _dmadesc_a[_dmadesc_a_idx].dw0.size = _dmadesc_a[_dmadesc_a_idx].dw0.length = size; // sizeof(data);
+ _dmadesc_a[_dmadesc_a_idx].buffer = data; // data;
+
+ if (_dmadesc_a_idx == _dmadesc_count - 1)
+ {
+ _dmadesc_a[_dmadesc_a_idx].next = (dma_descriptor_t *)&_dmadesc_a[0];
+ }
+ else
+ {
+ _dmadesc_a[_dmadesc_a_idx].next = (dma_descriptor_t *)&_dmadesc_a[_dmadesc_a_idx + 1];
+ }
+
+ _dmadesc_a_idx++;
+ }
+
+} // end create_dma_desc_link
+
+void Bus_Parallel16::dma_transfer_start()
+{
+ parlio_ll_tx_reset_fifo(&PARL_IO);
+ parlio_ll_tx_reset_clock(&PARL_IO);
+
+ gdma_start(dma_chan, (intptr_t)&_dmadesc_a[0]);
+
+ while (parlio_ll_tx_is_ready(&PARL_IO) == false);
+
+ parlio_ll_tx_start(&PARL_IO, true);
+ parlio_ll_tx_enable_clock(&PARL_IO, true);
+
+} // end
+
+void Bus_Parallel16::dma_transfer_stop()
+{
+
+ gdma_stop(dma_chan);
+
+} // end
+
+void Bus_Parallel16::flip_dma_output_buffer(int back_buffer_id)
+{
+
+ // if ( _double_dma_buffer == false) return;
+
+ if (back_buffer_id == 1) // change across to everything 'b''
+ {
+ _dmadesc_a[_dmadesc_count - 1].next = (dma_descriptor_t *)&_dmadesc_b[0];
+ _dmadesc_b[_dmadesc_count - 1].next = (dma_descriptor_t *)&_dmadesc_b[0];
+ }
+ else
+ {
+ _dmadesc_b[_dmadesc_count - 1].next = (dma_descriptor_t *)&_dmadesc_a[0];
+ _dmadesc_a[_dmadesc_count - 1].next = (dma_descriptor_t *)&_dmadesc_a[0];
+ }
+
+ // current_back_buffer_id ^= 1;
+
+ previousBufferFree = false;
+
+ // while (i2s_parallel_is_previous_buffer_free() == false) {}
+ while (!previousBufferFree)
+ ;
+
+} // end flip
+
+#endif \ No newline at end of file
diff --git a/src/platforms/esp32c6/dma_parallel_io.hpp b/src/platforms/esp32c6/dma_parallel_io.hpp
new file mode 100644
index 0000000..3d6bbab
--- /dev/null
+++ b/src/platforms/esp32c6/dma_parallel_io.hpp
@@ -0,0 +1,117 @@
+/*
+ Simple example of using the ESP32-C6's parallel IO peripheral for general-purpose
+ parallel data output with DMA.
+
+ Credits to ESPRESSIF them selfe, they made the first example:
+
+ https://github.com/espressif/esp-idf/tree/release/v5.1/examples/peripherals/parlio/simple_rgb_led_matrix
+
+ And Credits to the guy who implemented the S3 version of this library.
+ There is a lot of resusable code
+
+
+*/
+
+
+#pragma once
+
+#include <sdkconfig.h>
+
+#ifdef CONFIG_IDF_TARGET_ESP32C6
+
+#include "driver/parlio_tx.h"
+
+#include <esp_private/gdma.h>
+#include <hal/dma_types.h>
+#include <hal/gpio_hal.h>
+
+
+#define DMA_MAX (4096-4)
+#define HUB75_DMA_DESCRIPTOR_T dma_descriptor_t
+
+
+class Bus_Parallel16
+ {
+ public:
+ Bus_Parallel16()
+ {
+
+ }
+
+ struct config_t
+ {
+ // LCD_CAM peripheral number. No need to change (only 0 for ESP32-S3.)
+ //int port = 0;
+
+ // max 40MHz (when in 16 bit / 2 byte mode)
+ uint32_t bus_freq = 10000000;
+ int8_t pin_wr = -1;
+ //int8_t pin_rd = -1;
+ //int8_t pin_rs = -1; // D/C
+ bool invert_pclk = false;
+ //bool psram_clk_override = false;
+ union
+ {
+ int8_t pin_data[16];
+ struct
+ {
+ int8_t pin_d0;
+ int8_t pin_d1;
+ int8_t pin_d2;
+ int8_t pin_d3;
+ int8_t pin_d4;
+ int8_t pin_d5;
+ int8_t pin_d6;
+ int8_t pin_d7;
+ int8_t pin_d8;
+ int8_t pin_d9;
+ int8_t pin_d10;
+ int8_t pin_d11;
+ int8_t pin_d12;
+ int8_t pin_d13;
+ int8_t pin_d14;
+ int8_t pin_d15;
+ };
+ };
+ };
+
+ const config_t& config(void) const { return _cfg; }
+ void config(const config_t& config);
+
+ bool init(void) ;
+
+ void release(void) ;
+
+ void enable_double_dma_desc();
+ bool allocate_dma_desc_memory(size_t len);
+
+ void create_dma_desc_link(void *memory, size_t size, bool dmadesc_b = false);
+
+ void dma_transfer_start();
+ void dma_transfer_stop();
+
+ void flip_dma_output_buffer(int back_buffer_id);
+
+ private:
+
+ config_t _cfg;
+
+
+ gdma_channel_handle_t dma_chan;
+
+ uint32_t _dmadesc_count = 0; // number of dma decriptors
+
+ uint32_t _dmadesc_a_idx = 0;
+ uint32_t _dmadesc_b_idx = 0;
+
+ HUB75_DMA_DESCRIPTOR_T* _dmadesc_a = nullptr;
+ HUB75_DMA_DESCRIPTOR_T* _dmadesc_b = nullptr;
+
+ bool _double_dma_buffer = false;
+ //bool _dmadesc_a_active = true;
+
+ };
+
+
+
+#endif \ No newline at end of file
diff --git a/src/platforms/esp32c6/esp32c6-default-pins.hpp b/src/platforms/esp32c6/esp32c6-default-pins.hpp
new file mode 100644
index 0000000..ef9c04e
--- /dev/null
+++ b/src/platforms/esp32c6/esp32c6-default-pins.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+// Avoid and QSPI pins
+
+#define R1_PIN_DEFAULT 7
+#define G1_PIN_DEFAULT 4
+#define B1_PIN_DEFAULT 1
+#define R2_PIN_DEFAULT 6
+#define G2_PIN_DEFAULT 3
+#define B2_PIN_DEFAULT 0
+#define A_PIN_DEFAULT 20
+#define B_PIN_DEFAULT 21
+#define C_PIN_DEFAULT 22
+#define D_PIN_DEFAULT 23
+#define E_PIN_DEFAULT -1 // required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32
+#define LAT_PIN_DEFAULT 5
+#define OE_PIN_DEFAULT 2
+#define CLK_PIN_DEFAULT 10
diff --git a/src/platforms/platform_detect.hpp b/src/platforms/platform_detect.hpp
index 9532c88..fd2e7f5 100644
--- a/src/platforms/platform_detect.hpp
+++ b/src/platforms/platform_detect.hpp
@@ -22,11 +22,7 @@ Modified heavily for the ESP32 HUB75 DMA library by:
#include <sdkconfig.h>
- #if defined (CONFIG_IDF_TARGET_ESP32C3)
-
- #error "ERROR: ESP32C3 not supported."
-
- #elif defined (CONFIG_IDF_TARGET_ESP32S2)
+ #if defined (CONFIG_IDF_TARGET_ESP32S2)
//#pragma message "Compiling for ESP32-S2"
#include "esp32/esp32_i2s_parallel_dma.hpp"
@@ -47,9 +43,14 @@ Modified heavily for the ESP32 HUB75 DMA library by:
#define NO_FAST_FUNCTIONS 1
#endif
- #elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32H2)
+ #elif defined(CONFIG_IDF_TARGET_ESP32C6)
+
+ #include "esp32c6/dma_parallel_io.hpp"
+ #include "esp32c6/esp32c6-default-pins.hpp"
+
+ #elif defined(CONFIG_IDF_TARGET_ESP32P4)
- #error "ESP32 RISC-V devices do not have an LCD interface and are therefore not supported by this library."
+ #pragma message "you are ahead of your time. ESP32P4 Support is planned"
#elif defined (CONFIG_IDF_TARGET_ESP32) || defined(ESP32)
@@ -63,6 +64,11 @@ Modified heavily for the ESP32 HUB75 DMA library by:
#include "esp32/esp32_i2s_parallel_dma.hpp"
#include "esp32/esp32-default-pins.hpp"
+#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32H2)
+
+ #error "ESP32 C2 C3 and H2 devices are not supported by this library."
+
+
#else
#error "Unknown platform."