aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormrfaptastic <12006953+mrfaptastic@users.noreply.github.com>2021-12-21 22:19:59 +0000
committermrfaptastic <12006953+mrfaptastic@users.noreply.github.com>2021-12-21 22:19:59 +0000
commit4f5fcf039953cbfbae689f9a433c8f9cd36348c8 (patch)
tree561ce38c5656e488cfaaf867d7f64ddf6082b48e
parent229b0d874c5370fe4b50988dd9a17ff8248068ed (diff)
Christmas DMA core tweaks
Bring back support to change the I2S_NUM_X as a define. Attempt to reduce buffer swap flicker with some additional checks.
-rw-r--r--ESP32-HUB75-MatrixPanel-I2S-DMA.cpp18
-rw-r--r--ESP32-HUB75-MatrixPanel-I2S-DMA.h23
-rw-r--r--esp32_i2s_parallel_dma.c125
-rw-r--r--esp32_i2s_parallel_dma.h4
-rw-r--r--examples/1_SimpleTestShapes/1_SimpleTestShapes.ino9
-rw-r--r--examples/README.md5
6 files changed, 115 insertions, 69 deletions
diff --git a/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp b/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp
index a82b37f..a9fae2f 100644
--- a/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp
+++ b/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp
@@ -419,7 +419,7 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
Serial.println(F("Performing I2S setup:"));
#endif
- i2s_parallel_config_t cfg = {
+ i2s_parallel_config_t dma_cfg = {
.gpio_bus={_cfg.gpio.r1, _cfg.gpio.g1, _cfg.gpio.b1, _cfg.gpio.r2, _cfg.gpio.g2, _cfg.gpio.b2, _cfg.gpio.lat, _cfg.gpio.oe, _cfg.gpio.a, _cfg.gpio.b, _cfg.gpio.c, _cfg.gpio.d, _cfg.gpio.e, -1, -1, -1},
.gpio_clk=_cfg.gpio.clk,
.sample_rate=_cfg.i2sspeed,
@@ -428,18 +428,16 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
.lldesc_a=dmadesc_a,
.desccount_b=desccount,
.lldesc_b=dmadesc_b,
- .clkphase=_cfg.clkphase
+ .clkphase=_cfg.clkphase,
+ .int_ena_out_eof=_cfg.double_buff
};
-
- // Setup I2S
- i2s_parallel_driver_install(I2S_NUM_0, &cfg);
- //i2s_parallel_setup_without_malloc(&I2S1, &cfg);
-
- // Start DMA Output
- i2s_parallel_send_dma(I2S_NUM_0, &dmadesc_a[0]);
+
+ // Setup I2S
+ i2s_parallel_driver_install(ESP32_I2S_DEVICE, &dma_cfg);
+ i2s_parallel_send_dma(ESP32_I2S_DEVICE, &dmadesc_a[0]);
#if SERIAL_DEBUG
- Serial.println(F("configureDMA(): DMA setup completed on I2S_NUM_0."));
+ Serial.println(F("configureDMA(): DMA setup completed on ESP32_I2S_DEVICE."));
#endif
} // end initMatrixDMABuff
diff --git a/ESP32-HUB75-MatrixPanel-I2S-DMA.h b/ESP32-HUB75-MatrixPanel-I2S-DMA.h
index 3ef5713..db508cd 100644
--- a/ESP32-HUB75-MatrixPanel-I2S-DMA.h
+++ b/ESP32-HUB75-MatrixPanel-I2S-DMA.h
@@ -129,9 +129,10 @@
/***************************************************************************************/
/* Definitions below should NOT be ever changed without rewriting library logic */
-#define ESP32_I2S_DMA_MODE I2S_PARALLEL_WIDTH_16 // From esp32_i2s_parallel_v2.h = 16 bits in parallel
+#define ESP32_I2S_DMA_MODE I2S_PARALLEL_WIDTH_16 // From esp32_i2s_parallel_v2.h = 16 bits in parallel
#define ESP32_I2S_DMA_STORAGE_TYPE uint16_t // DMA output of one uint16_t at a time.
-#define CLKS_DURING_LATCH 0 // Not (yet) used.
+#define CLKS_DURING_LATCH 0 // Not (yet) used.
+#define ESP32_I2S_DEVICE I2S_NUM_1
// Panel Upper half RGB (numbering according to order in DMA gpio_bus configuration)
#define BITS_RGB1_OFFSET 0 // Start point of RGB_X1 bits
@@ -316,7 +317,7 @@ struct HUB75_I2S_CFG {
LAT_PIN_DEFAULT, OE_PIN_DEFAULT, CLK_PIN_DEFAULT },
shift_driver _drv = SHIFTREG,
bool _dbuff = false,
- clk_speed _i2sspeed = HZ_20M,
+ clk_speed _i2sspeed = HZ_10M,
uint8_t _latblk = 1, // Anything > 1 seems to cause artefacts on ICS panels
bool _clockphase = true,
uint8_t _min_refresh_rate = 85
@@ -525,14 +526,22 @@ class MatrixPanel_I2S_DMA {
Serial.printf_P(PSTR("Set back buffer to: %d\n"), back_buffer_id);
#endif
- i2s_parallel_flip_to_buffer(I2S_NUM_0, back_buffer_id);
-
+ i2s_parallel_set_previous_buffer_not_free();
// Wait before we allow any writing to the buffer. Stop flicker.
while(i2s_parallel_is_previous_buffer_free() == false) { }
+ i2s_parallel_flip_to_buffer(ESP32_I2S_DEVICE, back_buffer_id);
// Flip to other buffer as the backbuffer.
// i.e. Graphic changes happen to this buffer, but aren't displayed until flipDMABuffer() is called again.
- back_buffer_id ^= 1;
+ back_buffer_id ^= 1;
+
+ i2s_parallel_set_previous_buffer_not_free();
+ // Wait before we allow any writing to the buffer. Stop flicker.
+ while(i2s_parallel_is_previous_buffer_free() == false) { }
+
+
+
+
}
@@ -585,7 +594,7 @@ class MatrixPanel_I2S_DMA {
*/
void stopDMAoutput() {
resetbuffers();
- i2s_parallel_stop_dma(I2S_NUM_0);
+ i2s_parallel_stop_dma(ESP32_I2S_DEVICE);
}
diff --git a/esp32_i2s_parallel_dma.c b/esp32_i2s_parallel_dma.c
index 960fab6..ec6e17b 100644
--- a/esp32_i2s_parallel_dma.c
+++ b/esp32_i2s_parallel_dma.c
@@ -13,6 +13,7 @@
// Header
#include "esp32_i2s_parallel_dma.h"
+#include "esp32_i2s_parallel_mcu_def.h"
#include <stdbool.h>
#include <stdint.h>
@@ -25,22 +26,28 @@
#include <soc/gpio_sig_map.h>
// For I2S state management.
-static i2s_parallel_state_t *i2s_state = NULL;
+static i2s_parallel_state_t *i2s_state = NULL;
// ESP32-S2,S3,C3 only has IS20
// Original ESP32 has two I2S's, but we'll stick with the lowest common denominator.
-static i2s_dev_t* I2S = &I2S0; // Device to use for this library, change if you want.
+
+#ifdef ESP32_ORIG
+static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1};
+#else
+static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0};
+#endif
callback shiftCompleteCallback;
void setShiftCompleteCallback(callback f) {
shiftCompleteCallback = f;
}
-volatile bool previousBufferFree = true;
+volatile int previousBufferOutputLoopCount = 0;
+volatile bool previousBufferFree = true;
static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
-#ifdef ESP_ORIG
+#ifdef ESP32_ORIG
if ( (*(i2s_port_t*)arg) == I2S_NUM_1 ) { // https://www.bogotobogo.com/cplusplus/pointers2_voidpointers_arrays.php
//For I2S1
@@ -51,17 +58,25 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
}
#else
- // Other ESP32 MCU's only have one I2S
+ // Other ESP32 MCU's only have one I2S
SET_PERI_REG_BITS(I2S_INT_CLR_REG(0), I2S_OUT_EOF_INT_CLR_V, 1, I2S_OUT_EOF_INT_CLR_S);
-#endif
-
- // at this point, the previously active buffer is free, go ahead and write to it
- previousBufferFree = true;
-
- if(shiftCompleteCallback) // we've defined a callback function ?
- shiftCompleteCallback();
-
+#endif
+/*
+ if ( previousBufferOutputLoopCount == 1)
+ {
+ // at this point, the previously active buffer is free, go ahead and write to it
+ previousBufferFree = true;
+ ////previousBufferOutputLoopCount = 0;
+ //i2s_parallel_set_previous_buffer_not_free();
+ }
+ else { previousBufferOutputLoopCount++; }
+*/
+ previousBufferFree = true;
+
+ // if(shiftCompleteCallback) // we've defined a callback function ?
+ // shiftCompleteCallback();
+
} // end irq_hndlr
@@ -155,7 +170,7 @@ void link_dma_desc(volatile lldesc_t *dmadesc, volatile lldesc_t *prevdmadesc, v
esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* conf) {
- port = I2S_NUM_0; /// override.
+ //port = I2S_NUM_0; /// override.
if(port < I2S_NUM_0 || port >= I2S_NUM_MAX) {
return ESP_ERR_INVALID_ARG;
@@ -176,7 +191,7 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* co
int irq_source;
// Initialize I2S0 peripheral
- //if (port == I2S_NUM_0) {
+ if (port == I2S_NUM_0) {
periph_module_reset(PERIPH_I2S0_MODULE);
periph_module_enable(PERIPH_I2S0_MODULE);
iomux_clock = I2S0O_WS_OUT_IDX;
@@ -193,8 +208,12 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* co
case I2S_PARALLEL_WIDTH_MAX:
return ESP_ERR_INVALID_ARG;
}
- /*
- } else {
+ }
+#ifdef ESP32_ORIG
+ // Can't compile if I2S1 if it doesn't exist with that hardware's IDF....
+ else {
+// I2S = &I2S1;
+
periph_module_reset(PERIPH_I2S1_MODULE);
periph_module_enable(PERIPH_I2S1_MODULE);
iomux_clock = I2S1O_WS_OUT_IDX;
@@ -212,12 +231,14 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* co
return ESP_ERR_INVALID_ARG;
}
}
- */
+#endif
+
// Setup GPIOs
int bus_width = get_bus_width(conf->sample_width);
// Setup I2S peripheral
- i2s_dev_t* dev = I2S;
+ i2s_dev_t* dev = I2S[port];
+ //dev_reset(dev);
// Setup GPIO's
@@ -245,7 +266,7 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* co
#ifdef ESP32_SXXX
dev->clkm_conf.clk_sel = 2; // esp32-s2 only
- dev->clkm_conf.clk_en = 1;
+ dev->clkm_conf.clk_en = 1;
#endif
#ifdef ESP32_ORIG
@@ -314,7 +335,7 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* co
// Device Reset
- dev_reset(dev);
+ dev_reset(dev);
dev->conf1.val = 0;
dev->conf1.tx_stop_en = 0;
@@ -329,25 +350,27 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* co
state->dmadesc_b = conf->lldesc_b;
state->i2s_interrupt_port_arg = port; // need to keep this somewhere in static memory for the ISR
- // Get ISR setup
- esp_err_t err = esp_intr_alloc(irq_source,
- (int)(ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1),
- irq_hndlr,
- &state->i2s_interrupt_port_arg, NULL);
-
- if(err) {
- return err;
- }
-
-
dev->timing.val = 0;
-
-
- // Setup interrupt handler which is focussed only on the (page 322 of Tech. Ref. Manual)
- // "I2S_OUT_EOF_INT: Triggered when rxlink has finished sending a packet"
- // ... whatever the hell that is supposed to mean... One massive linked list.
- dev->int_ena.out_eof = 1;
+ // We using the double buffering switch logic?
+ if (conf->int_ena_out_eof)
+ {
+ // Get ISR setup
+ esp_err_t err = esp_intr_alloc(irq_source,
+ (int)(ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1),
+ irq_hndlr,
+ &state->i2s_interrupt_port_arg, NULL);
+
+ if(err) {
+ return err;
+ }
+
+
+ // Setup interrupt handler which is focussed only on the (page 322 of Tech. Ref. Manual)
+ // "I2S_OUT_EOF_INT: Triggered when rxlink has finished sending a packet"
+ // ... whatever the hell that is supposed to mean... One massive linked list? So all pixels in the chain?
+ dev->int_ena.out_eof = 1;
+ }
return ESP_OK;
}
@@ -357,7 +380,7 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* co
return ESP_ERR_INVALID_ARG;
}
- i2s_dev_t* dev = I2S;
+ i2s_dev_t* dev = I2S[port];
// Stop all ongoing DMA operations
dev->out_link.stop = 1;
@@ -373,7 +396,7 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* co
return ESP_ERR_INVALID_ARG;
}
- i2s_dev_t* dev = I2S;
+ i2s_dev_t* dev = I2S[port];
// Configure DMA burst mode
@@ -390,16 +413,23 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* co
return ESP_OK;
}
-
+/*
i2s_dev_t* i2s_parallel_get_dev(i2s_port_t port) {
if(port < I2S_NUM_0 || port >= I2S_NUM_MAX) {
return NULL;
}
- return I2S; // HARCODE THIS TO RETURN &I2S0
-}
+#ifdef ESP32_ORIG
+if (port == I2S_NUM_1)
+ return &I2S1;
+#endif
+
+ return I2S0; // HARCODE THIS TO RETURN &I2S0
+}
+*/
// Double buffering flipping
// Flip to a buffer: 0 for bufa, 1 for bufb
+// dmadesc_a and dmadesc_b point to the same memory if double buffering isn't enabled.
void i2s_parallel_flip_to_buffer(i2s_port_t port, int buffer_id) {
if (i2s_state == NULL) {
@@ -418,9 +448,16 @@ void i2s_parallel_flip_to_buffer(i2s_port_t port, int buffer_id) {
i2s_state->dmadesc_b[i2s_state->desccount_b-1].qe.stqe_next = active_dma_chain;
// we're still shifting out the buffer, so it shouldn't be written to yet.
- previousBufferFree = false;
+ //previousBufferFree = false;
+ i2s_parallel_set_previous_buffer_not_free();
}
bool i2s_parallel_is_previous_buffer_free() {
return previousBufferFree;
}
+
+
+void i2s_parallel_set_previous_buffer_not_free() {
+ previousBufferFree = false;
+ previousBufferOutputLoopCount = 0;
+}
diff --git a/esp32_i2s_parallel_dma.h b/esp32_i2s_parallel_dma.h
index 2b16e24..1570fe2 100644
--- a/esp32_i2s_parallel_dma.h
+++ b/esp32_i2s_parallel_dma.h
@@ -41,6 +41,7 @@ typedef struct {
int desccount_b; // only used with double buffering
lldesc_t * lldesc_b; // only used with double buffering
bool clkphase; // Clock signal phase
+ bool int_ena_out_eof; // Do we raise an interrupt every time the DMA output loops? Don't do this unless we're doing double buffering!
} i2s_parallel_config_t;
static inline int i2s_parallel_get_memory_width(i2s_port_t port, i2s_parallel_cfg_bits_t width) {
@@ -72,7 +73,7 @@ void link_dma_desc(volatile lldesc_t *dmadesc, volatile lldesc_t *prevdmadesc, v
esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* conf);
esp_err_t i2s_parallel_send_dma(i2s_port_t port, lldesc_t* dma_descriptor);
esp_err_t i2s_parallel_stop_dma(i2s_port_t port);
-i2s_dev_t* i2s_parallel_get_dev(i2s_port_t port);
+//i2s_dev_t* i2s_parallel_get_dev(i2s_port_t port);
// For frame buffer flipping / double buffering
typedef struct {
@@ -83,6 +84,7 @@ typedef struct {
void i2s_parallel_flip_to_buffer(i2s_port_t port, int bufid);
bool i2s_parallel_is_previous_buffer_free();
+void i2s_parallel_set_previous_buffer_not_free();
// Callback function for when whole length of DMA chain has been sent out.
typedef void (*callback)(void);
diff --git a/examples/1_SimpleTestShapes/1_SimpleTestShapes.ino b/examples/1_SimpleTestShapes/1_SimpleTestShapes.ino
index cfcd768..db3b0d1 100644
--- a/examples/1_SimpleTestShapes/1_SimpleTestShapes.ino
+++ b/examples/1_SimpleTestShapes/1_SimpleTestShapes.ino
@@ -143,11 +143,11 @@ uint8_t wheelval = 0;
void loop() {
// animate by going through the colour wheel for the first two lines
- //drawText(wheelval);
- //wheelval +=1;
-
- //delay(20);
+ drawText(wheelval);
+ wheelval +=1;
+ delay(20);
+/*
drawText(0);
delay(2000);
dma_display->clearScreen();
@@ -161,5 +161,6 @@ void loop() {
delay(2000);
dma_display->fillScreen(myWHITE);
dma_display->clearScreen();
+ */
}
diff --git a/examples/README.md b/examples/README.md
index 9144af8..2acbd79 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -8,7 +8,6 @@
|BitmapIcons |Simple example of how to display a bitmap image to the display. |
|ChainedPanels |Popular example on how to use the 'VirtualDisplay' class to chain multiple LED Matrix Panels to form a much bigger display! Refer to the README within this example's folder! |
|ChainedPanelsAuroraDemo |As above, but showing a large trippy plasma animation. |
-|Smooth Double Buffer |Example of using a back-buffer (double buffering). Not useful in 99.9% of use-cases of this library. Uses double the SRAM as well. |
-|One_Quarter_1_4_ScanPanel |Using this library with a 32w x 16h 1/4 Scan LED Matrix Panel. Custom co-ordinate remapping logic required. |
-|One_Eighth_1_8_ScanPanel |Using this library with a 64w x 32h 1/8 Scan LED Matrix Panel. Custom co-ordinate remapping logic required.
+|One_Quarter_1_4_ScanPanel |Using this library with a 32w x 16h 1/4 Scan LED Matrix Panel. Custom co-ordinate remapping logic required. |
+|One_Eighth_1_8_ScanPanel |Using this library with a 64w x 32h 1/8 Scan LED Matrix Panel. Custom co-ordinate remapping logic required.
|PIO_TestPatterns |Non-Arduino example of how to display basic shapes. |