diff options
| author | mrfaptastic <12006953+mrfaptastic@users.noreply.github.com> | 2022-09-30 03:17:19 +0100 |
|---|---|---|
| committer | mrfaptastic <12006953+mrfaptastic@users.noreply.github.com> | 2022-09-30 03:17:19 +0100 |
| commit | ebe75dcaba0239d225243cdedd31aaf860abbd0a (patch) | |
| tree | fda21143906b93de687447af52c40f9329956d21 /src/platforms/esp32s3 | |
| parent | 86063fe594cda6a572bd335e7e34af7c75226aad (diff) | |
Update to include S3 support.
Refactor tonnes of code. Double buffering not yet fully tested. PSRAM support doesn't work at all - garbled mess.
Enable in platformIO using:
build_flags =
-DSPIRAM_FRAMEBUFFER=1
Diffstat (limited to 'src/platforms/esp32s3')
| -rw-r--r-- | src/platforms/esp32s3/ESP32-S3-DevKitC-1-pin-layout.png | bin | 0 -> 497667 bytes | |||
| -rw-r--r-- | src/platforms/esp32s3/Readme.md | 16 | ||||
| -rw-r--r-- | src/platforms/esp32s3/ReservedPinsForPSRAM.PNG | bin | 0 -> 94554 bytes | |||
| -rw-r--r-- | src/platforms/esp32s3/esp32s3-default-pins.hpp | 18 | ||||
| -rw-r--r-- | src/platforms/esp32s3/gdma_lcd_parallel16.cpp | 356 | ||||
| -rw-r--r-- | src/platforms/esp32s3/gdma_lcd_parallel16.hpp | 176 |
6 files changed, 566 insertions, 0 deletions
diff --git a/src/platforms/esp32s3/ESP32-S3-DevKitC-1-pin-layout.png b/src/platforms/esp32s3/ESP32-S3-DevKitC-1-pin-layout.png Binary files differnew file mode 100644 index 0000000..c4391b3 --- /dev/null +++ b/src/platforms/esp32s3/ESP32-S3-DevKitC-1-pin-layout.png diff --git a/src/platforms/esp32s3/Readme.md b/src/platforms/esp32s3/Readme.md new file mode 100644 index 0000000..6b6c716 --- /dev/null +++ b/src/platforms/esp32s3/Readme.md @@ -0,0 +1,16 @@ +https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/external-ram.html + +Restrictions + +External RAM use has the following restrictions: + +When flash cache is disabled (for example, if the flash is being written to), the external RAM also becomes inaccessible; any reads from or writes to it will lead to an illegal cache access exception. This is also the reason why ESP-IDF does not by default allocate any task stacks in external RAM (see below). + + External RAM cannot be used as a place to store DMA transaction descriptors or as a buffer for a DMA transfer to read from or write into. Therefore when External RAM is enabled, any buffer that will be used in combination with DMA must be allocated using heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL) and can be freed using a standard free() call. + +*Note, although ESP32-S3 has hardware support for DMA to/from external RAM, this is not yet supported in ESP-IDF.* + +External RAM uses the same cache region as the external flash. This means that frequently accessed variables in external RAM can be read and modified almost as quickly as in internal ram. However, when accessing large chunks of data (>32 KB), the cache can be insufficient, and speeds will fall back to the access speed of the external RAM. Moreover, accessing large chunks of data can “push out” cached flash, possibly making the execution of code slower afterwards. + +In general, external RAM will not be used as task stack memory. xTaskCreate() and similar functions will always allocate internal memory for stack and task TCBs. + diff --git a/src/platforms/esp32s3/ReservedPinsForPSRAM.PNG b/src/platforms/esp32s3/ReservedPinsForPSRAM.PNG Binary files differnew file mode 100644 index 0000000..994fda8 --- /dev/null +++ b/src/platforms/esp32s3/ReservedPinsForPSRAM.PNG diff --git a/src/platforms/esp32s3/esp32s3-default-pins.hpp b/src/platforms/esp32s3/esp32s3-default-pins.hpp new file mode 100644 index 0000000..57d8aae --- /dev/null +++ b/src/platforms/esp32s3/esp32s3-default-pins.hpp @@ -0,0 +1,18 @@ +#pragma once + +// Avoid and QSPI pins + +#define R1_PIN_DEFAULT 4 +#define G1_PIN_DEFAULT 5 +#define B1_PIN_DEFAULT 6 +#define R2_PIN_DEFAULT 7 +#define G2_PIN_DEFAULT 15 +#define B2_PIN_DEFAULT 16 +#define A_PIN_DEFAULT 18 +#define B_PIN_DEFAULT 8 +#define C_PIN_DEFAULT 3 +#define D_PIN_DEFAULT 42 +#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 40 +#define OE_PIN_DEFAULT 2 +#define CLK_PIN_DEFAULT 41 diff --git a/src/platforms/esp32s3/gdma_lcd_parallel16.cpp b/src/platforms/esp32s3/gdma_lcd_parallel16.cpp new file mode 100644 index 0000000..785e489 --- /dev/null +++ b/src/platforms/esp32s3/gdma_lcd_parallel16.cpp @@ -0,0 +1,356 @@ +/* + Simple example of using the ESP32-S3's LCD peripheral for general-purpose + (non-LCD) parallel data output with DMA. Connect 8 LEDs (or logic analyzer), + cycles through a pattern among them at about 1 Hz. + This code is ONLY for the ESP32-S3, NOT the S2, C3 or original ESP32. + None of this is authoritative canon, just a lot of trial error w/datasheet + and register poking. Probably more robust ways of doing this still TBD. + + + FULL CREDIT goes to AdaFruit + + https://blog.adafruit.com/2022/06/21/esp32uesday-more-s3-lcd-peripheral-hacking-with-code/ + + PLEASE SUPPORT THEM! + + */ + #include <Arduino.h> + #include "gdma_lcd_parallel16.hpp" + + static const char* TAG = "gdma_lcd_parallel16"; + + + dma_descriptor_t desc; // DMA descriptor for testing +/* + uint8_t data[8][312]; // Transmit buffer (2496 bytes total) + uint16_t* dmabuff2; +*/ + // End-of-DMA-transfer callback + static IRAM_ATTR bool dma_callback(gdma_channel_handle_t dma_chan, + gdma_event_data_t *event_data, void *user_data) { + // This DMA callback seems to trigger a moment before the last data has + // issued (buffering between DMA & LCD peripheral?), so pause a moment + // before stopping LCD data out. The ideal delay may depend on the LCD + // clock rate...this one was determined empirically by monitoring on a + // logic analyzer. YMMV. + esp_rom_delay_us(100); + // The LCD peripheral stops transmitting at the end of the DMA xfer, but + // clear the lcd_start flag anyway -- we poll it in loop() to decide when + // the transfer has finished, and the same flag is set later to trigger + // the next transfer. + + LCD_CAM.lcd_user.lcd_start = 0; + return true; + } + + static lcd_cam_dev_t* getDev(int port) + { + return &LCD_CAM; + } + + // ------------------------------------------------------------------------------ + + void Bus_Parallel16::config(const config_t& cfg) + { + _cfg = cfg; + auto port = cfg.port; + _dev = getDev(port); + } + + + //https://github.com/adafruit/Adafruit_Protomatter/blob/master/src/arch/esp32-s3.h + bool Bus_Parallel16::init(void) + { + ///dmabuff2 = (uint16_t*)heap_caps_malloc(sizeof(uint16_t) * 64*32, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + + // LCD_CAM peripheral isn't enabled by default -- MUST begin with this: + periph_module_enable(PERIPH_LCD_CAM_MODULE); + periph_module_reset(PERIPH_LCD_CAM_MODULE); + + // Reset LCD bus + LCD_CAM.lcd_user.lcd_reset = 1; + esp_rom_delay_us(100); + + auto lcd_clkm_div_num = 160000000 / _cfg.bus_freq / 2; + + ESP_LOGI(TAG, "Clock divider is %d", lcd_clkm_div_num); + + // Configure LCD clock. Since this program generates human-perceptible + // output and not data for LED matrices or NeoPixels, use almost the + // slowest LCD clock rate possible. The S3-mini module used on Feather + // ESP32-S3 has a 40 MHz crystal. A 2-stage clock division of 1:16000 + // is applied (250*64), yielding 2,500 Hz. Still much too fast for + // human eyes, so later we set up the data to repeat each output byte + // many times over. + LCD_CAM.lcd_clock.clk_en = 1; // Enable peripheral clock + LCD_CAM.lcd_clock.lcd_clk_sel = 2; // 160mhz source + 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_clk_equ_sysclk = 0; // PCLK = CLK / (CLKCNT_N+1) + LCD_CAM.lcd_clock.lcd_clkm_div_num = lcd_clkm_div_num; // 1st stage 1:250 divide + LCD_CAM.lcd_clock.lcd_clkm_div_a = 1; // 0/1 fractional divide + LCD_CAM.lcd_clock.lcd_clkm_div_b = 0; + + // See section 26.3.3.1 of the ESP32S3 Technical Reference Manual + // for information on other clock sources and dividers. + + // Configure LCD frame format. This is where we fiddle the peripheral + // to provide generic 8-bit output rather than actually driving an LCD. + // There's also a 16-bit mode but that's not shown here. + LCD_CAM.lcd_ctrl.lcd_rgb_mode_en = 0; // i8080 mode (not RGB) + LCD_CAM.lcd_rgb_yuv.lcd_conv_bypass = 0; // Disable RGB/YUV converter + LCD_CAM.lcd_misc.lcd_next_frame_en = 0; // Do NOT auto-frame + LCD_CAM.lcd_data_dout_mode.val = 0; // No data delays + LCD_CAM.lcd_user.lcd_always_out_en = 1; // Enable 'always out' mode + LCD_CAM.lcd_user.lcd_8bits_order = 0; // Do not swap bytes + LCD_CAM.lcd_user.lcd_bit_order = 0; // Do not reverse bit order + LCD_CAM.lcd_user.lcd_2byte_en = 1; // 8-bit data mode + LCD_CAM.lcd_user.lcd_dummy = 0; // Dummy phase(s) @ LCD start + LCD_CAM.lcd_user.lcd_dummy_cyclelen = 0; // 1 dummy phase + LCD_CAM.lcd_user.lcd_cmd = 0; // No command at LCD start + // "Dummy phases" are initial LCD peripheral clock cycles before data + // begins transmitting when requested. After much testing, determined + // that at least one dummy phase MUST be enabled for DMA to trigger + // reliably. A problem with dummy phase(s) is if we're also using the + // LCD_PCLK_IDX signal (not used in this code, but Adafruit_Protomatter + // does)...the clock signal will start a couple of pulses before data, + // which may or may not be problematic in some situations. You can + // disable the dummy phase but need to keep the LCD TX FIFO primed + // in that case, which gets complex. + // always_out_en is set above to allow aribtrary-length transfers, + // else lcd_dout_cyclelen is used...but is limited to 8K. Long (>4K) + // transfers need DMA linked lists, not used here but mentioned later. + + // Route 8 LCD data signals to GPIO pins + int8_t* pins = _cfg.pin_data; + + for(int i = 0; i < 16; i++) + { + if (pins[i] >= 0) { // -1 value will CRASH the ESP32! + esp_rom_gpio_connect_out_signal(pins[i], LCD_DATA_OUT0_IDX + 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); + } + } + + /* + const struct { + int8_t pin; + uint8_t signal; + } mux[] = { + { 43, LCD_DATA_OUT0_IDX }, // These are 8 consecutive pins down one + { 42, LCD_DATA_OUT1_IDX }, // side of the ESP32-S3 Feather. The ESP32 + { 2, LCD_DATA_OUT2_IDX }, // has super flexible pin MUX capabilities, + { 9, LCD_DATA_OUT3_IDX }, // so any signal can go to any pin! + { 10, LCD_DATA_OUT4_IDX }, + { 11, LCD_DATA_OUT5_IDX }, + { 12, LCD_DATA_OUT6_IDX }, + { 13, LCD_DATA_OUT7_IDX }, + }; + for (int i = 0; i < 8; i++) { + esp_rom_gpio_connect_out_signal(mux[i].pin, LCD_DATA_OUT0_IDX + i, false, false); + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[mux[i].pin], PIN_FUNC_GPIO); + gpio_set_drive_capability((gpio_num_t)mux[i].pin, (gpio_drive_cap_t)3); + } +*/ + // Clock + esp_rom_gpio_connect_out_signal(_cfg.pin_wr, LCD_PCLK_IDX, _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); + + // This program has a known fixed-size data buffer (2496 bytes) that fits + // in a single DMA descriptor (max 4095 bytes). Large transfers would + // require a linked list of descriptors, but here it's just one... + + desc.dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + desc.dw0.suc_eof = 0; // Last descriptor + desc.next = &desc; // No linked list + + + // Remaining descriptor elements are initialized before each DMA transfer. + + // 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_LCD, 0)); + static gdma_strategy_config_t strategy_config = { + .owner_check = false, + .auto_update_desc = false + }; + gdma_apply_strategy(dma_chan, &strategy_config); + + // Enable DMA transfer callback + static gdma_tx_event_callbacks_t tx_cbs = { + .on_trans_eof = dma_callback + }; + gdma_register_tx_event_callbacks(dma_chan, &tx_cbs, NULL); + + // As mentioned earlier, the slowest clock we can get to the LCD + // peripheral is 40 MHz / 250 / 64 = 2500 Hz. To make an even slower + // bit pattern that's perceptible, we just repeat each value many + // times over. The pattern here just counts through each of 8 bits + // (each LED lights in sequence)...so to get this to repeat at about + // 1 Hz, each LED is lit for 2500/8 or 312 cycles, hence the + // data[8][312] declaration at the start of this code (it's not + // precisely 1 Hz because reality is messy, but sufficient for demo). + // In actual use, say controlling an LED matrix or NeoPixels, such + // shenanigans aren't necessary, as these operate at multiple MHz + // with much smaller clock dividers and can use 1 byte per datum. + /* + for (int i = 0; i < (sizeof(data) / sizeof(data[0])); i++) { // 0 to 7 + for (int j = 0; j < sizeof(data[0]); j++) { // 0 to 311 + data[i][j] = 1 << i; + } + } + */ + + + // This uses a busy loop to wait for each DMA transfer to complete... + // but the whole point of DMA is that one's code can do other work in + // the interim. The CPU is totally free while the transfer runs! + while (LCD_CAM.lcd_user.lcd_start); // Wait for DMA completion callback + + // After much experimentation, each of these steps is required to get + // a clean start on the next LCD transfer: + gdma_reset(dma_chan); // Reset DMA to known state + LCD_CAM.lcd_user.lcd_dout = 1; // Enable data out + LCD_CAM.lcd_user.lcd_update = 1; // Update registers + LCD_CAM.lcd_misc.lcd_afifo_reset = 1; // Reset LCD TX FIFO + + // This program happens to send the same data over and over...but, + // if desired, one could fill the data buffer with a new bit pattern + // here, or point to a completely different buffer each time through. + // With two buffers, one can make best use of time by filling each + // with new data before the busy loop above, alternating between them. + + // Reset elements of DMA descriptor. Just one in this code, long + // transfers would loop through a linked list. + + /* + desc.dw0.size = desc.dw0.length = sizeof(data); + desc.buffer = dmabuff2; //data; + desc.next = &desc; +*/ + + +/* + //gdma_start(dma_chan, (intptr_t)&desc); // Start DMA w/updated descriptor(s) + gdma_start(dma_chan, (intptr_t)&_dmadesc_a[0]); // Start DMA w/updated descriptor(s) + esp_rom_delay_us(100); // Must 'bake' a moment before... + LCD_CAM.lcd_user.lcd_start = 1; // Trigger LCD DMA transfer +*/ + + + return true; // no return val = illegal instruction + + } + + + void Bus_Parallel16::release(void) + { + if (_i80_bus) + { + esp_lcd_del_i80_bus(_i80_bus); + } + if (_dmadesc_a) + { + heap_caps_free(_dmadesc_a); + _dmadesc_a = nullptr; + _dmadesc_count = 0; + } + + } + + void Bus_Parallel16::enable_double_dma_desc(void) + { + //_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(TAG, "Allocating %d bytes memory for DMA descriptors.", 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(TAG, "ERROR: Couldn't malloc _dmadesc_a. Not enough memory."); + return false; + } + + _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(TAG, "Creating DMA descriptor which links to payload with size greater than MAX_DMA_LEN!"); + } + + if ( _dmadesc_a_idx >= _dmadesc_count) + { + ESP_LOGE(TAG, "Attempted to create more DMA descriptors than allocated memory for. Expecting a maximum of %d DMA descriptors", _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.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() + { + gdma_start(dma_chan, (intptr_t)&_dmadesc_a[0]); // Start DMA w/updated descriptor(s) + esp_rom_delay_us(100); // Must 'bake' a moment before... + LCD_CAM.lcd_user.lcd_start = 1; // Trigger LCD DMA transfer + + } // end + + void Bus_Parallel16::dma_transfer_stop() + { + + LCD_CAM.lcd_user.lcd_reset = 1; // Trigger LCD DMA transfer + LCD_CAM.lcd_user.lcd_update = 1; // Trigger LCD DMA transfer + + gdma_stop(dma_chan); + + } // end + + + void Bus_Parallel16::flip_dma_output_buffer() + { + + + } // end flip + + diff --git a/src/platforms/esp32s3/gdma_lcd_parallel16.hpp b/src/platforms/esp32s3/gdma_lcd_parallel16.hpp new file mode 100644 index 0000000..810eacb --- /dev/null +++ b/src/platforms/esp32s3/gdma_lcd_parallel16.hpp @@ -0,0 +1,176 @@ +/* + Simple example of using the ESP32-S3's LCD peripheral for general-purpose + (non-LCD) parallel data output with DMA. Connect 8 LEDs (or logic analyzer), + cycles through a pattern among them at about 1 Hz. + This code is ONLY for the ESP32-S3, NOT the S2, C3 or original ESP32. + None of this is authoritative canon, just a lot of trial error w/datasheet + and register poking. Probably more robust ways of doing this still TBD. + + + FULL CREDIT goes to AdaFruit + + https://blog.adafruit.com/2022/06/21/esp32uesday-more-s3-lcd-peripheral-hacking-with-code/ + + PLEASE SUPPORT THEM! + + + Putin’s Russia and its genocide in Ukraine is a disgrace to humanity. + + https://www.reddit.com/r/ukraine/comments/xfuc6v/more_than_460_graves_have_already_been_found_in/ + + +/---------------------------------------------------------------------------- + +*/ + +#pragma once + +#if __has_include (<esp_lcd_panel_io.h>) + +#include <sdkconfig.h> +#include <esp_lcd_panel_io.h> + +//#include <freertos/portmacro.h> +#include <esp_intr_alloc.h> + +#include <esp_err.h> +#include <esp_log.h> + +#include <driver/gpio.h> +#include <soc/gpio_sig_map.h> + + +#include <hal/gpio_ll.h> +#include <hal/lcd_hal.h> + + + +#include <string.h> +#include <math.h> + +#include <stdint.h> + +#if (ESP_IDF_VERSION_MAJOR == 5) +#include <esp_private/periph_ctrl.h> +#else +#include <driver/periph_ctrl.h> +#endif +#include <esp_private/gdma.h> +#include <esp_rom_gpio.h> +#include <hal/dma_types.h> +#include <hal/gpio_hal.h> +#include <hal/lcd_ll.h> +#include <soc/lcd_cam_reg.h> +#include <soc/lcd_cam_struct.h> +#include <esp_heap_caps.h> +#include <esp_heap_caps_init.h> + + +#if __has_include (<esp_private/periph_ctrl.h>) + #include <esp_private/periph_ctrl.h> +#else + #include <driver/periph_ctrl.h> +#endif + +#if __has_include(<esp_arduino_version.h>) + #include <esp_arduino_version.h> +#endif + +#define DMA_MAX (4096-4) + +// The type used for this SoC +#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 = 20000000; + int8_t pin_wr = -1; + int8_t pin_rd = -1; + int8_t pin_rs = -1; // D/C + bool invert_pclk = 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(); + + private: + + config_t _cfg; + + volatile lcd_cam_dev_t* _dev; + gdma_channel_handle_t dma_chan; + + uint32_t _dmadesc_count = 0; // number of dma decriptors + uint32_t _dmadesc_a_idx = 0; + + HUB75_DMA_DESCRIPTOR_T* _dmadesc_a = nullptr; + + // uint32_t _clock_reg_value; + // uint32_t _fast_wait = 0; + + //bool _double_dma_buffer = false; + //bool _dmadesc_a_active = true; + + //uint32_t _dmadesc_b_idx = 0; + + //HUB75_DMA_DESCRIPTOR_T* _dmadesc_b = nullptr; + + esp_lcd_i80_bus_handle_t _i80_bus; + + + }; + + +#endif
\ No newline at end of file |
