Reduce #338
This commit is contained in:
parent
9308b59445
commit
9d36abeeaf
6 changed files with 1299 additions and 1332 deletions
File diff suppressed because it is too large
Load diff
|
@ -8,14 +8,14 @@
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
|
|
||||||
//#include <Arduino.h>
|
// #include <Arduino.h>
|
||||||
#include "platforms/platform_detect.hpp"
|
#include "platforms/platform_detect.hpp"
|
||||||
|
|
||||||
#ifdef USE_GFX_ROOT
|
#ifdef USE_GFX_ROOT
|
||||||
#include <FastLED.h>
|
#include <FastLED.h>
|
||||||
#include "GFX.h" // Adafruit GFX core class -> https://github.com/mrfaptastic/GFX_Root
|
#include "GFX.h" // Adafruit GFX core class -> https://github.com/mrfaptastic/GFX_Root
|
||||||
#elif !defined NO_GFX
|
#elif !defined NO_GFX
|
||||||
#include "Adafruit_GFX.h" // Adafruit class with all the other stuff
|
#include "Adafruit_GFX.h" // Adafruit class with all the other stuff
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*******************************************************************************************
|
/*******************************************************************************************
|
||||||
|
@ -41,18 +41,17 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#ifndef MATRIX_WIDTH
|
#ifndef MATRIX_WIDTH
|
||||||
#define MATRIX_WIDTH 64 // Single panel of 64 pixel width
|
#define MATRIX_WIDTH 64 // Single panel of 64 pixel width
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MATRIX_HEIGHT
|
#ifndef MATRIX_HEIGHT
|
||||||
#define MATRIX_HEIGHT 32 // CHANGE THIS VALUE to 64 IF USING 64px HIGH panel(s) with E PIN
|
#define MATRIX_HEIGHT 32 // CHANGE THIS VALUE to 64 IF USING 64px HIGH panel(s) with E PIN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CHAIN_LENGTH
|
#ifndef CHAIN_LENGTH
|
||||||
#define CHAIN_LENGTH 1 // Number of modules chained together, i.e. 4 panels chained result in virtualmatrix 64x4=256 px long
|
#define CHAIN_LENGTH 1 // Number of modules chained together, i.e. 4 panels chained result in virtualmatrix 64x4=256 px long
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Interesting Fact: We end up using a uint16_t to send data in parallel to the HUB75... but
|
// Interesting Fact: We end up using a uint16_t to send data in parallel to the HUB75... but
|
||||||
// given we only map to 14 physical output wires/bits, we waste 2 bits.
|
// given we only map to 14 physical output wires/bits, we waste 2 bits.
|
||||||
|
|
||||||
|
@ -61,8 +60,8 @@
|
||||||
|
|
||||||
// keeping a check sine it was possibe to set it previously
|
// keeping a check sine it was possibe to set it previously
|
||||||
#ifdef MATRIX_ROWS_IN_PARALLEL
|
#ifdef MATRIX_ROWS_IN_PARALLEL
|
||||||
#pragma message "You are not supposed to set MATRIX_ROWS_IN_PARALLEL. Setting it back to default."
|
#pragma message "You are not supposed to set MATRIX_ROWS_IN_PARALLEL. Setting it back to default."
|
||||||
#undef MATRIX_ROWS_IN_PARALLEL
|
#undef MATRIX_ROWS_IN_PARALLEL
|
||||||
#endif
|
#endif
|
||||||
#define MATRIX_ROWS_IN_PARALLEL 2
|
#define MATRIX_ROWS_IN_PARALLEL 2
|
||||||
|
|
||||||
|
@ -70,14 +69,14 @@
|
||||||
// can be extended to offer deeper colors, or
|
// can be extended to offer deeper colors, or
|
||||||
// might be reduced to save DMA RAM
|
// might be reduced to save DMA RAM
|
||||||
#ifdef PIXEL_COLOUR_DEPTH_BITS
|
#ifdef PIXEL_COLOUR_DEPTH_BITS
|
||||||
#define PIXEL_COLOR_DEPTH_BITS PIXEL_COLOUR_DEPTH_BITS
|
#define PIXEL_COLOR_DEPTH_BITS PIXEL_COLOUR_DEPTH_BITS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//support backwarts compatibility
|
// support backwarts compatibility
|
||||||
#ifdef PIXEL_COLOR_DEPTH_BITS
|
#ifdef PIXEL_COLOR_DEPTH_BITS
|
||||||
#define PIXEL_COLOR_DEPTH_BITS_DEFAULT PIXEL_COLOR_DEPTH_BITS
|
#define PIXEL_COLOR_DEPTH_BITS_DEFAULT PIXEL_COLOR_DEPTH_BITS
|
||||||
#else
|
#else
|
||||||
#define PIXEL_COLOR_DEPTH_BITS_DEFAULT 8
|
#define PIXEL_COLOR_DEPTH_BITS_DEFAULT 8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PIXEL_COLOR_DEPTH_BITS_MAX 12
|
#define PIXEL_COLOR_DEPTH_BITS_MAX 12
|
||||||
|
@ -89,27 +88,27 @@
|
||||||
|
|
||||||
// Panel Upper half RGB (numbering according to order in DMA gpio_bus configuration)
|
// Panel Upper half RGB (numbering according to order in DMA gpio_bus configuration)
|
||||||
#define BITS_RGB1_OFFSET 0 // Start point of RGB_X1 bits
|
#define BITS_RGB1_OFFSET 0 // Start point of RGB_X1 bits
|
||||||
#define BIT_R1 (1<<0)
|
#define BIT_R1 (1 << 0)
|
||||||
#define BIT_G1 (1<<1)
|
#define BIT_G1 (1 << 1)
|
||||||
#define BIT_B1 (1<<2)
|
#define BIT_B1 (1 << 2)
|
||||||
|
|
||||||
// Panel Lower half RGB
|
// Panel Lower half RGB
|
||||||
#define BITS_RGB2_OFFSET 3 // Start point of RGB_X2 bits
|
#define BITS_RGB2_OFFSET 3 // Start point of RGB_X2 bits
|
||||||
#define BIT_R2 (1<<3)
|
#define BIT_R2 (1 << 3)
|
||||||
#define BIT_G2 (1<<4)
|
#define BIT_G2 (1 << 4)
|
||||||
#define BIT_B2 (1<<5)
|
#define BIT_B2 (1 << 5)
|
||||||
|
|
||||||
// Panel Control Signals
|
// Panel Control Signals
|
||||||
#define BIT_LAT (1<<6)
|
#define BIT_LAT (1 << 6)
|
||||||
#define BIT_OE (1<<7)
|
#define BIT_OE (1 << 7)
|
||||||
|
|
||||||
// Panel GPIO Pin Addresses (A, B, C, D etc..)
|
// Panel GPIO Pin Addresses (A, B, C, D etc..)
|
||||||
#define BITS_ADDR_OFFSET 8 // Start point of address bits
|
#define BITS_ADDR_OFFSET 8 // Start point of address bits
|
||||||
#define BIT_A (1<<8)
|
#define BIT_A (1 << 8)
|
||||||
#define BIT_B (1<<9)
|
#define BIT_B (1 << 9)
|
||||||
#define BIT_C (1<<10)
|
#define BIT_C (1 << 10)
|
||||||
#define BIT_D (1<<11)
|
#define BIT_D (1 << 11)
|
||||||
#define BIT_E (1<<12)
|
#define BIT_E (1 << 12)
|
||||||
|
|
||||||
// BitMasks are pre-computed based on the above #define's for performance.
|
// BitMasks are pre-computed based on the above #define's for performance.
|
||||||
#define BITMASK_RGB1_CLEAR (0b1111111111111000) // inverted bitmask for R1G1B1 bit in pixel vector
|
#define BITMASK_RGB1_CLEAR (0b1111111111111000) // inverted bitmask for R1G1B1 bit in pixel vector
|
||||||
|
@ -129,7 +128,8 @@
|
||||||
/** @brief - Structure holds raw DMA data to drive TWO full rows of pixels spanning through all chained modules
|
/** @brief - Structure holds raw DMA data to drive TWO full rows of pixels spanning through all chained modules
|
||||||
* Note: sizeof(data) must be multiple of 32 bits, as ESP32 DMA linked list buffer address pointer must be word-aligned
|
* Note: sizeof(data) must be multiple of 32 bits, as ESP32 DMA linked list buffer address pointer must be word-aligned
|
||||||
*/
|
*/
|
||||||
struct rowBitStruct {
|
struct rowBitStruct
|
||||||
|
{
|
||||||
const size_t width;
|
const size_t width;
|
||||||
const uint8_t colour_depth;
|
const uint8_t colour_depth;
|
||||||
const bool double_buff;
|
const bool double_buff;
|
||||||
|
@ -143,24 +143,34 @@ struct rowBitStruct {
|
||||||
* default - returns full data vector size for a SINGLE buff
|
* default - returns full data vector size for a SINGLE buff
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
size_t size(uint8_t _dpth=0 ) { if (!_dpth) _dpth = colour_depth; return width * _dpth * sizeof(ESP32_I2S_DMA_STORAGE_TYPE); };
|
size_t size(uint8_t _dpth = 0)
|
||||||
|
{
|
||||||
|
if (!_dpth)
|
||||||
|
_dpth = colour_depth;
|
||||||
|
return width * _dpth * sizeof(ESP32_I2S_DMA_STORAGE_TYPE);
|
||||||
|
};
|
||||||
|
|
||||||
/** @brief - returns pointer to the row's data vector beginning at pixel[0] for _dpth colour bit
|
/** @brief - returns pointer to the row's data vector beginning at pixel[0] for _dpth colour bit
|
||||||
* default - returns pointer to the data vector's head
|
* default - returns pointer to the data vector's head
|
||||||
* NOTE: this call might be very slow in loops. Due to poor instruction caching in esp32 it might be required a reread from flash
|
* NOTE: this call might be very slow in loops. Due to poor instruction caching in esp32 it might be required a reread from flash
|
||||||
* every loop cycle, better use inlined #define instead in such cases
|
* every loop cycle, better use inlined #define instead in such cases
|
||||||
*/
|
*/
|
||||||
inline ESP32_I2S_DMA_STORAGE_TYPE* getDataPtr(const uint8_t _dpth=0, const bool buff_id=0) { return &(data[_dpth*width + buff_id*(width*colour_depth)]); };
|
// inline ESP32_I2S_DMA_STORAGE_TYPE* getDataPtr(const uint8_t _dpth=0, const bool buff_id=0) { return &(data[_dpth*width + buff_id*(width*colour_depth)]); };
|
||||||
|
|
||||||
|
// BUFFER ID VALUE IS NOW IGNORED!!!!
|
||||||
|
inline ESP32_I2S_DMA_STORAGE_TYPE *getDataPtr(const uint8_t _dpth = 0, const bool buff_id = 0) { return &(data[_dpth * width]); };
|
||||||
|
|
||||||
// constructor - allocates DMA-capable memory to hold the struct data
|
// constructor - allocates DMA-capable memory to hold the struct data
|
||||||
rowBitStruct(const size_t _width, const uint8_t _depth, const bool _dbuff) : width(_width), colour_depth(_depth), double_buff(_dbuff) {
|
rowBitStruct(const size_t _width, const uint8_t _depth, const bool _dbuff) : width(_width), colour_depth(_depth), double_buff(_dbuff)
|
||||||
|
{
|
||||||
|
|
||||||
//#if defined(SPIRAM_FRAMEBUFFER) && defined (CONFIG_IDF_TARGET_ESP32S3)
|
// #if defined(SPIRAM_FRAMEBUFFER) && defined (CONFIG_IDF_TARGET_ESP32S3)
|
||||||
#if defined(SPIRAM_DMA_BUFFER)
|
#if defined(SPIRAM_DMA_BUFFER)
|
||||||
// #pragma message "Enabling PSRAM / SPIRAM for frame buffer."
|
|
||||||
// ESP_LOGI("rowBitStruct", "Allocated DMA BitBuffer from PSRAM (SPIRAM)");
|
// data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_aligned_alloc(64, size()+size()*double_buff, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||||
//data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_malloc( size()+size()*double_buff, MALLOC_CAP_SPIRAM);
|
|
||||||
data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_aligned_alloc(64, size()+size()*double_buff, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
// No longer have double buffer in the same struct - have a different struct
|
||||||
|
data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_aligned_alloc(64, size(), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||||
/*
|
/*
|
||||||
if (!psramFound())
|
if (!psramFound())
|
||||||
{
|
{
|
||||||
|
@ -168,15 +178,16 @@ struct rowBitStruct {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
#else
|
#else
|
||||||
data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_malloc( size()+size()*double_buff, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
|
// data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_malloc( size()+size()*double_buff, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
|
||||||
|
|
||||||
|
// No longer have double buffer in the same struct - have a different struct
|
||||||
|
data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_malloc(size(), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
|
||||||
// ESP_LOGI("rowBitStruct", "Allocated DMA BitBuffer from regular (and limited) SRAM");
|
// ESP_LOGI("rowBitStruct", "Allocated DMA BitBuffer from regular (and limited) SRAM");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
~rowBitStruct() { delete data;}
|
~rowBitStruct() { delete data; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* frameStruct
|
/* frameStruct
|
||||||
* Note: A 'frameStruct' contains ALL the data for a full-frame (i.e. BOTH 2x16-row frames are
|
* Note: A 'frameStruct' contains ALL the data for a full-frame (i.e. BOTH 2x16-row frames are
|
||||||
* are contained in parallel within the one uint16_t that is sent in parallel to the HUB75).
|
* are contained in parallel within the one uint16_t that is sent in parallel to the HUB75).
|
||||||
|
@ -184,13 +195,14 @@ struct rowBitStruct {
|
||||||
* This structure isn't actually allocated in one memory block anymore, as the library now allocates
|
* This structure isn't actually allocated in one memory block anymore, as the library now allocates
|
||||||
* memory per row (per rowBits) instead.
|
* memory per row (per rowBits) instead.
|
||||||
*/
|
*/
|
||||||
struct frameStruct {
|
struct frameStruct
|
||||||
uint8_t rows=0; // number of rows held in current frame, not used actually, just to keep the idea of struct
|
{
|
||||||
std::vector<std::shared_ptr<rowBitStruct> > rowBits;
|
uint8_t rows = 0; // number of rows held in current frame, not used actually, just to keep the idea of struct
|
||||||
|
std::vector<std::shared_ptr<rowBitStruct>> rowBits;
|
||||||
};
|
};
|
||||||
|
|
||||||
/***************************************************************************************/
|
/***************************************************************************************/
|
||||||
//C/p'ed from https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/
|
// C/p'ed from https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/
|
||||||
// Example calculator: https://gist.github.com/mathiasvr/19ce1d7b6caeab230934080ae1f1380e
|
// Example calculator: https://gist.github.com/mathiasvr/19ce1d7b6caeab230934080ae1f1380e
|
||||||
// need to make sure this would end up in RAM for fastest access
|
// need to make sure this would end up in RAM for fastest access
|
||||||
#ifndef NO_CIE1931
|
#ifndef NO_CIE1931
|
||||||
|
@ -200,7 +212,7 @@ static const uint8_t DRAM_ATTR lumConvTab[]={
|
||||||
*/
|
*/
|
||||||
// This is 16-bit version of the table,
|
// This is 16-bit version of the table,
|
||||||
// the constants taken from the example in the article above, each entries subtracted from 65535:
|
// the constants taken from the example in the article above, each entries subtracted from 65535:
|
||||||
static const uint16_t DRAM_ATTR lumConvTab[]={
|
static const uint16_t DRAM_ATTR lumConvTab[] = {
|
||||||
0, 27, 56, 84, 113, 141, 170, 198, 227, 255, 284, 312, 340, 369, 397, 426,
|
0, 27, 56, 84, 113, 141, 170, 198, 227, 255, 284, 312, 340, 369, 397, 426,
|
||||||
454, 483, 511, 540, 568, 597, 626, 657, 688, 720, 754, 788, 824, 860, 898, 936,
|
454, 483, 511, 540, 568, 597, 626, 657, 688, 720, 754, 788, 824, 860, 898, 936,
|
||||||
976, 1017, 1059, 1102, 1146, 1191, 1238, 1286, 1335, 1385, 1436, 1489, 1543, 1598, 1655, 1713,
|
976, 1017, 1059, 1102, 1146, 1191, 1238, 1286, 1335, 1385, 1436, 1489, 1543, 1598, 1655, 1713,
|
||||||
|
@ -216,8 +228,7 @@ static const uint16_t DRAM_ATTR lumConvTab[]={
|
||||||
31946, 32360, 32777, 33197, 33622, 34049, 34481, 34916, 35354, 35797, 36243, 36692, 37146, 37603, 38064, 38528,
|
31946, 32360, 32777, 33197, 33622, 34049, 34481, 34916, 35354, 35797, 36243, 36692, 37146, 37603, 38064, 38528,
|
||||||
38996, 39469, 39945, 40424, 40908, 41395, 41886, 42382, 42881, 43383, 43890, 44401, 44916, 45434, 45957, 46484,
|
38996, 39469, 39945, 40424, 40908, 41395, 41886, 42382, 42881, 43383, 43890, 44401, 44916, 45434, 45957, 46484,
|
||||||
47014, 47549, 48088, 48630, 49177, 49728, 50283, 50842, 51406, 51973, 52545, 53120, 53700, 54284, 54873, 55465,
|
47014, 47549, 48088, 48630, 49177, 49728, 50283, 50842, 51406, 51973, 52545, 53120, 53700, 54284, 54873, 55465,
|
||||||
56062, 56663, 57269, 57878, 58492, 59111, 59733, 60360, 60992, 61627, 62268, 62912, 63561, 64215, 64873, 65535
|
56062, 56663, 57269, 57878, 58492, 59111, 59733, 60360, 60992, 61627, 62268, 62912, 63561, 64215, 64873, 65535};
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @brief - configuration values for HUB75_I2S driver
|
/** @brief - configuration values for HUB75_I2S driver
|
||||||
|
@ -225,19 +236,33 @@ static const uint16_t DRAM_ATTR lumConvTab[]={
|
||||||
* an initialization values when creating an instance of MatrixPanel_I2S_DMA object.
|
* an initialization values when creating an instance of MatrixPanel_I2S_DMA object.
|
||||||
* All params have it's default values.
|
* All params have it's default values.
|
||||||
*/
|
*/
|
||||||
struct HUB75_I2S_CFG {
|
struct HUB75_I2S_CFG
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumeration of hardware-specific chips
|
* Enumeration of hardware-specific chips
|
||||||
* used to drive matrix modules
|
* used to drive matrix modules
|
||||||
*/
|
*/
|
||||||
enum shift_driver {SHIFTREG=0, FM6124, FM6126A, ICN2038S, MBI5124, SM5266P};
|
enum shift_driver
|
||||||
|
{
|
||||||
|
SHIFTREG = 0,
|
||||||
|
FM6124,
|
||||||
|
FM6126A,
|
||||||
|
ICN2038S,
|
||||||
|
MBI5124,
|
||||||
|
SM5266P
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I2S clock speed selector
|
* I2S clock speed selector
|
||||||
*/
|
*/
|
||||||
enum clk_speed {HZ_8M=8000000, HZ_10M=10000000, HZ_15M=15000000, HZ_20M=20000000};
|
enum clk_speed
|
||||||
|
{
|
||||||
|
HZ_8M = 8000000,
|
||||||
|
HZ_10M = 10000000,
|
||||||
|
HZ_15M = 15000000,
|
||||||
|
HZ_20M = 20000000
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Members must be in order of declaration or it breaks Arduino compiling due to strict checking.
|
// Members must be in order of declaration or it breaks Arduino compiling due to strict checking.
|
||||||
|
@ -253,7 +278,10 @@ struct HUB75_I2S_CFG {
|
||||||
uint16_t chain_length;
|
uint16_t chain_length;
|
||||||
|
|
||||||
// GPIO Mapping
|
// GPIO Mapping
|
||||||
struct i2s_pins{ int8_t r1, g1, b1, r2, g2, b2, a, b, c, d, e, lat, oe, clk; } gpio;
|
struct i2s_pins
|
||||||
|
{
|
||||||
|
int8_t r1, g1, b1, r2, g2, b2, a, b, c, d, e, lat, oe, clk;
|
||||||
|
} gpio;
|
||||||
|
|
||||||
// Matrix driver chip type - default is a plain shift register
|
// Matrix driver chip type - default is a plain shift register
|
||||||
shift_driver driver;
|
shift_driver driver;
|
||||||
|
@ -286,77 +314,70 @@ struct HUB75_I2S_CFG {
|
||||||
// Minimum refresh / scan rate needs to be configured on start due to LSBMSB_TRANSITION_BIT calculation in allocateDMAmemory()
|
// Minimum refresh / scan rate needs to be configured on start due to LSBMSB_TRANSITION_BIT calculation in allocateDMAmemory()
|
||||||
uint8_t min_refresh_rate;
|
uint8_t min_refresh_rate;
|
||||||
|
|
||||||
|
|
||||||
// struct constructor
|
// struct constructor
|
||||||
HUB75_I2S_CFG (
|
HUB75_I2S_CFG(
|
||||||
uint16_t _w = MATRIX_WIDTH,
|
uint16_t _w = MATRIX_WIDTH,
|
||||||
uint16_t _h = MATRIX_HEIGHT,
|
uint16_t _h = MATRIX_HEIGHT,
|
||||||
uint16_t _chain = CHAIN_LENGTH,
|
uint16_t _chain = CHAIN_LENGTH,
|
||||||
i2s_pins _pinmap = {
|
i2s_pins _pinmap = {
|
||||||
R1_PIN_DEFAULT, G1_PIN_DEFAULT, B1_PIN_DEFAULT, R2_PIN_DEFAULT, G2_PIN_DEFAULT, B2_PIN_DEFAULT,
|
R1_PIN_DEFAULT, G1_PIN_DEFAULT, B1_PIN_DEFAULT, R2_PIN_DEFAULT, G2_PIN_DEFAULT, B2_PIN_DEFAULT,
|
||||||
A_PIN_DEFAULT, B_PIN_DEFAULT, C_PIN_DEFAULT, D_PIN_DEFAULT, E_PIN_DEFAULT,
|
A_PIN_DEFAULT, B_PIN_DEFAULT, C_PIN_DEFAULT, D_PIN_DEFAULT, E_PIN_DEFAULT,
|
||||||
LAT_PIN_DEFAULT, OE_PIN_DEFAULT, CLK_PIN_DEFAULT },
|
LAT_PIN_DEFAULT, OE_PIN_DEFAULT, CLK_PIN_DEFAULT},
|
||||||
shift_driver _drv = SHIFTREG,
|
shift_driver _drv = SHIFTREG, bool _dbuff = false, clk_speed _i2sspeed = HZ_15M,
|
||||||
bool _dbuff = false,
|
|
||||||
clk_speed _i2sspeed = HZ_15M,
|
|
||||||
uint8_t _latblk = DEFAULT_LAT_BLANKING, // Anything > 1 seems to cause artefacts on ICS panels
|
uint8_t _latblk = DEFAULT_LAT_BLANKING, // Anything > 1 seems to cause artefacts on ICS panels
|
||||||
bool _clockphase = true,
|
bool _clockphase = true, uint16_t _min_refresh_rate = 60, uint8_t _pixel_color_depth_bits = PIXEL_COLOR_DEPTH_BITS_DEFAULT) : mx_width(_w), mx_height(_h), chain_length(_chain), gpio(_pinmap), driver(_drv), double_buff(_dbuff), i2sspeed(_i2sspeed), latch_blanking(_latblk), clkphase(_clockphase), min_refresh_rate(_min_refresh_rate)
|
||||||
uint16_t _min_refresh_rate = 60,
|
|
||||||
uint8_t _pixel_color_depth_bits = PIXEL_COLOR_DEPTH_BITS_DEFAULT
|
|
||||||
) : mx_width(_w),
|
|
||||||
mx_height(_h),
|
|
||||||
chain_length(_chain),
|
|
||||||
gpio(_pinmap),
|
|
||||||
driver(_drv),
|
|
||||||
double_buff(_dbuff),
|
|
||||||
i2sspeed(_i2sspeed),
|
|
||||||
latch_blanking(_latblk),
|
|
||||||
clkphase(_clockphase),
|
|
||||||
min_refresh_rate(_min_refresh_rate)
|
|
||||||
{
|
{
|
||||||
setPixelColorDepthBits(_pixel_color_depth_bits);
|
setPixelColorDepthBits(_pixel_color_depth_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
//pixel_color_depth_bits must be between 12 and 2, and mask_offset needs to be calculated accordently
|
// pixel_color_depth_bits must be between 12 and 2, and mask_offset needs to be calculated accordently
|
||||||
//so they have to be private with getter (and setter)
|
// so they have to be private with getter (and setter)
|
||||||
void setPixelColorDepthBits(uint8_t _pixel_color_depth_bits){
|
void setPixelColorDepthBits(uint8_t _pixel_color_depth_bits)
|
||||||
if(_pixel_color_depth_bits > PIXEL_COLOR_DEPTH_BITS_MAX || _pixel_color_depth_bits < 2){
|
{
|
||||||
|
if (_pixel_color_depth_bits > PIXEL_COLOR_DEPTH_BITS_MAX || _pixel_color_depth_bits < 2)
|
||||||
|
{
|
||||||
|
|
||||||
if(_pixel_color_depth_bits > PIXEL_COLOR_DEPTH_BITS_MAX){
|
if (_pixel_color_depth_bits > PIXEL_COLOR_DEPTH_BITS_MAX)
|
||||||
|
{
|
||||||
pixel_color_depth_bits = PIXEL_COLOR_DEPTH_BITS_MAX;
|
pixel_color_depth_bits = PIXEL_COLOR_DEPTH_BITS_MAX;
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
pixel_color_depth_bits = 2;
|
pixel_color_depth_bits = 2;
|
||||||
}
|
}
|
||||||
ESP_LOGW("HUB75_I2S_CFG", "Invalid pixel_color_depth_bits (%d): 2 <= pixel_color_depth_bits <= %d, choosing nearest valid %d", _pixel_color_depth_bits, PIXEL_COLOR_DEPTH_BITS_MAX, pixel_color_depth_bits);
|
ESP_LOGW("HUB75_I2S_CFG", "Invalid pixel_color_depth_bits (%d): 2 <= pixel_color_depth_bits <= %d, choosing nearest valid %d", _pixel_color_depth_bits, PIXEL_COLOR_DEPTH_BITS_MAX, pixel_color_depth_bits);
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
pixel_color_depth_bits = _pixel_color_depth_bits;
|
pixel_color_depth_bits = _pixel_color_depth_bits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getPixelColorDepthBits(){
|
uint8_t getPixelColorDepthBits()
|
||||||
|
{
|
||||||
return pixel_color_depth_bits;
|
return pixel_color_depth_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//these were priviously handeld as defines (PIXEL_COLOR_DEPTH_BITS, MASK_OFFSET)
|
// these were priviously handeld as defines (PIXEL_COLOR_DEPTH_BITS, MASK_OFFSET)
|
||||||
//to make it changable after compilation, it is now part of the config
|
// to make it changable after compilation, it is now part of the config
|
||||||
uint8_t pixel_color_depth_bits;
|
uint8_t pixel_color_depth_bits;
|
||||||
}; // end of structure HUB75_I2S_CFG
|
}; // end of structure HUB75_I2S_CFG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************/
|
/***************************************************************************************/
|
||||||
#ifdef USE_GFX_ROOT
|
#ifdef USE_GFX_ROOT
|
||||||
class MatrixPanel_I2S_DMA : public GFX {
|
class MatrixPanel_I2S_DMA : public GFX
|
||||||
|
{
|
||||||
#elif !defined NO_GFX
|
#elif !defined NO_GFX
|
||||||
class MatrixPanel_I2S_DMA : public Adafruit_GFX {
|
class MatrixPanel_I2S_DMA : public Adafruit_GFX
|
||||||
|
{
|
||||||
#else
|
#else
|
||||||
class MatrixPanel_I2S_DMA {
|
class MatrixPanel_I2S_DMA
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ------- PUBLIC -------
|
// ------- PUBLIC -------
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MatrixPanel_I2S_DMA
|
* MatrixPanel_I2S_DMA
|
||||||
*
|
*
|
||||||
|
@ -369,7 +390,8 @@ class MatrixPanel_I2S_DMA {
|
||||||
#elif !defined NO_GFX
|
#elif !defined NO_GFX
|
||||||
: Adafruit_GFX(MATRIX_WIDTH, MATRIX_HEIGHT)
|
: Adafruit_GFX(MATRIX_WIDTH, MATRIX_HEIGHT)
|
||||||
#endif
|
#endif
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MatrixPanel_I2S_DMA
|
* MatrixPanel_I2S_DMA
|
||||||
|
@ -377,21 +399,24 @@ class MatrixPanel_I2S_DMA {
|
||||||
* @param {HUB75_I2S_CFG} opts : structure with matrix configuration
|
* @param {HUB75_I2S_CFG} opts : structure with matrix configuration
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
MatrixPanel_I2S_DMA(const HUB75_I2S_CFG& opts)
|
MatrixPanel_I2S_DMA(const HUB75_I2S_CFG &opts)
|
||||||
#ifdef USE_GFX_ROOT
|
#ifdef USE_GFX_ROOT
|
||||||
: GFX(opts.mx_width*opts.chain_length, opts.mx_height)
|
: GFX(opts.mx_width * opts.chain_length, opts.mx_height)
|
||||||
#elif !defined NO_GFX
|
#elif !defined NO_GFX
|
||||||
: Adafruit_GFX(opts.mx_width*opts.chain_length, opts.mx_height)
|
: Adafruit_GFX(opts.mx_width * opts.chain_length, opts.mx_height)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
setCfg(opts);
|
setCfg(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Propagate the DMA pin configuration, allocate DMA buffs and start data output, initially blank */
|
/* Propagate the DMA pin configuration, allocate DMA buffs and start data output, initially blank */
|
||||||
bool begin(){
|
bool begin()
|
||||||
|
{
|
||||||
|
|
||||||
if (initialized) return true; // we don't do this twice or more!
|
if (initialized)
|
||||||
if(!config_set) return false;
|
return true; // we don't do this twice or more!
|
||||||
|
if (!config_set)
|
||||||
|
return false;
|
||||||
|
|
||||||
ESP_LOGI("begin()", "Using GPIO %d for R1_PIN", m_cfg.gpio.r1);
|
ESP_LOGI("begin()", "Using GPIO %d for R1_PIN", m_cfg.gpio.r1);
|
||||||
ESP_LOGI("begin()", "Using GPIO %d for G1_PIN", m_cfg.gpio.g1);
|
ESP_LOGI("begin()", "Using GPIO %d for G1_PIN", m_cfg.gpio.g1);
|
||||||
|
@ -408,52 +433,52 @@ class MatrixPanel_I2S_DMA {
|
||||||
ESP_LOGI("begin()", "Using GPIO %d for OE_PIN", m_cfg.gpio.oe);
|
ESP_LOGI("begin()", "Using GPIO %d for OE_PIN", m_cfg.gpio.oe);
|
||||||
ESP_LOGI("begin()", "Using GPIO %d for CLK_PIN", m_cfg.gpio.clk);
|
ESP_LOGI("begin()", "Using GPIO %d for CLK_PIN", m_cfg.gpio.clk);
|
||||||
|
|
||||||
|
|
||||||
// initialize some specific panel drivers
|
// initialize some specific panel drivers
|
||||||
if (m_cfg.driver)
|
if (m_cfg.driver)
|
||||||
shiftDriver(m_cfg);
|
shiftDriver(m_cfg);
|
||||||
|
|
||||||
#if defined(SPIRAM_DMA_BUFFER)
|
#if defined(SPIRAM_DMA_BUFFER)
|
||||||
// Trick library into dropping colour depth slightly when using PSRAM.
|
// Trick library into dropping colour depth slightly when using PSRAM.
|
||||||
// Actual output clockrate override occurs in configureDMA
|
// Actual output clockrate override occurs in configureDMA
|
||||||
m_cfg.i2sspeed = HUB75_I2S_CFG::HZ_8M;
|
m_cfg.i2sspeed = HUB75_I2S_CFG::HZ_8M;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* As DMA buffers are dynamically allocated, we must allocated in begin()
|
/* As DMA buffers are dynamically allocated, we must allocated in begin()
|
||||||
* Ref: https://github.com/espressif/arduino-esp32/issues/831
|
* Ref: https://github.com/espressif/arduino-esp32/issues/831
|
||||||
*/
|
*/
|
||||||
if ( !allocateDMAmemory() ) { return false; } // couldn't even get the basic ram required.
|
if (!allocateDMAmemory())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
} // couldn't even get the basic ram required.
|
||||||
|
|
||||||
// Flush the DMA buffers prior to configuring DMA - Avoid visual artefacts on boot.
|
// Flush the DMA buffers prior to configuring DMA - Avoid visual artefacts on boot.
|
||||||
resetbuffers(); // Must fill the DMA buffer with the initial output bit sequence or the panel will display garbage
|
resetbuffers(); // Must fill the DMA buffer with the initial output bit sequence or the panel will display garbage
|
||||||
|
|
||||||
// Setup the ESP32 DMA Engine. Sprite_TM built this stuff.
|
// Setup the ESP32 DMA Engine. Sprite_TM built this stuff.
|
||||||
configureDMA(m_cfg); //DMA and I2S configuration and setup
|
configureDMA(m_cfg); // DMA and I2S configuration and setup
|
||||||
|
|
||||||
//showDMABuffer(); // show backbuf_id of 0
|
// showDMABuffer(); // show backbuf_id of 0
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized)
|
||||||
|
{
|
||||||
ESP_LOGE("being()", "MatrixPanel_I2S_DMA::begin() failed!");
|
ESP_LOGE("being()", "MatrixPanel_I2S_DMA::begin() failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return initialized;
|
return initialized;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obj destructor
|
// Obj destructor
|
||||||
~MatrixPanel_I2S_DMA(){
|
~MatrixPanel_I2S_DMA()
|
||||||
|
{
|
||||||
|
|
||||||
dma_bus.release();
|
dma_bus.release();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* overload for compatibility
|
* overload for compatibility
|
||||||
*/
|
*/
|
||||||
bool begin(int r1, int g1 = G1_PIN_DEFAULT, int b1 = B1_PIN_DEFAULT, int r2 = R2_PIN_DEFAULT, int g2 = G2_PIN_DEFAULT, int b2 = B2_PIN_DEFAULT, int a = A_PIN_DEFAULT, int b = B_PIN_DEFAULT, int c = C_PIN_DEFAULT, int d = D_PIN_DEFAULT, int e = E_PIN_DEFAULT, int lat = LAT_PIN_DEFAULT, int oe = OE_PIN_DEFAULT, int clk = CLK_PIN_DEFAULT);
|
bool begin(int r1, int g1 = G1_PIN_DEFAULT, int b1 = B1_PIN_DEFAULT, int r2 = R2_PIN_DEFAULT, int g2 = G2_PIN_DEFAULT, int b2 = B2_PIN_DEFAULT, int a = A_PIN_DEFAULT, int b = B_PIN_DEFAULT, int c = C_PIN_DEFAULT, int d = D_PIN_DEFAULT, int e = E_PIN_DEFAULT, int lat = LAT_PIN_DEFAULT, int oe = OE_PIN_DEFAULT, int clk = CLK_PIN_DEFAULT);
|
||||||
bool begin(const HUB75_I2S_CFG& cfg);
|
bool begin(const HUB75_I2S_CFG &cfg);
|
||||||
|
|
||||||
// Adafruit's BASIC DRAW API (565 colour format)
|
// Adafruit's BASIC DRAW API (565 colour format)
|
||||||
virtual void drawPixel(int16_t x, int16_t y, uint16_t color); // overwrite adafruit implementation
|
virtual void drawPixel(int16_t x, int16_t y, uint16_t color); // overwrite adafruit implementation
|
||||||
|
@ -462,82 +487,88 @@ class MatrixPanel_I2S_DMA {
|
||||||
/**
|
/**
|
||||||
* A wrapper to fill whatever selected DMA buffer / screen with black
|
* A wrapper to fill whatever selected DMA buffer / screen with black
|
||||||
*/
|
*/
|
||||||
inline void clearScreen() { updateMatrixDMABuffer(0,0,0); };
|
inline void clearScreen() { updateMatrixDMABuffer(0, 0, 0); };
|
||||||
|
|
||||||
#ifndef NO_FAST_FUNCTIONS
|
#ifndef NO_FAST_FUNCTIONS
|
||||||
/**
|
/**
|
||||||
* @brief - override Adafruit's FastVLine
|
* @brief - override Adafruit's FastVLine
|
||||||
* this works faster than multiple consecutive pixel by pixel drawPixel() call
|
* this works faster than multiple consecutive pixel by pixel drawPixel() call
|
||||||
*/
|
*/
|
||||||
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color){
|
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
|
||||||
|
{
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
color565to888(color, r, g, b);
|
color565to888(color, r, g, b);
|
||||||
startWrite();
|
startWrite();
|
||||||
|
|
||||||
int16_t w = 1;
|
int16_t w = 1;
|
||||||
transform( x, y, w, h);
|
transform(x, y, w, h);
|
||||||
if( h > w )
|
if (h > w)
|
||||||
vlineDMA( x, y, h, r, g, b);
|
vlineDMA(x, y, h, r, g, b);
|
||||||
else
|
else
|
||||||
hlineDMA( x, y, w, r, g, b);
|
hlineDMA(x, y, w, r, g, b);
|
||||||
|
|
||||||
endWrite();
|
endWrite();
|
||||||
}
|
}
|
||||||
// rgb888 overload
|
// rgb888 overload
|
||||||
virtual inline void drawFastVLine(int16_t x, int16_t y, int16_t h, uint8_t r, uint8_t g, uint8_t b){
|
virtual inline void drawFastVLine(int16_t x, int16_t y, int16_t h, uint8_t r, uint8_t g, uint8_t b)
|
||||||
|
{
|
||||||
int16_t w = 1;
|
int16_t w = 1;
|
||||||
transform( x, y, w, h);
|
transform(x, y, w, h);
|
||||||
if( h > w )
|
if (h > w)
|
||||||
vlineDMA( x, y, h, r, g, b);
|
vlineDMA(x, y, h, r, g, b);
|
||||||
else
|
else
|
||||||
hlineDMA( x, y, w, r, g, b);
|
hlineDMA(x, y, w, r, g, b);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief - override Adafruit's FastHLine
|
* @brief - override Adafruit's FastHLine
|
||||||
* this works faster than multiple consecutive pixel by pixel drawPixel() call
|
* this works faster than multiple consecutive pixel by pixel drawPixel() call
|
||||||
*/
|
*/
|
||||||
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color){
|
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
|
||||||
|
{
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
color565to888(color, r, g, b);
|
color565to888(color, r, g, b);
|
||||||
startWrite();
|
startWrite();
|
||||||
|
|
||||||
int16_t h = 1;
|
int16_t h = 1;
|
||||||
transform( x, y, w, h);
|
transform(x, y, w, h);
|
||||||
if( h > w )
|
if (h > w)
|
||||||
vlineDMA( x, y, h, r, g, b);
|
vlineDMA(x, y, h, r, g, b);
|
||||||
else
|
else
|
||||||
hlineDMA( x, y, w, r, g, b);
|
hlineDMA(x, y, w, r, g, b);
|
||||||
|
|
||||||
endWrite();
|
endWrite();
|
||||||
}
|
}
|
||||||
// rgb888 overload
|
// rgb888 overload
|
||||||
virtual inline void drawFastHLine(int16_t x, int16_t y, int16_t w, uint8_t r, uint8_t g, uint8_t b){
|
virtual inline void drawFastHLine(int16_t x, int16_t y, int16_t w, uint8_t r, uint8_t g, uint8_t b)
|
||||||
|
{
|
||||||
int16_t h = 1;
|
int16_t h = 1;
|
||||||
transform( x, y, w, h);
|
transform(x, y, w, h);
|
||||||
if( h > w )
|
if (h > w)
|
||||||
vlineDMA( x, y, h, r, g, b);
|
vlineDMA(x, y, h, r, g, b);
|
||||||
else
|
else
|
||||||
hlineDMA( x, y, w, r, g, b);
|
hlineDMA(x, y, w, r, g, b);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief - override Adafruit's fillRect
|
* @brief - override Adafruit's fillRect
|
||||||
* this works much faster than multiple consecutive per-pixel drawPixel() calls
|
* this works much faster than multiple consecutive per-pixel drawPixel() calls
|
||||||
*/
|
*/
|
||||||
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
|
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
|
||||||
|
{
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
color565to888(color, r, g, b);
|
color565to888(color, r, g, b);
|
||||||
startWrite();
|
startWrite();
|
||||||
transform( x, y, w, h);
|
transform(x, y, w, h);
|
||||||
fillRectDMA( x, y, w, h, r, g, b);
|
fillRectDMA(x, y, w, h, r, g, b);
|
||||||
endWrite();
|
endWrite();
|
||||||
}
|
}
|
||||||
// rgb888 overload
|
// rgb888 overload
|
||||||
virtual inline void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t r, uint8_t g, uint8_t b){
|
virtual inline void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t r, uint8_t g, uint8_t b)
|
||||||
|
{
|
||||||
startWrite();
|
startWrite();
|
||||||
transform( x, y, w, h);
|
transform(x, y, w, h);
|
||||||
fillRectDMA( x, y, w, h, r, g, b);
|
fillRectDMA(x, y, w, h, r, g, b);
|
||||||
endWrite();
|
endWrite();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -551,10 +582,10 @@ class MatrixPanel_I2S_DMA {
|
||||||
void drawPixel(int16_t x, int16_t y, CRGB color);
|
void drawPixel(int16_t x, int16_t y, CRGB color);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void drawIcon (int *ico, int16_t x, int16_t y, int16_t cols, int16_t rows);
|
void drawIcon(int *ico, int16_t x, int16_t y, int16_t cols, int16_t rows);
|
||||||
|
|
||||||
// Colour 444 is a 4 bit scale, so 0 to 15, colour 565 takes a 0-255 bit value, so scale up by 255/15 (i.e. 17)!
|
// Colour 444 is a 4 bit scale, so 0 to 15, colour 565 takes a 0-255 bit value, so scale up by 255/15 (i.e. 17)!
|
||||||
static uint16_t color444(uint8_t r, uint8_t g, uint8_t b) { return color565(r*17,g*17,b*17); }
|
static uint16_t color444(uint8_t r, uint8_t g, uint8_t b) { return color565(r * 17, g * 17, b * 17); }
|
||||||
|
|
||||||
// Converts RGB888 to RGB565
|
// Converts RGB888 to RGB565
|
||||||
static uint16_t color565(uint8_t r, uint8_t g, uint8_t b); // This is what is used by Adafruit GFX!
|
static uint16_t color565(uint8_t r, uint8_t g, uint8_t b); // This is what is used by Adafruit GFX!
|
||||||
|
@ -569,14 +600,26 @@ class MatrixPanel_I2S_DMA {
|
||||||
*/
|
*/
|
||||||
static void color565to888(const uint16_t color, uint8_t &r, uint8_t &g, uint8_t &b);
|
static void color565to888(const uint16_t color, uint8_t &r, uint8_t &g, uint8_t &b);
|
||||||
|
|
||||||
|
|
||||||
inline void flipDMABuffer()
|
inline void flipDMABuffer()
|
||||||
{
|
{
|
||||||
if ( !m_cfg.double_buff) { return; }
|
if (!m_cfg.double_buff)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (back_buffer_id == 0) // back buffer is 0 (dmadesc_a)
|
||||||
|
{
|
||||||
|
fb = &frame_buffer[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fb = &frame_buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
dma_bus.flip_dma_output_buffer(back_buffer_id);
|
||||||
|
|
||||||
|
back_buffer_id ^= 1;
|
||||||
|
|
||||||
// while (active_gfx_writes) { } // wait a bit ?
|
|
||||||
// initialized = false;
|
|
||||||
dma_bus.flip_dma_output_buffer( back_buffer_id );
|
|
||||||
// initialized = true;
|
// initialized = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -593,7 +636,6 @@ class MatrixPanel_I2S_DMA {
|
||||||
// Wait before we allow any writing to the buffer. Stop flicker.
|
// Wait before we allow any writing to the buffer. Stop flicker.
|
||||||
while(i2s_parallel_is_previous_buffer_free() == false) { }
|
while(i2s_parallel_is_previous_buffer_free() == false) { }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -610,11 +652,10 @@ class MatrixPanel_I2S_DMA {
|
||||||
brightness = b;
|
brightness = b;
|
||||||
brtCtrlOEv2(b, 0);
|
brtCtrlOEv2(b, 0);
|
||||||
|
|
||||||
if (m_cfg.double_buff) {
|
if (m_cfg.double_buff)
|
||||||
|
{
|
||||||
brtCtrlOEv2(b, 1);
|
brtCtrlOEv2(b, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes a value that is between 0 and MATRIX_WIDTH-1
|
// Takes a value that is between 0 and MATRIX_WIDTH-1
|
||||||
|
@ -652,10 +693,9 @@ class MatrixPanel_I2S_DMA {
|
||||||
void setBrightness8(const uint8_t b)
|
void setBrightness8(const uint8_t b)
|
||||||
{
|
{
|
||||||
setBrightness(b);
|
setBrightness(b);
|
||||||
//setPanelBrightness(b * PIXELS_PER_ROW / 256);
|
// setPanelBrightness(b * PIXELS_PER_ROW / 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief - Sets how many clock cycles to blank OE before/after LAT signal change
|
* @brief - Sets how many clock cycles to blank OE before/after LAT signal change
|
||||||
* @param uint8_t pulses - clocks before/after OE
|
* @param uint8_t pulses - clocks before/after OE
|
||||||
|
@ -669,10 +709,12 @@ class MatrixPanel_I2S_DMA {
|
||||||
* Get a class configuration struct
|
* Get a class configuration struct
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const HUB75_I2S_CFG& getCfg() const {return m_cfg;};
|
const HUB75_I2S_CFG &getCfg() const { return m_cfg; };
|
||||||
|
|
||||||
inline bool setCfg(const HUB75_I2S_CFG& cfg){
|
inline bool setCfg(const HUB75_I2S_CFG &cfg)
|
||||||
if(initialized) return false;
|
{
|
||||||
|
if (initialized)
|
||||||
|
return false;
|
||||||
|
|
||||||
m_cfg = cfg;
|
m_cfg = cfg;
|
||||||
PIXELS_PER_ROW = m_cfg.mx_width * m_cfg.chain_length;
|
PIXELS_PER_ROW = m_cfg.mx_width * m_cfg.chain_length;
|
||||||
|
@ -686,26 +728,27 @@ class MatrixPanel_I2S_DMA {
|
||||||
/**
|
/**
|
||||||
* Stop the ESP32 DMA Engine. Screen will forever be black until next ESP reboot.
|
* Stop the ESP32 DMA Engine. Screen will forever be black until next ESP reboot.
|
||||||
*/
|
*/
|
||||||
void stopDMAoutput() {
|
void stopDMAoutput()
|
||||||
|
{
|
||||||
resetbuffers();
|
resetbuffers();
|
||||||
//i2s_parallel_stop_dma(ESP32_I2S_DEVICE);
|
// i2s_parallel_stop_dma(ESP32_I2S_DEVICE);
|
||||||
dma_bus.dma_transfer_stop();
|
dma_bus.dma_transfer_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void startWrite() {
|
void startWrite()
|
||||||
//ESP_LOGI("TAG", "startWrite() called");
|
{
|
||||||
|
// ESP_LOGI("TAG", "startWrite() called");
|
||||||
active_gfx_writes++;
|
active_gfx_writes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void endWrite()
|
||||||
void endWrite() {
|
{
|
||||||
active_gfx_writes--;
|
active_gfx_writes--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------- PROTECTED -------
|
// ------- PROTECTED -------
|
||||||
// those might be useful for child classes, like VirtualMatrixPanel
|
// those might be useful for child classes, like VirtualMatrixPanel
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief - clears and reinitializes colour/control data in DMA buffs
|
* @brief - clears and reinitializes colour/control data in DMA buffs
|
||||||
* When allocated, DMA buffs might be dirty, so we need to blank it and initialize ABCDE,LAT,OE control bits.
|
* When allocated, DMA buffs might be dirty, so we need to blank it and initialize ABCDE,LAT,OE control bits.
|
||||||
|
@ -725,19 +768,20 @@ class MatrixPanel_I2S_DMA {
|
||||||
/**
|
/**
|
||||||
* wipes DMA buffer(s) and reset all colour/service bits
|
* wipes DMA buffer(s) and reset all colour/service bits
|
||||||
*/
|
*/
|
||||||
inline void resetbuffers(){
|
inline void resetbuffers()
|
||||||
|
{
|
||||||
|
|
||||||
clearFrameBuffer();
|
// flipDMABuffer();
|
||||||
brtCtrlOEv2(brightness, 0);
|
fb = &frame_buffer[0];
|
||||||
|
|
||||||
if (m_cfg.double_buff){
|
clearFrameBuffer(0); // buffer ID is not used
|
||||||
clearFrameBuffer(1);
|
brtCtrlOEv2(brightness, 0); // buffer ID is not used
|
||||||
brtCtrlOEv2(brightness, 1);
|
|
||||||
|
fb = &frame_buffer[1];
|
||||||
|
clearFrameBuffer(1); // buffer ID is not used
|
||||||
|
brtCtrlOEv2(brightness, 1); // buffer ID is not used
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef NO_FAST_FUNCTIONS
|
#ifndef NO_FAST_FUNCTIONS
|
||||||
/**
|
/**
|
||||||
* @brief - update DMA buff drawing horizontal line at specified coordinates
|
* @brief - update DMA buff drawing horizontal line at specified coordinates
|
||||||
|
@ -770,38 +814,37 @@ class MatrixPanel_I2S_DMA {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ------- PRIVATE -------
|
// ------- PRIVATE -------
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/* Calculate the memory available for DMA use, do some other stuff, and allocate accordingly */
|
/* Calculate the memory available for DMA use, do some other stuff, and allocate accordingly */
|
||||||
bool allocateDMAmemory();
|
bool allocateDMAmemory();
|
||||||
|
|
||||||
/* Setup the DMA Link List chain and initiate the ESP32 DMA engine */
|
/* Setup the DMA Link List chain and initiate the ESP32 DMA engine */
|
||||||
void configureDMA(const HUB75_I2S_CFG& opts);
|
void configureDMA(const HUB75_I2S_CFG &opts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pre-init procedures for specific drivers
|
* pre-init procedures for specific drivers
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void shiftDriver(const HUB75_I2S_CFG& opts);
|
void shiftDriver(const HUB75_I2S_CFG &opts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief - FM6124-family chips initialization routine
|
* @brief - FM6124-family chips initialization routine
|
||||||
*/
|
*/
|
||||||
void fm6124init(const HUB75_I2S_CFG& _cfg);
|
void fm6124init(const HUB75_I2S_CFG &_cfg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief - reset OE bits in DMA buffer in a way to control brightness
|
* @brief - reset OE bits in DMA buffer in a way to control brightness
|
||||||
* @param brt - brightness level from 0 to row_width
|
* @param brt - brightness level from 0 to row_width
|
||||||
* @param _buff_id - buffer id to control
|
* @param _buff_id - buffer id to control
|
||||||
*/
|
*/
|
||||||
//void brtCtrlOE(int brt, const bool _buff_id=0);
|
// void brtCtrlOE(int brt, const bool _buff_id=0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief - reset OE bits in DMA buffer in a way to control brightness
|
* @brief - reset OE bits in DMA buffer in a way to control brightness
|
||||||
* @param brt - brightness level from 0 to row_width
|
* @param brt - brightness level from 0 to row_width
|
||||||
* @param _buff_id - buffer id to control
|
* @param _buff_id - buffer id to control
|
||||||
*/
|
*/
|
||||||
void brtCtrlOEv2(uint8_t brt, const int _buff_id=0);
|
void brtCtrlOEv2(uint8_t brt, const int _buff_id = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief - transforms coordinates according to orientation
|
* @brief - transforms coordinates according to orientation
|
||||||
|
@ -810,28 +853,47 @@ class MatrixPanel_I2S_DMA {
|
||||||
* @param w - rectangular width
|
* @param w - rectangular width
|
||||||
* @param h - rectangular height
|
* @param h - rectangular height
|
||||||
*/
|
*/
|
||||||
void transform(int16_t &x, int16_t &y, int16_t &w, int16_t &h){
|
void transform(int16_t &x, int16_t &y, int16_t &w, int16_t &h)
|
||||||
#ifndef NO_GFX
|
{
|
||||||
|
#ifndef NO_GFX
|
||||||
int16_t t;
|
int16_t t;
|
||||||
switch (rotation) {
|
switch (rotation)
|
||||||
case 1: t = _height - 1 - y - ( h - 1 ); y = x; x = t; t = h; h = w; w = t; return;
|
{
|
||||||
case 2: x = _width - 1 - x - ( w - 1 ); y = _height - 1 - y - ( h - 1 ); return;
|
case 1:
|
||||||
case 3: t = y; y = _width - 1 - x - ( w - 1 ); x = t; t = h; h = w; w = t; return;
|
t = _height - 1 - y - (h - 1);
|
||||||
|
y = x;
|
||||||
|
x = t;
|
||||||
|
t = h;
|
||||||
|
h = w;
|
||||||
|
w = t;
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
x = _width - 1 - x - (w - 1);
|
||||||
|
y = _height - 1 - y - (h - 1);
|
||||||
|
return;
|
||||||
|
case 3:
|
||||||
|
t = y;
|
||||||
|
y = _width - 1 - x - (w - 1);
|
||||||
|
x = t;
|
||||||
|
t = h;
|
||||||
|
h = w;
|
||||||
|
w = t;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
public:
|
|
||||||
/**
|
/**
|
||||||
* Contains the resulting refresh rate (scan rate) that will be achieved
|
* Contains the resulting refresh rate (scan rate) that will be achieved
|
||||||
* based on the i2sspeed, colour depth and min_refresh_rate requested.
|
* based on the i2sspeed, colour depth and min_refresh_rate requested.
|
||||||
*/
|
*/
|
||||||
int calculated_refresh_rate = 0;
|
int calculated_refresh_rate = 0;
|
||||||
protected:
|
|
||||||
Bus_Parallel16 dma_bus;
|
|
||||||
private:
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Bus_Parallel16 dma_bus;
|
||||||
|
|
||||||
|
private:
|
||||||
// Matrix i2s settings
|
// Matrix i2s settings
|
||||||
HUB75_I2S_CFG m_cfg;
|
HUB75_I2S_CFG m_cfg;
|
||||||
|
|
||||||
|
@ -842,7 +904,10 @@ class MatrixPanel_I2S_DMA {
|
||||||
* Since it's dimensions is unknown prior to class initialization, we just declare it here as empty struct and will do all allocations later.
|
* Since it's dimensions is unknown prior to class initialization, we just declare it here as empty struct and will do all allocations later.
|
||||||
* Refer to rowBitStruct to get the idea of it's internal structure
|
* Refer to rowBitStruct to get the idea of it's internal structure
|
||||||
*/
|
*/
|
||||||
frameStruct dma_buff;
|
// frameStruct dma_buff;
|
||||||
|
|
||||||
|
frameStruct frame_buffer[2];
|
||||||
|
frameStruct *fb; // What framebuffer we are writing pixel changes to? (pointer to either frame_buffer[0] or frame_buffer[1] basically )
|
||||||
|
|
||||||
// ESP 32 DMA Linked List descriptor
|
// ESP 32 DMA Linked List descriptor
|
||||||
int desccount = 0;
|
int desccount = 0;
|
||||||
|
@ -878,7 +943,8 @@ class MatrixPanel_I2S_DMA {
|
||||||
* @param uint16_t colour - RGB565 input colour
|
* @param uint16_t colour - RGB565 input colour
|
||||||
* @param uint8_t &r, &g, &b - refs to variables where converted colours would be emplaced
|
* @param uint8_t &r, &g, &b - refs to variables where converted colours would be emplaced
|
||||||
*/
|
*/
|
||||||
inline void MatrixPanel_I2S_DMA::color565to888(const uint16_t color, uint8_t &r, uint8_t &g, uint8_t &b){
|
inline void MatrixPanel_I2S_DMA::color565to888(const uint16_t color, uint8_t &r, uint8_t &g, uint8_t &b)
|
||||||
|
{
|
||||||
r = ((((color >> 11) & 0x1F) * 527) + 23) >> 6;
|
r = ((((color >> 11) & 0x1F) * 527) + 23) >> 6;
|
||||||
g = ((((color >> 5) & 0x3F) * 259) + 33) >> 6;
|
g = ((((color >> 5) & 0x3F) * 259) + 33) >> 6;
|
||||||
b = (((color & 0x1F) * 527) + 23) >> 6;
|
b = (((color & 0x1F) * 527) + 23) >> 6;
|
||||||
|
@ -886,30 +952,30 @@ inline void MatrixPanel_I2S_DMA::color565to888(const uint16_t color, uint8_t &r,
|
||||||
|
|
||||||
inline void MatrixPanel_I2S_DMA::drawPixel(int16_t x, int16_t y, uint16_t color) // adafruit virtual void override
|
inline void MatrixPanel_I2S_DMA::drawPixel(int16_t x, int16_t y, uint16_t color) // adafruit virtual void override
|
||||||
{
|
{
|
||||||
uint8_t r,g,b;
|
uint8_t r, g, b;
|
||||||
color565to888(color,r,g,b);
|
color565to888(color, r, g, b);
|
||||||
|
|
||||||
int16_t w = 1, h = 1;
|
int16_t w = 1, h = 1;
|
||||||
transform( x, y, w, h);
|
transform(x, y, w, h);
|
||||||
updateMatrixDMABuffer( x, y, r, g, b);
|
updateMatrixDMABuffer(x, y, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MatrixPanel_I2S_DMA::fillScreen(uint16_t color) // adafruit virtual void override
|
inline void MatrixPanel_I2S_DMA::fillScreen(uint16_t color) // adafruit virtual void override
|
||||||
{
|
{
|
||||||
uint8_t r,g,b;
|
uint8_t r, g, b;
|
||||||
color565to888(color,r,g,b);
|
color565to888(color, r, g, b);
|
||||||
|
|
||||||
updateMatrixDMABuffer(r, g, b); // RGB only (no pixel coordinate) version of 'updateMatrixDMABuffer'
|
updateMatrixDMABuffer(r, g, b); // RGB only (no pixel coordinate) version of 'updateMatrixDMABuffer'
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MatrixPanel_I2S_DMA::drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g,uint8_t b)
|
inline void MatrixPanel_I2S_DMA::drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b)
|
||||||
{
|
{
|
||||||
int16_t w = 1, h = 1;
|
int16_t w = 1, h = 1;
|
||||||
transform( x, y, w, h);
|
transform(x, y, w, h);
|
||||||
updateMatrixDMABuffer( x, y, r, g, b);
|
updateMatrixDMABuffer(x, y, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MatrixPanel_I2S_DMA::fillScreenRGB888(uint8_t r, uint8_t g,uint8_t b)
|
inline void MatrixPanel_I2S_DMA::fillScreenRGB888(uint8_t r, uint8_t g, uint8_t b)
|
||||||
{
|
{
|
||||||
updateMatrixDMABuffer(r, g, b); // RGB only (no pixel coordinate) version of 'updateMatrixDMABuffer'
|
updateMatrixDMABuffer(r, g, b); // RGB only (no pixel coordinate) version of 'updateMatrixDMABuffer'
|
||||||
}
|
}
|
||||||
|
@ -919,8 +985,8 @@ inline void MatrixPanel_I2S_DMA::fillScreenRGB888(uint8_t r, uint8_t g,uint8_t b
|
||||||
inline void MatrixPanel_I2S_DMA::drawPixel(int16_t x, int16_t y, CRGB color)
|
inline void MatrixPanel_I2S_DMA::drawPixel(int16_t x, int16_t y, CRGB color)
|
||||||
{
|
{
|
||||||
int16_t w = 1, h = 1;
|
int16_t w = 1, h = 1;
|
||||||
transform( x, y, w, h);
|
transform(x, y, w, h);
|
||||||
updateMatrixDMABuffer( x, y, color.red, color.green, color.blue);
|
updateMatrixDMABuffer(x, y, color.red, color.green, color.blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MatrixPanel_I2S_DMA::fillScreen(CRGB color)
|
inline void MatrixPanel_I2S_DMA::fillScreen(CRGB color)
|
||||||
|
@ -929,22 +995,24 @@ inline void MatrixPanel_I2S_DMA::fillScreen(CRGB color)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Pass 8-bit (each) R,G,B, get back 16-bit packed colour
|
// Pass 8-bit (each) R,G,B, get back 16-bit packed colour
|
||||||
//https://github.com/squix78/ILI9341Buffer/blob/master/ILI9341_SPI.cpp
|
// https://github.com/squix78/ILI9341Buffer/blob/master/ILI9341_SPI.cpp
|
||||||
inline uint16_t MatrixPanel_I2S_DMA::color565(uint8_t r, uint8_t g, uint8_t b) {
|
inline uint16_t MatrixPanel_I2S_DMA::color565(uint8_t r, uint8_t g, uint8_t b)
|
||||||
|
{
|
||||||
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Promote 3/3/3 RGB to Adafruit_GFX 5/6/5 RRRrrGGGgggBBBbb
|
// Promote 3/3/3 RGB to Adafruit_GFX 5/6/5 RRRrrGGGgggBBBbb
|
||||||
inline uint16_t MatrixPanel_I2S_DMA::color333(uint8_t r, uint8_t g, uint8_t b) {
|
inline uint16_t MatrixPanel_I2S_DMA::color333(uint8_t r, uint8_t g, uint8_t b)
|
||||||
|
{
|
||||||
return ((r & 0x7) << 13) | ((r & 0x6) << 10) | ((g & 0x7) << 8) | ((g & 0x7) << 5) | ((b & 0x7) << 2) | ((b & 0x6) >> 1);
|
return ((r & 0x7) << 13) | ((r & 0x6) << 10) | ((g & 0x7) << 8) | ((g & 0x7) << 5) | ((b & 0x7) << 2) | ((b & 0x6) >> 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MatrixPanel_I2S_DMA::drawIcon (int *ico, int16_t x, int16_t y, int16_t cols, int16_t rows) {
|
inline void MatrixPanel_I2S_DMA::drawIcon(int *ico, int16_t x, int16_t y, int16_t cols, int16_t rows)
|
||||||
/* drawIcon draws a C style bitmap.
|
{
|
||||||
// Example 10x5px bitmap of a yellow sun
|
/* drawIcon draws a C style bitmap.
|
||||||
//
|
// Example 10x5px bitmap of a yellow sun
|
||||||
|
//
|
||||||
int half_sun [50] = {
|
int half_sun [50] = {
|
||||||
0x0000, 0x0000, 0x0000, 0xffe0, 0x0000, 0x0000, 0xffe0, 0x0000, 0x0000, 0x0000,
|
0x0000, 0x0000, 0x0000, 0xffe0, 0x0000, 0x0000, 0xffe0, 0x0000, 0x0000, 0x0000,
|
||||||
0x0000, 0xffe0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe0, 0x0000,
|
0x0000, 0xffe0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe0, 0x0000,
|
||||||
|
@ -956,21 +1024,20 @@ inline void MatrixPanel_I2S_DMA::drawIcon (int *ico, int16_t x, int16_t y, int16
|
||||||
MatrixPanel_I2S_DMA matrix;
|
MatrixPanel_I2S_DMA matrix;
|
||||||
|
|
||||||
matrix.drawIcon (half_sun, 0,0,10,5);
|
matrix.drawIcon (half_sun, 0,0,10,5);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i < rows; i++) {
|
for (i = 0; i < rows; i++)
|
||||||
for (j = 0; j < cols; j++) {
|
{
|
||||||
drawPixel (x + j, y + i, (uint16_t) ico[i * cols + j]);
|
for (j = 0; j < cols; j++)
|
||||||
|
{
|
||||||
|
drawPixel(x + j, y + i, (uint16_t)ico[i * cols + j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Credits: Louis Beaudoin <https://github.com/pixelmatix/SmartMatrix/tree/teensylc>
|
// Credits: Louis Beaudoin <https://github.com/pixelmatix/SmartMatrix/tree/teensylc>
|
||||||
// and Sprite_TM: https://www.esp32.com/viewtopic.php?f=17&t=3188 and https://www.esp32.com/viewtopic.php?f=13&t=3256
|
// and Sprite_TM: https://www.esp32.com/viewtopic.php?f=17&t=3188 and https://www.esp32.com/viewtopic.php?f=13&t=3256
|
||||||
|
|
||||||
|
|
|
@ -28,55 +28,29 @@ Modified heavily for the ESP32 HUB75 DMA library by:
|
||||||
#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 make sure thi is uncommented to get ESP_LOG output on (Arduino) Serial output!!!!
|
#include <Arduino.h> // Need to make sure this is uncommented to get ESP_LOG output on (Arduino) Serial output!!!!
|
||||||
#include <esp_err.h>
|
#include <esp_err.h>
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
|
|
||||||
// Get CPU freq function.
|
// Get CPU freq function.
|
||||||
#include <soc/rtc.h>
|
#include <soc/rtc.h>
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
callback shiftCompleteCallback;
|
|
||||||
void setShiftCompleteCallback(callback f) {
|
|
||||||
shiftCompleteCallback = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
volatile int previousBufferOutputLoopCount = 0;
|
|
||||||
volatile bool previousBufferFree = true;
|
volatile bool previousBufferFree = true;
|
||||||
|
|
||||||
static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
// Todo: handle IS20? (this is hard coded for I2S1 only)
|
||||||
|
static void IRAM_ATTR i2s_isr(void* arg) {
|
||||||
SET_PERI_REG_BITS(I2S_INT_CLR_REG(ESP32_I2S_DEVICE), I2S_OUT_EOF_INT_CLR_V, 1, I2S_OUT_EOF_INT_CLR_S);
|
REG_WRITE(I2S_INT_CLR_REG(1), (REG_READ(I2S_INT_RAW_REG(1)) & 0xffffffc0) | 0x3f);
|
||||||
|
|
||||||
|
// at this point, the previously active buffer is free, go ahead and write to it
|
||||||
previousBufferFree = true;
|
previousBufferFree = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DRAM_ATTR i2s_parallel_is_previous_buffer_free() {
|
||||||
|
return previousBufferFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // end irq_hndlr
|
|
||||||
*/
|
|
||||||
|
|
||||||
volatile int DRAM_ATTR active_dma_buffer_output_count = 0;
|
|
||||||
|
|
||||||
void IRAM_ATTR irq_hndlr(void* arg) {
|
|
||||||
|
|
||||||
// Clear flag so we can get retriggered
|
|
||||||
SET_PERI_REG_BITS(I2S_INT_CLR_REG(ESP32_I2S_DEVICE), I2S_OUT_EOF_INT_CLR_V, 1, I2S_OUT_EOF_INT_CLR_S);
|
|
||||||
|
|
||||||
active_dma_buffer_output_count++;
|
|
||||||
|
|
||||||
/*
|
|
||||||
if ( active_dma_buffer_output_count++ )
|
|
||||||
{
|
|
||||||
// Disable DMA chain EOF interrupt until next requested flipbuffer.
|
|
||||||
// Otherwise we're needlessly generating interrupts we don't care about.
|
|
||||||
//SET_PERI_REG_BITS(I2S_INT_ENA_REG(ESP32_I2S_DEVICE), I2S_OUT_EOF_INT_ENA_V, 0, I2S_OUT_EOF_INT_ENA_S);
|
|
||||||
active_dma_buffer_output_count = 0;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
} // end irq_hndlr
|
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
i2s_dev_t* getDev()
|
i2s_dev_t* getDev()
|
||||||
{
|
{
|
||||||
|
@ -221,22 +195,6 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
ESP_LOGD("ESP32/S2", "Requested output clock frequency: %d Mhz", (freq/1000000));
|
ESP_LOGD("ESP32/S2", "Requested output clock frequency: %d Mhz", (freq/1000000));
|
||||||
|
|
||||||
// What is the current CPU frequency?
|
// What is the current CPU frequency?
|
||||||
/*
|
|
||||||
rtc_cpu_freq_config_t conf;
|
|
||||||
rtc_clk_cpu_freq_get_config(&conf);
|
|
||||||
auto source_freq = conf.source_freq_mhz;
|
|
||||||
|
|
||||||
|
|
||||||
ESP_LOGD("ESP32/S2", "PLL (source) frequency: %d", source_freq);
|
|
||||||
ESP_LOGD("ESP32/S2", "CPU frequency: %d", conf.freq_mhz);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
if(_div_num < 2 || _div_num > 16) {
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Calculate clock divider for ESP32-S2
|
// Calculate clock divider for ESP32-S2
|
||||||
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
||||||
|
@ -415,21 +373,12 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
/* If we have double buffering, then allocate an interrupt service routine function
|
/* If we have double buffering, then allocate an interrupt service routine function
|
||||||
* that can be used for I2S0/I2S1 created interrupts.
|
* that can be used for I2S0/I2S1 created interrupts.
|
||||||
*/
|
*/
|
||||||
if (_double_dma_buffer) {
|
|
||||||
|
|
||||||
// Get ISR setup
|
// setup I2S Interrupt
|
||||||
esp_err_t err = esp_intr_alloc(irq_source,
|
SET_PERI_REG_BITS(I2S_INT_ENA_REG(1), I2S_OUT_EOF_INT_ENA_V, 1, I2S_OUT_EOF_INT_ENA_S);
|
||||||
(int)(ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1),
|
// allocate a level 1 intterupt: lowest priority, as ISR isn't urgent and may take a long time to complete
|
||||||
irq_hndlr, NULL, NULL);
|
esp_intr_alloc(ETS_I2S1_INTR_SOURCE, (int)(ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1), i2s_isr, NULL, NULL);
|
||||||
|
|
||||||
if(err) {
|
|
||||||
ESP_LOGE("ESP32/S2", "init() Failed to setup interrupt request handeler.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't do this here. Don't enable just yet.
|
|
||||||
// dev->int_ena.out_eof = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
#if defined (CONFIG_IDF_TARGET_ESP32S2)
|
||||||
|
@ -490,7 +439,7 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
|
|
||||||
ESP_LOGD("ESP32/S2", "Allocating the second buffer (double buffer enabled).");
|
ESP_LOGD("ESP32/S2", "Allocating the second buffer (double buffer enabled).");
|
||||||
|
|
||||||
_dmadesc_b= (HUB75_DMA_DESCRIPTOR_T*)heap_caps_malloc(sizeof(HUB75_DMA_DESCRIPTOR_T) * len, MALLOC_CAP_DMA);
|
_dmadesc_b = (HUB75_DMA_DESCRIPTOR_T*)heap_caps_malloc(sizeof(HUB75_DMA_DESCRIPTOR_T) * len, MALLOC_CAP_DMA);
|
||||||
|
|
||||||
if (_dmadesc_b == nullptr)
|
if (_dmadesc_b == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -611,21 +560,16 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
} // end
|
} // end
|
||||||
|
|
||||||
|
|
||||||
void Bus_Parallel16::flip_dma_output_buffer(int ¤t_back_buffer_id) // pass by reference so we can change in main matrixpanel class
|
void Bus_Parallel16::flip_dma_output_buffer(int buffer_id) // pass by reference so we can change in main matrixpanel class
|
||||||
{
|
{
|
||||||
|
|
||||||
// Setup interrupt handler which is focussed only on the (page 322 of Tech. Ref. Manual)
|
// 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" (when dma linked list with eof = 1 is hit)
|
// "I2S_OUT_EOF_INT: Triggered when rxlink has finished sending a packet" (when dma linked list with eof = 1 is hit)
|
||||||
//_dev->int_ena.out_eof = 1;
|
|
||||||
_dev->int_ena.out_eof = 1; // enable interrupt
|
|
||||||
|
|
||||||
if ( current_back_buffer_id == 1) {
|
if ( buffer_id == 1) {
|
||||||
|
|
||||||
_dmadesc_a[_dmadesc_last].qe.stqe_next = &_dmadesc_b[0]; // Start sending out _dmadesc_b (or buffer 1)
|
_dmadesc_a[_dmadesc_last].qe.stqe_next = &_dmadesc_b[0]; // Start sending out _dmadesc_b (or buffer 1)
|
||||||
|
|
||||||
active_dma_buffer_output_count = 0;
|
|
||||||
while (!active_dma_buffer_output_count) {}
|
|
||||||
|
|
||||||
//fix _dmadesc_ loop issue #407
|
//fix _dmadesc_ loop issue #407
|
||||||
//need to connect the up comming _dmadesc_ not the old one
|
//need to connect the up comming _dmadesc_ not the old one
|
||||||
_dmadesc_b[_dmadesc_last].qe.stqe_next = &_dmadesc_b[0];
|
_dmadesc_b[_dmadesc_last].qe.stqe_next = &_dmadesc_b[0];
|
||||||
|
@ -633,17 +577,15 @@ static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
_dmadesc_b[_dmadesc_last].qe.stqe_next = &_dmadesc_a[0];
|
_dmadesc_b[_dmadesc_last].qe.stqe_next = &_dmadesc_a[0];
|
||||||
|
|
||||||
active_dma_buffer_output_count = 0;
|
|
||||||
while (!active_dma_buffer_output_count) {}
|
|
||||||
|
|
||||||
_dmadesc_a[_dmadesc_last].qe.stqe_next = &_dmadesc_a[0];
|
_dmadesc_a[_dmadesc_last].qe.stqe_next = &_dmadesc_a[0];
|
||||||
|
|
||||||
}
|
}
|
||||||
current_back_buffer_id ^= 1;
|
|
||||||
|
|
||||||
// Disable intterupt
|
previousBufferFree = false;
|
||||||
_dev->int_ena.out_eof = 0;
|
while (i2s_parallel_is_previous_buffer_free() == false) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // end flip
|
} // end flip
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,8 @@ Contributors:
|
||||||
|
|
||||||
#define DMA_MAX (4096-4)
|
#define DMA_MAX (4096-4)
|
||||||
|
|
||||||
#ifndef ESP32_I2S_DEVICE
|
// DO NOT CHANGE
|
||||||
#define ESP32_I2S_DEVICE I2S_NUM_0
|
#define ESP32_I2S_DEVICE I2S_NUM_1
|
||||||
#endif
|
|
||||||
|
|
||||||
// The type used for this SoC
|
// The type used for this SoC
|
||||||
#define HUB75_DMA_DESCRIPTOR_T lldesc_t
|
#define HUB75_DMA_DESCRIPTOR_T lldesc_t
|
||||||
|
@ -119,7 +118,7 @@ i2s_dev_t* getDev();
|
||||||
void dma_transfer_start();
|
void dma_transfer_start();
|
||||||
void dma_transfer_stop();
|
void dma_transfer_stop();
|
||||||
|
|
||||||
void flip_dma_output_buffer(int ¤t_back_buffer_id);
|
void flip_dma_output_buffer(int buffer_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -441,12 +441,12 @@
|
||||||
} // end
|
} // end
|
||||||
|
|
||||||
|
|
||||||
void Bus_Parallel16::flip_dma_output_buffer(int ¤t_back_buffer_id)
|
void Bus_Parallel16::flip_dma_output_buffer(int back_buffer_id)
|
||||||
{
|
{
|
||||||
|
|
||||||
// if ( _double_dma_buffer == false) return;
|
// if ( _double_dma_buffer == false) return;
|
||||||
|
|
||||||
if ( current_back_buffer_id == 1) // change across to everything 'b''
|
if ( back_buffer_id == 1) // change across to everything 'b''
|
||||||
{
|
{
|
||||||
_dmadesc_a[_dmadesc_count-1].next = (dma_descriptor_t *) &_dmadesc_b[0];
|
_dmadesc_a[_dmadesc_count-1].next = (dma_descriptor_t *) &_dmadesc_b[0];
|
||||||
_dmadesc_b[_dmadesc_count-1].next = (dma_descriptor_t *) &_dmadesc_b[0];
|
_dmadesc_b[_dmadesc_count-1].next = (dma_descriptor_t *) &_dmadesc_b[0];
|
||||||
|
@ -457,7 +457,7 @@
|
||||||
_dmadesc_a[_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;
|
//current_back_buffer_id ^= 1;
|
||||||
|
|
||||||
|
|
||||||
} // end flip
|
} // end flip
|
||||||
|
|
|
@ -147,7 +147,7 @@
|
||||||
void dma_transfer_start();
|
void dma_transfer_start();
|
||||||
void dma_transfer_stop();
|
void dma_transfer_stop();
|
||||||
|
|
||||||
void flip_dma_output_buffer(int ¤t_back_buffer_id);
|
void flip_dma_output_buffer(int back_buffer_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue