Giter Site home page Giter Site logo

mrfaptastic / esp32-hub75-matrixpanel-dma Goto Github PK

View Code? Open in Web Editor NEW
912.0 38.0 202.0 6.67 MB

An Adafruit GFX Compatible Library for the ESP32, ESP32-S2, ESP32-S3 to drive HUB75 LED matrix panels using DMA for high refresh rates. Supports panel chaining.

License: MIT License

C++ 98.27% CMake 1.71% Makefile 0.02%
led-panels dma esp32 esp32-arduino esp32s2 hub75 hub75e esp32s3

esp32-hub75-matrixpanel-dma's Introduction

HUB75 RGB LED matrix panel library utilizing ESP32 DMA

BUILD OPTIONS | EXAMPLES | PlatformIO CI

Table of Content

Introduction

  • This is an ESP32 Arduino/IDF library for HUB75 / HUB75E connection based RGB LED panels.
  • This library 'out of the box' (mostly) supports HUB75 panels where simple TWO rows/lines are updated in parallel... referred to as 'two scan' panels within this documentation.
  • 'Four scan' panels are also supported - but please refer to the Four Scan Panel example sketch.
  • The library uses the DMA functionality provided by the ESP32's 'LCD Mode' for fast data output.

Features

  • Low CPU overhead - Pixel data is sent directly with the use of hardware-backed DMA, no CPU involvement
  • Fast - Updating pixel data involves only bit-wise logic over DMA buffer memory, no pins manipulation or blocking IO
  • Full screen BCM - Library utilizes binary-code modulation to render pixel color depth / brightness over the entire matrix to give reasonable colour depth
  • Variable color depth - Up to TrueColor 24 bits output is possible depending on matrix size/refresh rate required
  • CIE 1931 luminance correction (aka natural LED dimming) implemented
  • Adafruit GFX API - Library can be built with AdafruitGFX, simplified GFX or without a GFX API at all

ESP32 variants supported

  • Original ESP32 - That being the ESP-WROOM-32 module with ESP32‑D0WDQ6 chip from ~2017.
  • ESP32-S2; and
  • ESP32-S3

RISC-V ESP32's (like the C3) are not supported as they do not have the hardware 'LCD mode' support.

Required memory

"What's the price for those features?" - It's memory, you pay it all by precious MCU's internal memory (SRAM) for the DMA buffer.

Please use the 'Memory Calculator' to see what is typically achievable with the typical ESP32. This is only a guide. Memory Calculator

For the ESP32-S3 only, you can use SPIRAM/PSRAM to drive the HUB75 DMA buffer when using an ESP32-S3 with OCTAL SPI-RAM (PSTRAM) (i.e. ESP32 S3 N8R8 variant). However, due to bandwidth limitations, the maximum output frequency is limited to approx. 13Mhz, which will limit the real-world number of panels that can be chained without flicker. Please do not use PSRAM as the DMA buffer if using QUAD SPI (Q-SPI), as it's too slow.

To enable PSRAM support on the ESP32-S3, refer to the build options to enable.

For all other ESP32 variants (like the most popular ‘original’ ESP32), only internal SRAM can be used, so you will be limited to the ~200KB or so of 'free' SRAM (because of the memory used for your sketch amongst other things) regardless of how many megabytes of SPIRAM/PSRAM you may have connected.

Supported panel can types

It is impossible to provide a comprehensive list of what panels are supported (or not supported) as new variations of the chips used to 'drive' these panels are created almost weekly (usually from China). You should contact the seller to confirm the chips used in a panel before purchasing to use with this library.

  • 'Two scan' panels where two rows/lines are updated in parallel.

    • 64x32 (width x height) 'Indoor' panels, which are often referred to as 1/16 'scan panel' as every 16th row is updated in parallel (hence why I refer to it as 'two scan')
    • 64x64 pixel 1/32 Scan LED Matrix 'Indoor' Panel
  • 'Four scan' panels where four rows/lines are updated in parallel.

    • 32x16 pixel 1/4 Scan LED Matrix 'Indoor' Panel using an ingenious workaround as demonstrated in the Four_Scan_Panel example.
    • 126x64 SM5266P

Ones interested in internals of such matrices could find this article useful.

Panel Scan Types

Specific chips found to work

  • ICND2012
  • RUC7258
  • FM6126A AKA ICN2038S, FM6124 (Refer to PatternPlasma example on how to use.)
  • SM5266P
  • DP3246 with SM5368 row addressing registers

Specific chips found NOT TO work

  • ANY panel that uses S-PWM or PWM based chips (such as the RUL6024, MBI6024).
  • SM1620B
  • RUL5358 / SHIFTREG_ABC_BIN_DE based panels are not supported.
  • ICN2053 / FM6353 based panels - Refer to this library, which is a fork of this library ( discussion link).
  • Any other panel not listed above.

Please use an alternative library if you bought one of these.

Getting Started

1. Library Installation

  • Dependency: You will need to install Adafruit_GFX from the "Library > Manage Libraries" menu.
  • Install this library from the Arduino Library manager.

Library also tested to work fine with PlatformIO, install into your PlatformIO projects' lib/ folder as appropriate. Or just add it into platformio.ini lib_deps section.

2. Wiring the ESP32 to an LED Matrix Panel

Refer to the '*default-pins.hpp' file within the applicable platforms folder.

If you want to change the GPIO mapping at runtime, simply provide the wanted pin mapping as part of the class initialization structure. For example, in your sketch have something like the following:

// Change these to whatever suits
#define R1_PIN 25
#define G1_PIN 26
#define B1_PIN 27
#define R2_PIN 14
#define G2_PIN 12
#define B2_PIN 13
#define A_PIN 23
#define B_PIN 19
#define C_PIN 5
#define D_PIN 17
#define E_PIN -1 // required for 1/32 scan panels, like 64x64px. Any available pin would do, i.e. IO32
#define LAT_PIN 4
#define OE_PIN 15
#define CLK_PIN 16

HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN};
HUB75_I2S_CFG mxconfig(
	64, // Module width
	32, // Module height
	2, // chain length
	_pins, // pin mapping
);
dma_display = new MatrixPanel_I2S_DMA(mxconfig);

Make sure you also connect one of the HUB75 interfaces ground pins to a ground pin of the ESP32, otherwise you may get electrical artefacts on LED Matrix Panel.

Various people have created PCBs for which one can simply connect an ESP32 to a PCB, and then the PCB to the HUB75 connector, such as:

Please contact or order these products from the respective authors.

How can I configure it to work with an off-the-shelf board/shield with HUB75 connector, e.g. Adafruit MatrixPortal?

You need to find the correct pin mapping for your board. For Adafruit boards/shields, you can look in one of the examples provided with the Protomatter library, for example here. Find your board variant, copy the pin values into the #defines described above, and pass the pin mapping into your mxconfig.

For example, for MatrixPortal S3, the Protomatter example file contains the following:

uint8_t rgbPins[]  = {42, 41, 40, 38, 39, 37};
uint8_t addrPins[] = {45, 36, 48, 35, 21};
uint8_t clockPin   = 2;
uint8_t latchPin   = 47;
uint8_t oePin      = 14;

which for use with this library, converts to:

#define R1_PIN 42
#define G1_PIN 41
#define B1_PIN 40
#define R2_PIN 38
#define G2_PIN 39
#define B2_PIN 37
#define A_PIN  45
#define B_PIN  36
#define C_PIN  48
#define D_PIN  35
#define E_PIN  21 
#define LAT_PIN 47
#define OE_PIN  14
#define CLK_PIN 2

HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN};

// Module configuration
HUB75_I2S_CFG mxconfig(
  PANEL_RES_X,   // module width
  PANEL_RES_Y,   // module height
  PANEL_CHAIN,   // Chain length
  _pins          // Pin mapping
);

Can I use with a larger panel (i.e. 64x64px square panel)?

If you want to use with a 64x64 pixel panel (typically a HUB75E panel) you MUST configure a valid E_PIN to your ESP32 and connect it to the E pin of the HUB75 panel! Hence the 'E' in 'HUB75E'

3. Run a Test Sketch

Below is a bare minimum sketch to draw a single white dot in the top left. You must call begin() before you call ANY pixel-drawing (fonts, lines, colours etc.) function of the MatrixPanel_I2S_DMA class.

Once this is working, refer to the PIO Test Patterns example. This sketch draws simple colors/lines/gradients over the entire matrix and it could help to troubleshoot various issues with ghosting, flickering, etc...

Note: Requires the use of PlatformIO, which you should probably use if you aren't already.

Further information

Can I chain panels?

Yes!

VID-20200824-WA0004.mp4

For example: If you want to chain two of these horizontally to make a 128x32 panel you can do so by connecting the panels in series using the HUB75 ribbon cable. Than you must provide proper configuration structure to the class constructor letting it know that you use "one long virtual matrix chain". Refer to Pattern Plasma example for all the details about configuration setup.

Finally, if you wanted to chain 4 x (64x32px) panels to make 128x64px display (essentially a 2x2 grid of 64x32 LED Matrix modules), a little more magic will be required. Refer to the VirtualMatrixPanel example and the AuroraDemo example of its practical use.

Resolutions beyond 128x64 are more likely to result in crashes due to memory constraints etc. You are on your own after this point - PLEASE do not raise issues about this, the library can't magically defeat the SRAM memory constraints of the ESP32.

ezgif com-video-to-gif

Adjusting Panel Brightness

By default you should not need to change / set the brightness value (which is 128 or 50%) as it should be sufficient for most purposes. Brightness can be changed by calling setPanelBrightness(xx) or setBrightness8(xx).

The value to pass must be a number between 0 (for a black screen) and 255 (max brightness).

Example:

void setup() {
Serial.begin(115200);
	dma_display->begin(); // setup the LED matrix
    dma_display->setBrightness8(192); //0-255
    dma_display->clearScreen();	
}

Brightness Samples

Build-time options

Although Arduino IDE does not seem to offer any way of specifying compile-time options for external libs there are other IDE's (like PlatformIO/Eclipse) that could use that. Check Build Options document for reference.

Latch blanking

If you are facing issues with image ghosting when pixels has clones with horizontal offset, than you try to change Latch blanking value. Latch blanking controls for how many clock pulses matrix output is disabled via EO signal before/after toggling LAT signal. It hides row bits transitioning and different panels may require longer times for proper operation. Default value is 1 clock before/after LAT row transition. This could be controlled with MatrixPanel_I2S_DMA::setLatBlanking(uint8_t v). v could be between 1 to 4, default is 1, larger values won't give any benefit other than reducing brightness.

An example:

dma_display->setLatBlanking(2);

Power, Power and Power!

Having a good power supply is CRITICAL, and it is highly recommended, for chains of LED Panels to have a 1000-2000uf capacitor soldered to the back of each LED Panel across the GND and VCC pins, otherwise you WILL run into issues with 'flashy' graphics whereby a large amount of LEDs are turned on and off in succession (due to current/power draw peaks and troughs).

  • Refer to this guide written for the rpi-rgb-led-matrix library for an explanation.

  • Refer to this example issue of what can go wrong with a poor power supply.

  • Refer to this comment in regards to certain panels not playing nice with voltages, and a 3.3volt signal that the ESP32 GPIO can only provide.

Inspiration

This project was inspired by:

Cool uses of this library

There are a number of great looking LED graphical display projects which leverage this library, these include:

Thank you!

  • Brian Lough (youtube link) for providing code contributions, hardware and suggestions
  • Vortigont for his game changing code contributions and performance optimisations
  • Galaxy Man for donation of 1/16 scan panels to support the implemenation of led matrix panel chaining (virtual display) support
  • Pipimaxi for the donation of a ESP32-S2 and Radu for the donation of an ESP32-S3 to enable support for ESP32 S2/S3's to be tested and implemented.
  • Mark Donners ('The Electronic Engineer' on youtube) for the donation of a 1/8 scan panel to build and test working support of these led matrix panels!
  • PaintYourDragon for the DMA logic for the ESP32-S3.
  • And lots of others, let me know if I've missed you.

If you want to donate money to the project, please refer to this discussion about it. If you want to donate/buy an LED panel for the library author to improve compatibility and/or testing - please feel free to post in the same discussion.

It's better in real life

esp32-hub75-matrixpanel-dma's People

Contributors

2beckham2 avatar abrender avatar adi961 avatar beta-tester avatar board707 avatar chegewara avatar csloz avatar dependabot[bot] avatar dorianim avatar drvkmr avatar elliotmatson avatar jnthas avatar kosso avatar kouzeru avatar loganfin avatar lols avatar lostincompilation avatar lukaswnd avatar marcmerlin avatar mcauser avatar mkalkbrenner avatar mrcodetastic avatar njh avatar oseiler2 avatar solhuebner avatar tomduncalf avatar vortigont avatar witnessmenow avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

esp32-hub75-matrixpanel-dma's Issues

Cannot chaining panel 128x32

Hi mrfaptastic,
I used smartmatrix pinout and the display runs good using single panel.
However, the displays is always cloned when I used :
#define MATRIX_WIDTH 128 #define MATRIX_HEIGHT 32

I run example sketches and no modification other than MATRIX WIDTH 128.
Did I just go wrong?

CLONED DISPLAY

FM6126 based HUB75 Panels

Same issue will affect this library, reference: hzeller/rpi-rgb-led-matrix#746

Potential fix required before using: .begin() -> #20

#include <Arduino.h>
#include <TomThumb.h> // this should be in the adafruit-gfx library
#include <ESP32-RGB64x32MatrixPanel-I2S-DMA.h>

RGB64x32MatrixPanel_I2S_DMA matrix;

////////////////////////////////////////////////////////////////////
// Reset Panel
// This needs to be near the top of the code
//
// Change these to whatever suits
// recommended settings and patches are by
//
// pinout for ESP38 38pin module
// http://arduinoinfo.mywikis.net/wiki/Esp32#KS0413_keyestudio_ESP32_Core_Board
//

// R1 | G1
// B1 | GND
// R2 | G2
// B2 | E
// A | B
// C | D
// CLK| LAT
// OE | GND

#define R1 25
#define G1 26
#define BL1 27
#define R2 5 // 21 SDA
#define G2 19 // 22 SDL
#define BL2 23
#define CH_A 12
#define CH_B 16
#define CH_C 17
#define CH_D 18
#define CH_E -1 // assign to pin if using two panels
#define CLK 15
#define LAT 32
#define OE 33

void resetPanel()
{
int MaxLed = 64;

int C12[16] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int C13[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0};

pinMode(R1, OUTPUT);
pinMode(G1, OUTPUT);
pinMode(BL1, OUTPUT);
pinMode(R2, OUTPUT);
pinMode(G2, OUTPUT);
pinMode(BL2, OUTPUT);
pinMode(CH_A, OUTPUT);
pinMode(CH_B, OUTPUT);
pinMode(CH_C, OUTPUT);
pinMode(CH_D, OUTPUT);
pinMode(CH_E, OUTPUT);
pinMode(CLK, OUTPUT);
pinMode(LAT, OUTPUT);
pinMode(OE, OUTPUT);

// Send Data to control register 11
digitalWrite(OE, HIGH); // Display reset
digitalWrite(LAT, LOW);
digitalWrite(CLK, LOW);
for (int l = 0; l < MaxLed; l++)
{
int y = l % 16;
digitalWrite(R1, LOW);
digitalWrite(G1, LOW);
digitalWrite(BL1, LOW);
digitalWrite(R2, LOW);
digitalWrite(G2, LOW);
digitalWrite(BL2, LOW);
if (C12[y] == 1)
{
digitalWrite(R1, HIGH);
digitalWrite(G1, HIGH);
digitalWrite(BL1, HIGH);
digitalWrite(R2, HIGH);
digitalWrite(G2, HIGH);
digitalWrite(BL2, HIGH);
}
if (l > MaxLed - 12)
{
digitalWrite(LAT, HIGH);
}
else
{
digitalWrite(LAT, LOW);
}
digitalWrite(CLK, HIGH);
digitalWrite(CLK, LOW);
}
digitalWrite(LAT, LOW);
digitalWrite(CLK, LOW);
// Send Data to control register 12
for (int l = 0; l < MaxLed; l++)
{
int y = l % 16;
digitalWrite(R1, LOW);
digitalWrite(G1, LOW);
digitalWrite(BL1, LOW);
digitalWrite(R2, LOW);
digitalWrite(G2, LOW);
digitalWrite(BL2, LOW);
if (C13[y] == 1)
{
digitalWrite(R1, HIGH);
digitalWrite(G1, HIGH);
digitalWrite(BL1, HIGH);
digitalWrite(R2, HIGH);
digitalWrite(G2, HIGH);
digitalWrite(BL2, HIGH);
}
if (l > MaxLed - 13)
{
digitalWrite(LAT, HIGH);
}
else
{
digitalWrite(LAT, LOW);
}
digitalWrite(CLK, HIGH);
digitalWrite(CLK, LOW);
}
digitalWrite(LAT, LOW);
digitalWrite(CLK, LOW);
}
// End of default setup for RGB Matrix 64x32 panel
///////////////////////////////////////////////////////////////

void setup(){

resetPanel(); // do this before matrix.begin

// If you experience ghosting, you will need to reduce the brightness level, not all RGB Matrix
// Panels are the same - some seem to display ghosting artefacts at lower brightness levels.
// In the setup() function do something like:

matrix.setPanelBrightness(10); // SETS THE BRIGHTNESS HERE. 60 OR LOWER IDEAL.

matrix.begin(R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK); // setup the LED matrix
// matrix.setFont(&TomThumb.h);
matrix.setTextColor(matrix.Color(96, 0, 96)); // r,g,b
matrix.setCursor(1, 15);
matrix.println("Hello World");

}

void loop(){

}

FM6126A - garbage after ESP reboot

Maybe, if someone else could confirm it, or not.
After successful FM6126A initialization it works fine. But if ESP reboots afterward than some part of the combined screen contains garbage. It is almost always NOT the first panel connected to CPU but all other in chain.
Looks like somehow a random values got itself locked in 6126 registers and usual LAT/OE signals can't write new data to it any more.
The only proven way is to power down both ESP and the whole panel than power up both at the same time.
Not sure how to fix this since specs for 6126 are scarce. Need more experiments with reg vals.

Make ESP32 pinout compatible between your lib and SmartMatrix?

Howdy again, I tried your library to see if it would look better on video than SmartMatrix which is ok with the naked eye, but looks very flickery on video, see
https://community.pixelmatix.com/t/working-around-sync-offsets-and-flicker-when-filming-taking-pictures/346
https://www.youtube.com/watch?v=1f2aDTCmLcE

Louis recommended that I try your lib, which I got working in 32x64 (not 64x64 yet). One issue though is the two libs use different pinout. See
https://github.com/pixelmatix/SmartMatrix/blob/teensylc/src/MatrixHardware_ESP32_V0.h#L64
Would you be willing to change your pinout to be compatible with it so that people can switch between both libs without rewiring?

ESP32-RGB64x32MatrixPanel-I2S-DMA.h:
#define R1_PIN 2
#define G1_PIN 15
#define B1_PIN 4
#define R2_PIN 16
#define G2_PIN 27
#define B2_PIN 17

#define A_PIN 5
#define B_PIN 18
#define C_PIN 19
#define D_PIN 21
#define E_PIN 12

#define LAT_PIN 26
#define OE_PIN 25

#define CLK_PIN 22

Thank you and Merry Xmas,
Marc

32x32 Matrix not working!

I know that this library only has been tested with 64x64 matrix but i've heard that people have got it working with a 32x16 so i thought it would be just plug and play here but sadly no :/

my board is
IFH6-32x32-16S-V1.0 (HUB75D)

Support for stacked coordinate layout (64x64 with 2x64x32 panels) in addition to side by side (128x32)

I tried your library, it worked fine on my ESP32, thank you.
For 64x32 it just works.
That said, I have chained panels and would like to try 64x64 and ultimately 64x96 which does work with Louis' SmartMatrix already
I went in your library edited ESP32-RGB64x32MatrixPanel-I2S-DMA.h
#define MATRIX_HEIGHT 64

Once I do, I get this
23:24:18.962 -> Setting up parallel I2S bus at I2S1
23:24:18.963 -> I2S setup done.
23:24:18.964 -> Flushing buffer 0Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
0x400d12af: RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(short, short, unsigned char, unsigned char, unsigned char) at /home/merlin/Arduino/libraries/ESP32-RGB64x32MatrixPanel-I2S-DMA/ESP32-RGB64x32MatrixPanel-I2S-DMA.cpp line 266
0x400d0c11: RGB64x32MatrixPanel_I2S_DMA::flushDMAbuffer() at /home/merlin/Arduino/libraries/ESP32-RGB64x32MatrixPanel-I2S-DMA/ESP32-RGB64x32MatrixPanel-I2S-DMA.h line 233
0x400d0c5c: setup() at /home/merlin/Arduino/libraries/ESP32-RGB64x32MatrixPanel-I2S-DMA/ESP32-RGB64x32MatrixPanel-I2S-DMA.h line 182
0x400e5a77: loopTask(void*) at /home/merlin/Arduino/hardware/espressif/esp32/cores/esp32/main.cpp line 15

Details:
23:24:18.859 -> *****************************************************
23:24:18.861 -> HELLO !
23:24:18.862 -> *****************************************************
23:24:18.863 -> lsbMsbTransitionBit of 0 requires 198304 RAM, 113792 available, leaving -84512 free:
23:24:18.863 -> lsbMsbTransitionBit of 1 requires 149152 RAM, 113792 available, leaving -35360 free:
23:24:18.894 -> lsbMsbTransitionBit of 2 requires 124576 RAM, 113792 available, leaving -10784 free:
23:24:18.896 -> lsbMsbTransitionBit of 3 requires 112288 RAM, 113792 available, leaving 1504 free:
23:24:18.898 -> Raised lsbMsbTransitionBit to 3/7 to fit in RAM
23:24:18.898 -> ns per latch: 3200:
23:24:18.899 -> nsPerFrame: 3481600:
23:24:18.900 -> lsbMsbTransitionBit of 3 gives 287 Hz refresh:
23:24:18.925 -> Raised lsbMsbTransitionBit to 3/7 to meet minimum refresh rate
23:24:18.928 -> Descriptors for lsbMsbTransitionBit 3/7 with 32 rows require 12288 bytes of DMA RAM
23:24:18.930 -> SmartMatrix Mallocs Complete
23:24:18.930 -> Heap Memory Available: 367940 bytes total, 113792 bytes largest free block:
23:24:18.931 -> 8-bit Accessible Memory Available: 279436 bytes total, 113792 bytes largest free block:
23:24:18.933 -> 32-bit Memory Available: 367940 bytes total, 113792 bytes largest free block:
23:24:18.960 -> DMA Memory Available: 279436 bytes total, 113792 bytes largest free block:
23:24:18.961 -> Performing I2S setup.
23:24:18.962 -> Setting up parallel I2S bus at I2S1
23:24:18.963 -> I2S setup done.
23:24:18.964 -> Flushing buffer 0Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
23:24:18.964 -> Core 1 register dump:
23:24:18.965 -> PC : 0x400d12af PS : 0x00060730 A0 : 0x800d0c14 A1 : 0x3ffb1f10
23:24:18.993 -> A2 : 0x3ffc2420 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x00000002
23:24:18.995 -> A6 : 0x00000000 A7 : 0x00001f82 A8 : 0x00000002 A9 : 0x00000000
23:24:18.997 -> A10 : 0x00000000 A11 : 0x00000000 A12 : 0x00000001 A13 : 0x00000008
23:24:18.998 -> A14 : 0x00000002 A15 : 0x00000004 SAR : 0x00000020 EXCCAUSE: 0x0000001c
23:24:19.025 -> EXCVADDR: 0x00000002 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xffffffff
23:24:19.026 ->
23:24:19.027 -> Backtrace: 0x400d12af:0x3ffb1f10 0x400d0c11:0x3ffb1f60 0x400d0c5c:0x3ffb1f80 0x400e5a77:0x3ffb1fa0
23:24:19.028 ->
23:24:19.028 -> Rebooting...

Question about using ESP32

Your readme.md is extensive; thank you.
I do have a few questions:

  1. what type of ESP32 board are you using, and does it matter?

  2. I don't see any level shifters, are they needed?

  3. Is your assignment of I/O pins anything other than 'random' ?
    Would it theoretically work if alternates were used?
    Your readme.md refers to (defaults defined in ESP32-RGB64x32MatrixPanel-I2S-DMA.h).
    /* ESP32 Pin Definition. You can change this, but best if you keep it as is...

the above are the questions I hoped you could answer.
If you are interested, here are more details about the alternate pin order

  1. I would like to use an Adafruit RGB Matrix Featherwing kit
    https://www.adafruit.com/product/3036
    https://learn.adafruit.com/assets/59625

RGB MR.FAP ADAFRUIT
R1 -> IO25 IO32
G1 -> IO26 IO14
B1 -> IO27 IO15
R2 -> IO14 IO27
G2 -> IO12 IO33
B2 -> IO13 IO12
A -> IO23 IO 4
B -> IO22 IO36
C -> IO 5 IO39
D -> IO17 IO34
CLK -> IO16 IO13
LAT -> IO 4 IO16
OE -> IO15 IO17

Here is your original list of #defines

/* ESP32 Pin Definition. You can change this, but best if you keep it as is...

#define R1_PIN_DEFAULT 25
#define G1_PIN_DEFAULT 26
#define B1_PIN_DEFAULT 27
#define R2_PIN_DEFAULT 14
#define G2_PIN_DEFAULT 12
#define B2_PIN_DEFAULT 13

#define A_PIN_DEFAULT 23
#define B_PIN_DEFAULT 19
#define C_PIN_DEFAULT 5
#define D_PIN_DEFAULT 17
#define E_PIN_DEFAULT -1 // Change to a valid pin if using a 64 pixel row panel.

#define LAT_PIN_DEFAULT 4
#define OE_PIN_DEFAULT 15

#define CLK_PIN_DEFAULT 16

//-----------------------------------------------------//

Here is my replace list of #defines

#define R1_PIN_DEFAULT 32
#define G1_PIN_DEFAULT 14
#define B1_PIN_DEFAULT 15
#define R2_PIN_DEFAULT 27
#define G2_PIN_DEFAULT 33
#define B2_PIN_DEFAULT 12

#define A_PIN_DEFAULT 4
#define B_PIN_DEFAULT 36
#define C_PIN_DEFAULT 39
#define D_PIN_DEFAULT 34
#define E_PIN_DEFAULT -1 // Change to a valid pin if using a 64 pixel row panel.

#define LAT_PIN_DEFAULT 16
#define OE_PIN_DEFAULT 17

#define CLK_PIN_DEFAULT 13

Option to change how pixels are addressed on the grid.

I've set up a simple little demo with an EPS32 and 2 64x32 panels and it all works, this is more of a quality of life/ease of use sorta thing.

So instead of the traditional layout description where all the panels are connected in one long row I'd like to work with them in one long column. I'm not talking stacked I'd like to run them end to end. For instance lets say I have 5 panels; with the current chaining method I could (theoretically, not tested) create a chain of 320 wide by 32 high, however I'm looking for 32 wide and 320 high.

I think this could be faked by having the options to swap out where the defined coordinate lands, as the rest of the chaining seems to work fine. I considered just writing a shim function to do that but since X and Y change positions it doesn't seem like it'll be as smooth a process as I imagined (I come from a web dev background where higher level languages would make this simpler).

It's possible there is a way to do this with the virtual display library but it seemed like it was the only option not supported.

Edit I've noticed another quirk about my panel, it's not RGB, it's RBG. I built a simple sketch to confirm, a way to change that would be nice as well, something I can define on setup to do the swap on the library side would be nice to de-clutter the sketch.

Slowdown (or little freeze) during the animation

Hello,

I come back to you to ask if you have noticed a slowdown problem during the running of the animated gifs. I first asked the author of the AnimatedGIFs library, I specified all the details that I observed, but it does not use too much esp32.
If you have a moment, I suggest you read directly what I wrote here :
pixelmatix/AnimatedGIFs#24

It's not a serious or urgent problem, it's just to know if you have an idea :-)

Best regards.
Patrick BESSE.

add in color333

Too lazy to do a pull request.

Can you add in Color333 support also in ESP32-RGB64x32MatrixPanel-I2S-DMA.h

// Promote 3/3/3 RGB to Adafruit_GFX 5/6/5 RRRrrGGGgggBBBbb
uint16_t 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);}

updates and other libs

Hi mrfaptastic, I tried to send you Email but it bounced. If you Email me at marc at merlins.org, happy to take this off a github issue where it might not quite belong ;)
I also Cc Rory who did the 128x64 ESP32 furret with SmartMatrix. I'm not sure
if your lib would offer him more free memory in that resolution
https://github.com/rorosaurus/FurretTotem https://www.youtube.com/watch?v=Q7uGj0VHFyQ

As you know, last year, I ended up concentrating on SmartMatrix as it
supported more panels types than your library, including chaining in
various ways all the way to 128x128 (which actually can work on teensy
3.6, although only barely. ESP32 is limited to 128x64 due to DMA RAM).

I saw you made some updates to your lib, and I was curious if it's still
superior in any way to SmartMatrix, or if it's just a personal project
that you're happy to keep maintaining, because why not? :)

Since last year, I did a crapload of work with RGBPanels.

The most relevant thing is a big collection of multi API backends (I
support Adafruit::GFX, FastLED:NeoMatrix, and LEDMatrix).
I saw you spent time re-porting Aurora demos to GFX independently from me :)
(sorry, I wish we had been able to share and I'd have avoided you the
work of doing it too).

Please have all my demos here:
https://github.com/marcmerlin/FastLED_NeoMatrix_SmartMatrix_LEDMatrix_GFX_Demos
to steal all my demos :)

That said, for the non GFX ones, if you're interested in using your
library over SmartMatrix, please look at
https://github.com/marcmerlin/FastLED_NeoMatrix_SmartMatrix_LEDMatrix_GFX_Demos/blob/master/neomatrix_config.h
and
https://github.com/marcmerlin/Framebuffer_GFX
and
https://github.com/marcmerlin/SmartMatrix_GFX

You'll notice that
https://github.com/marcmerlin/SmartMatrix_GFX/blob/master/SmartMatrix_GFX.cpp
does mostly nothing except handle showptr
The magic happens in
https://github.com/marcmerlin/FastLED_NeoMatrix_SmartMatrix_LEDMatrix_GFX_Demos/blob/beddfb3278852f64bbf2c74886385a2aed15bbeb/neomatrix_
config.h#L162

if you write something equivalent for your lib, then you get all this
demo code for free, including the really cool TableMarkEstes
screenshots:
http://marc.merlins.org/perso/arduino/2019-04.html#Comparing-FastLED_NeoMatrix-and-SmartMatrix_GFX-with-PixelMatrix-Aurora-and-Table-ME-
Demos
old video demo on low res Neopixel array:
https://www.youtube.com/watch?v=SSllLL5SGCg

Now, the reason I bother you :) is to sell you neomatrix_config and
https://github.com/marcmerlin/Framebuffer_GFX :)

If you use them (by simply using SmartMatrix and SmartMatrix::GFX as is,
or making a small glue driver for your library), once you write code
against it using any of the 3 APIs, I mentioned, you get to run it on a
lot of backends:

The last 2 are pretty exciting (I just wrote them a few days ago), as they
allow you to run your code on a linux PC for testing, no arduino required.
The 2nd one is even more cool, it allows you to run your arduino code on a
Raspberry Pi and display on much bigger displays up to at least 256x256.
https://community.pixelmatix.com/t/preannounce-smartmatrix-gfx-and-fastled-neomatrix-on-top-of-rpi/579
https://github.com/marcmerlin/ArduinoOnPc-FastLED-GFX-LEDMatrix
https://github.com/marcmerlin/FastLED_RPIRGBPanel_GFX

Best,
Marc

Alternative method for buffering on 2x2 chained panel

Hello @mrfaptastic
Been great use this librarry, it’s so straight forward and easy to understand.
Currently I’m able to do 2x2 using class VirtualMatrixPanel on panel fm6124 for total res 128x64.
Try simple scroll text, which I need to refresh each frame with fillscreen(0). This make flickering issues.
And I see example about framebuffer, introduce to flipDmaBuffer(), but it’s not available on VirtualMatrixPanel class.

Can you suggest what best way to get rid this flickering on my code?

Thanks

Brownouts / Power usage increase on new version of library

Good news - no more green boogies.

Bad news - the power consumption seems to have increased.
Before I could run plasma test on USB for days without issue, now it lasts about 1/2 second before rebooting without external power.

New library draw -
10% coverage (Conway game of life)
5v/ .46A - Brightness 50
5v/ .32A - Brightness 20
5v/ .27A - Brightness 10
5v/ .25A - Brightness 5

100% coverage (plasma)
5v/ .36A - Brightness 5
5v/ .48A - Brightness 10
5v/ .59A - Brightness 15
5v/ .70A - Brightness 20
Over that = brownout/reset.

Win some, lose some!

Will add in a cap to see if that improves USB power brownout, otherwise will need to add in some code to try modulate power if its going to go over hard limits.

Ghosting 2 pixels to the right

@mrfaptastic Any thoughts on where to start troubleshooting why I would be getting ghosting 2 pixels shifted to the right (see image)? I'm using PanelGFXDemo pretty much stock except for changing the pinouts to match my wiring:

#define R1_PIN_DEFAULT  15
#define G1_PIN_DEFAULT  2
#define B1_PIN_DEFAULT  0
#define R2_PIN_DEFAULT  4
#define G2_PIN_DEFAULT  16
#define B2_PIN_DEFAULT  17

#define A_PIN_DEFAULT   5
#define B_PIN_DEFAULT   18
#define C_PIN_DEFAULT   19
#define D_PIN_DEFAULT   21
#define E_PIN_DEFAULT   -1
          
#define LAT_PIN_DEFAULT 3
#define OE_PIN_DEFAULT  23

#define CLK_PIN_DEFAULT 22

Any thoughts/ideas you have would be much appreciated!

IMG_5838

Wrong wiring guide

The wiring guide in the README.md have the following:

` HUB 75 PANEL ESP 32 PIN
+-----------+
| R1 G1 | R1 -> IO25 G1 -> IO26
| B1 GND | B1 -> IO27
| R2 G2 | R2 -> IO14 G2 -> IO12
| B2 GND | B2 -> IO13
| A B | A -> IO23 B -> IO22
| C D | C -> IO 5 D -> IO17
| CLK LAT | CLK -> IO16 LAT -> IO 4
| OE GND | OE -> IO15 GND -> ESP32 GND
+-----------+

`
The pin B is connected to pin 22
But in the ESP32-RGB64x32MatrixPanel-I2S-DMA.h:

`
#define R1_PIN_DEFAULT 25
#define G1_PIN_DEFAULT 26
#define B1_PIN_DEFAULT 27
#define R2_PIN_DEFAULT 14
#define G2_PIN_DEFAULT 12
#define B2_PIN_DEFAULT 13

#define A_PIN_DEFAULT 23
#define B_PIN_DEFAULT 19
#define C_PIN_DEFAULT 5
#define D_PIN_DEFAULT 17
#define E_PIN_DEFAULT -1 // Change to a valid pin if using a 64 pixel row panel.

#define LAT_PIN_DEFAULT 4
#define OE_PIN_DEFAULT 15

#define CLK_PIN_DEFAULT 16

`
The pin B is connected to pin 19 now.

(And, after finding the problem, I successfully get this library running perfectly on my 32x16 led matrix,just changing the matrix height and width and change the pin E into -1 in the library header file.)

getTextBounds returning an incorrect width

I was centering some text and I realized getTextBounds is returning an incorrect width, I'm not sure if this is a bug with this library or Adafruit GFX.

Here is the code I'm using the test:

dma_display.setTextSize(2);     // size 2 == 16 pixels high

int16_t xOne, yOne;
uint16_t w, h;

dma_display.getTextBounds("BB", 0, 0, &xOne, &yOne, &w, &h);
xPosition = dma_display.width()/2 - w/2 + 1;
Serial.println(w);

dma_display.setCursor(xPosition, 24);
dma_display.print("BB");
  • Physically counting the pixels that the string takes up: 22
  • Serial print of W: 24

It seems to always return 2 pixels bigger, regardless of the length of the string (even a single character)

It can be worked around for centering by just adding 1 pixel to where you calculate, but I thought I would raise it when I saw it.

EDIT: Using the latest library from the library manager (But I was seeing the same before I updated too)

Any issue with AsyncWebServer and AsyncMQTT

Until there I'm using PxMatrix, even if it's working fine, when added heavy stuff such as ayncWebServer or AsyncMQTT there are some issues (ESP32 crash), I'm thinking moving to this DMA version, but has anyone experienced better results and no issues with MQTT and or WebServer implemented on the same time ?

Thanks

I2S clock speed formula

@mrfaptastic I was playing with some i2s values and found some inconsistencies in code/values/formulas, whatever...
So, this code in esp32_i2s_parrallel.c sets divisors for clock generator.

dev->clkm_conf.clkm_div_a=63;
dev->clkm_conf.clkm_div_b=63;
dev->clkm_conf.clkm_div_num=80000000L/(cfg->clkspeed_hz + 1);

To my great surprise I was able to run matrix at ESP32_I2S_CLOCK_SPEED=40000000. Hard to believe, eh, so I checked with scope what was going on at the clk line.

HUB75_clk_20Mhz

X-scale is 10ns per square. So it looks like exactly 20MHz from rising edge to rising edge.

More to this, according to the esp docs i2s clock is sourced from PLL_D2_CLK running at 160MHz which makes it even more mystery to me. Calculating the formula based on 160MHz source should give 80 MHz clk, not 40 and 20.
What do you think?

NodeMCU

will this work with a NodeMCU?

Stutter & freezing when adding wifi control.

Hi i'm having an issue on wifi where it works fine then it freezes it also seems to set the wrong pixels too. Ive attached a video and the code i've used.

I've adapted ArtNet to use these matrix panels.

#include <ArtnetWifi.h>
#include <Arduino.h>
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
MatrixPanel_I2S_DMA matrix;

// Wifi settings
const char* ssid = "Reece-PC";
const char* password = "";
const int numLeds = 2048; // CHANGE FOR YOUR SETUP
const int numberOfChannels = numLeds * 3; // Total number of channels you want to receive (1 led = 3 channels)
// Art-Net settings
ArtnetWifi artnet;
const int startUniverse = 0; // CHANGE FOR YOUR SETUP most software this is 1, some software send out artnet first universe as 0.
const int maxUniverses = numberOfChannels / 512 + ((numberOfChannels % 512) ? 1 : 0);
bool universesReceived[maxUniverses];
bool sendFrame = 1;
int previousDataLength = 0;

int matrixWidth = 64;
int matrixHeight = 32;
boolean ConnectWifi(void)
{
  boolean state = true;
  int i = 0;

  WiFi.begin(ssid, password);
  Serial.println("");
  Serial.println("Connecting to WiFi");

  // Wait for connection
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (i > 20){
      state = false;
      break;
    }
    i++;
  }
  if (state){
    Serial.println("");
    Serial.print("Connected to ");
    Serial.println(ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("");
    Serial.println("Connection failed.");
  }

  return state;
}

int* computeLedPos(int ledNo)
{
  int x = 0;
  int y = 0;
  for (int i = 0; i < ledNo; i++)
  {
    if(y = 32) {
      ++x;
      y = 0;
    }
    ++y;
  }
  static int cords[2];
  cords[0] = x;
  cords[1] = y;
  return cords;
}

void initTest()
{

}

void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data)
{
  sendFrame = 1;
  // set brightness of the whole strip
  if (universe == 15)
  {
    //FastLED.setBrightness(data[0]);
    //FastLED.show();
  }

  // Store which universe has got in
  if ((universe - startUniverse) < maxUniverses) {
    universesReceived[universe - startUniverse] = 1;
  }

  for (int i = 0 ; i < maxUniverses ; i++)
  {
    if (universesReceived[i] == 0)
    {
      //Serial.println("Broke");
      sendFrame = 0;
      break;
    }
  }

  // read universe and put into the right part of the display buffer
  for (int i = 0; i < length / 3; i++)
  {
    int led = i + (universe - startUniverse) * (previousDataLength / 3);
    if (led < numLeds){
      int x = led % matrixWidth;
      int y = led / matrixWidth;
      //Serial.print("X: ");
      //Serial.print(x);
      //Serial.print("Y: ");
      //Serial.print(y);
      //Serial.print("R: ");
      //Serial.print(data[i * 3]);
      //Serial.print("G: ");
      //Serial.print( data[i * 3 + 1]);
      //Serial.print("B: ");
      //Serial.print( data[i * 3 + 2]);
      //Serial.println();
      matrix.drawPixelRGB888(x, y, data[i * 3], data[i * 3 + 1], data[i * 3 + 2]);
      //leds[led] = CRGB(data[i * 3], data[i * 3 + 1], data[i * 3 + 2]);
    }
  }
  previousDataLength = length;

  if (sendFrame)
  {
    matrix.fillScreen(0);
    // Reset universeReceived to 0
    memset(universesReceived, 0, maxUniverses);
  }
}

void setup()
{
  Serial.begin(115200);
  ConnectWifi();
  matrix.begin();
  matrix.fillScreen(0);
  artnet.begin();
  initTest();
  artnet.setArtDmxCallback(onDmxFrame);
}

void loop()
{
  // we call the read function inside the loop
  artnet.read();
} 

Only a few pixels at the top are being set too that maybe me doing the wrong calculation however as the orignal example used FastLED which sets leds using:

leds[led] = CRGB(data[i * 3], data[i * 3 + 1], data[i * 3 + 2]);

And i do:

int x = led % matrixWidth; int y = led / matrixWidth; matrix.drawPixelRGB888(x, y, data[i * 3], data[i * 3 + 1], data[i * 3 + 2]);

Any help would be greatly appreicated.

VID_118971226_003316_604.mp4

64x64 Matrix not showing anything, when used as 64x32 works (partly)

Hello,

ive got a P2 64x64 (1/32 scan) module that works fine with the PxMatrix library. Now with the DMA library i have a hard time getting it working correctly. The aurora demo works only when i define the panel to be a 64x32, then it will run the demo but the picture has "gaps" as x32 is wrong of course. If i configure it to be 64x64 the screen stays blank, console output is working. I assume this has to do with the E pin (which is working fine with PxMatrix) but not DMA. I tried relocating it to a different pin, same effect.
Not sure if this is related: with PxMatrix i had to set a muxDelay for the B channel, otherwise i would get gaps in the image.

What could be wrong or how can i debug this further?

Can't compile after last updates.

Can't compile after last updates. Code was working two weeks ago.
Now i get:

In file included from /home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:9:0:
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.h:13:17: fatal error: GFX.h: No such file or directory
compilation terminated.

image

I opened Layer.h and changed line number 13 from #include <GFX.h> to #include <Adafruit_GFX.h>

After this I get:

In file included from /home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:9:0:
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.h:14:21: fatal error: FastLed.h: No such file or directory
compilation terminated.

image

I'm using linux and on linux capital letters matters, so I changed line number 14 from #include <FastLed.h> to #include <FastLED.h>

I now i get a lot of errors:

In file included from /home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.h:14:0,
                 from /home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:9:
/home/dinux/Arduino/libraries/FastLED/FastLED.h:14:21: note: #pragma message: FastLED version 3.003.003
 #    pragma message "FastLED version 3.003.003"
                     ^
In file included from /home/dinux/Arduino/libraries/FastLED/FastLED.h:65:0,
                 from /home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.h:14,
                 from /home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:9:
/home/dinux/Arduino/libraries/FastLED/fastspi.h:130:23: note: #pragma message: No hardware SPI pins defined.  All SPI access will default to bitbanged output
 #      pragma message "No hardware SPI pins defined.  All SPI access will default to bitbanged output"
                       ^
In file included from /home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.h:15:0,
                 from /home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:9:
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/ESP32-RGB64x32MatrixPanel-I2S-DMA.h:2:17: note: #pragma message: Please update your include to use ESP32-HUB75-MatrixPanel-I2S-DMA.h instead!
 #pragma message "Please update your include to use ESP32-HUB75-MatrixPanel-I2S-DMA.h instead!"
                 ^
In file included from /home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:9:0:
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.h:32:1: error: expected class-name before '{' token
 {
 ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.h: In constructor 'Layer::Layer(RGB64x32MatrixPanel_I2S_DMA&)':
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.h:38:46: error: class 'Layer' does not have any field named 'GFX'
   Layer(RGB64x32MatrixPanel_I2S_DMA &disp) : GFX (LAYER_WIDTH, LAYER_HEIGHT) {
                                              ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp: In member function 'void Layer::drawCentreText(const char*, textPosition, const GFXfont*, CRGB, int)':
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:100:21: error: 'setTextWrap' was not declared in this scope
    setTextWrap(false);
                     ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:103:26: error: 'setFont' was not declared in this scope
      setFont((GFXfont *)f);
                          ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:105:14: error: 'setFont' was not declared in this scope
      setFont(); // use default
              ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:109:45: error: 'getTextBounds' was not declared in this scope
    getTextBounds(buf, 0, 0, &x1, &y1, &w, &h); //calc width of new string
                                             ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:126:40: error: 'setCursor' was not declared in this scope
      setCursor((LAYER_WIDTH - w) / 2, 0); // top 
                                        ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:128:55: error: 'setCursor' was not declared in this scope
      setCursor((LAYER_WIDTH - w) / 2, LAYER_HEIGHT - h);
                                                       ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:130:61: error: 'setCursor' was not declared in this scope
      setCursor((LAYER_WIDTH - w) / 2, (LAYER_HEIGHT - h) / 2); // top 
                                                             ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:142:33: error: 'setCursor' was not declared in this scope
      setCursor(wstart, h+yadjust); // top 
                                 ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:144:50: error: 'setCursor' was not declared in this scope
      setCursor(wstart+1, (LAYER_HEIGHT-1)+yadjust);
                                                  ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:146:61: error: 'setCursor' was not declared in this scope
      setCursor( wstart, ((LAYER_HEIGHT/2) + (h/2)) + yadjust);
                                                             ^
/home/dinux/Arduino/libraries/ESP32-HUB75-MatrixPanel-I2S-DMA-master/Layer.cpp:153:58: error: 'setTextColor' was not declared in this scope
    setTextColor(this->color565(color.r, color.g, color.b)); // Need to confirm from FastLed CRGB to adafruit 565
                                                          ^
exit status 1
Error compiling for board ESP32 Dev Module.

What i'm doing here wrong?
Should I install some additional libraries?

all columns shifted one pixel left, column 0 is shown on right side of panel

Thanks for this work, I plan to use that lib as it works best of all I saw.
However one thing I cannot easily find how to correct:
I use a standard p3 panel 64x32, 1/16 scan. All works so far, but all pixels with x=0 show on the rightmost column instead of the leftmost, and all pixels with x=63 show on column 63 instead 64. So all pixels are shifted left one column, and the leftmost appears at column 64.

I wonder why since my panel is standard and I also used it already with other libs.
Thanks in advance!

Animations can look bad on video to refresh sync mismatch between camera and panel

See https://www.youtube.com/watch?v=MZSxv4Knk0c

This is probably totally unfixable, and in some way the artifact looks better on your library than SmartMatix since yours does full frame updates before looping back for PWM levels.
That being said, it seems that there is no good way to get those panels to look good in pictures or video whether you do PWM per line or PWM per full frame.

Feel free to close this if you agree that there is no good fix and it's an issue with the technology. Fix of course would be to use a neomatrix panel instead, but those don't come in pitch 5, 4, or 3 last I checked.

Problem with chaining panels 2x2

Good day and thank you in advance for such a great library and examples!

I had no issue with using the library with a single panel, as everything worked as expected. However, if I chain up a total of 4 panels (each are 64x32 in size) I get the following error on the serial port:

ERROR: MATRIX_WIDTH and/or MATRIX_HEIGHT in 'ESP32-HUB75-MatrixPanel-I2S-DMA.h'
is not configured correctly for the requested VirtualMatrixPanel dimensions!

I am using the example ChainedPanels sketch with the added defines of

#define MATRIX_WIDTH 128
#define MATRIX_HEIGHT 64

to represent the total pixels of the virtualized 4 panels.

The other defines are unchanged:

#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.

#define NUM_ROWS 2 // Number of rows of chained INDIVIDUAL PANELS
#define NUM_COLS 2 // Number of INDIVIDUAL PANELS per ROW

I am confused as to why the error message is generated, as my setup seems to match the examples listed in the comments. Can anyone shed some light as to how I am misunderstanding or misconfiguring the library?

Thanks in advance!

Cheers,

Sam

External RAM

do you plan to implement PSRAM in the future?

there would be more opportunities.

or maybe it already works? just need to esp32 accordingly with PSRAM

Great version 1.2.2, but little problem with slow brightness adjustment.

Hello mrfaptastic,

I just updated your library to version 1.2.2 and it still works fine.
Since this version, the whites are perfect, and the colors are more contrasted.

I am using an ESP32 is two in-line RGB LED matrices (128x32)
And to get a good fluidity of the texts I increased min_refresh_rate to the value 1600 (I don't know the real limit)

Since this version 1.2.2, I just have a small problem with the "setPanelBrightness" command which no longer acts instantly.
I have a page an html page (in websocket) with a slider that allows you to adjust the brightness.
The slider value is read by setPanelBrightness each time the main loop is passed.

With the previous version the brightness can change immediately when I touch the slider.
Now I have to wait several loop (up to 5/10s) or a reset, for the brightness to change.

However if I display my instant value with Serial.print(myValue) this value changes well in same time with the cursor, but the setPanelBrightness command is much slower.

Did you change anything around the brightness setting?
Or do you have an idea?

Thank you for your work and your responses.

Drawing in different orientations

Hi everyone,

would it be possible to write text in different orentations? I have a 64x32 panel, but I would like to use it lengthwise and write text into it. So it would function as a 32x64 panel. Would this be possible and if so, how?

AnimatedGIFPanel example error

Hello, this is AnimatedGIFPanel example error.
No change was made in the original example.
Sketch data already uploaded.
I dont know why...

아두이노:1.8.13 (Windows 10), 보드:"WEMOS D1 MINI ESP32, 80MHz, Default, 240MHz (WiFi/BT), 115200"

C:\Users\inhyu\Documents\Arduino\libraries\ESP32-RGB64x32MatrixPanel-I2S-DMA-master\examples\AnimatedGIFPanel\AnimatedGIFPanel.ino: In function 'void ShowGIF(char*)':

AnimatedGIFPanel:171:82: error: invalid conversion from 'void* ()(char, int32_t*) {aka void* ()(char, int*)}' to 'void* ()(const char, int32_t*) {aka void* ()(const char, int*)}' [-fpermissive]

if (gif.open(name, GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw))

                                                                              ^

In file included from C:\Users\inhyu\Documents\Arduino\libraries\ESP32-RGB64x32MatrixPanel-I2S-DMA-master\examples\AnimatedGIFPanel\AnimatedGIFPanel.ino:23:0:

C:\Users\inhyu\Documents\Arduino\libraries\AnimatedGIF\src/AnimatedGIF.h:138:9: note: initializing argument 2 of 'int AnimatedGIF::open(const char*, void* ()(const char, int32_t*), void ()(void), int32_t ()(GIFFILE, uint8_t*, int32_t), int32_t ()(GIFFILE, int32_t), void ()(GIFDRAW))'

 int open(const char *szFilename, GIF_OPEN_CALLBACK *pfnOpen, GIF_CLOSE_CALLBACK *pfnClose, GIF_READ_CALLBACK *pfnRead, GIF_SEEK_CALLBACK *pfnSeek, GIF_DRAW_CALLBACK *pfnDraw);

     ^

exit status 1

invalid conversion from 'void* ()(char, int32_t*) {aka void* ()(char, int*)}' to 'void* ()(const char, int32_t*) {aka void* ()(const char, int*)}' [-fpermissive]

Example of using multiple panels in a non standard layout

Hello,

First, thanks a lot of the library, it is working great! Much appreciated.

I have made a shield for using this library with the D1 mini style ESP32 board (if you want one @mrfaptastic , I would be more than happy to donate one) and someone wanted to arrange their panels vertically rather than horizontally and I came up with this fairly hacky, but very simple solution that I wanted to share.

https://github.com/witnessmenow/ESP32-i2s-Matrix-Shield/tree/master/examples/MultiplePanelVirtualScreenPatternPlasma

I'm creating a virtual display using AdafruitGFX where the user configures how their panels are laid out and it will look after the mapping of the pixels for them. A reference to this library is passed into the virtual displays constructor. I've implemented the same virtual calls as this library so you should be able to just swap out the matrix calls with the virtual display.

It should be flexible enough to be used with panels arranged in rows and columns too. There is possibly a better way of doing this, but this was one idea I had that I thought would be really simple for end users to use.

I noticed earlier that you updated to GFX, I haven't got a chance to try that out instead with the virtual display, its still using AdafruitGFX.

The example linked is patternPlasma, but I also tried it out on Aurora and it worked fine too. (I only have two panels though)

Just as a BTW, Aurora was running out of memory for me originally, but I noticed in #23 that you had mentioned that you updated some things to free up some, so I updated to version from about 8 hours ago (I see you have updated since!) and now it's working perfectly.

Render 128x64 in 4 panel

Hi @mrfaptastic ,

i did some test by chaining 2x1 panel to display 128(W)x32(H) by changing MATRIX_WIDTH to 128 and it render the gifs without any issue. i am planning to create a 128(W)x64(H) by chaining 4 panel in 2x2 configuration. is it possible to render gif using 2x2 configuration?
if i set the MATRIX_WIDTH to 256. It will be define by the library as 4(W)x1(H) and will not able to display in 2x2 configuration right?. Any specific changes that i could do to achieve 2x2 configuration?

Thank you.

Draw gif animation

Hi mrfaptastic, i want to thank you so much for such a great library and afford you did to deliver this library.

I would like to have this library to be capable on drawing gif animation as was previously done by the Sprite_TM but my knowledge, capability on writing good codes and understanding all the technic written in the library are very limited.
I have issue to reimplement back the gif animation code as below:

#include "anim.h"
inline void MatrixPanel_I2S_DMA::drawGif() {

    int apos=0; //which frame in the animation we're on
    int backbuf_id=0; //which buffer is the backbuffer, as in, which one is not active so we can write to it
    while(1) {
        //Fill bitplanes with the data for the current image
        const uint8_t *pix=&anim[apos*64*32*3];     //pixel data for this animation frame
        for (int pl=0; pl<ROWS_PER_FRAME; pl++) {
            int mask=(1<<(8-ROWS_PER_FRAME+pl)); //bitmask for pixel data in input for this bitplane

            //uint16_t *p=bitplane[backbuf_id][pl]; //bitplane location to write to

            rowColorDepthStruct *fb_row_malloc_ptr = (rowColorDepthStruct *) matrix_row_framebuffer_malloc[pl];
            // The destination for the pixel bitstream
            rowBitStruct *pRowBitStruct = &fb_row_malloc_ptr[back_buffer_id].rowbits[pl]; //matrixUpdateFrames location to write to uint16_t's
            uint16_t *p= pRowBitStruct->data;

            for (unsigned int y=0; y<16; y++) {
                int lbits=0;                //Precalculate line bits of the *previous* line, which is the one we're displaying now
                if ((y-1)&1) lbits|=BIT_A;
                if ((y-1)&2) lbits|=BIT_B;
                if ((y-1)&4) lbits|=BIT_C;
                if ((y-1)&8) lbits|=BIT_D;
                for (int fx=0; fx<64; fx++) {

	#if DISPLAY_ROWS_SWAPPED
						int x=fx^1; //to correct for the fact that the stupid LED screen I have has each row swapped...
	#else
						int x=fx;
	#endif

                    int v=lbits;
                    //Do not show image while the line bits are changing
                    if (fx<1 || fx>=brightness) v|=BIT_OE;
                    if (fx==62) v|=BIT_LAT; //latch on second-to-last bit... why not last bit? Dunno, probably a timing thing.

                    //int c1, c2;
                    int c1=getpixel((uint8_t*)pix, x, y);
                    int c2=getpixel((uint8_t*)pix, x, y+16);
                    if (c1 & (mask<<16)) v|=BIT_R1;
                    if (c1 & (mask<<8)) v|=BIT_G1;
                    if (c1 & (mask<<0)) v|=BIT_B1;
                    if (c2 & (mask<<16)) v|=BIT_R2;
                    if (c2 & (mask<<8)) v|=BIT_G2;
                    if (c2 & (mask<<0)) v|=BIT_B2;

                    //Save the calculated value to the bitplane memory
                    *p++=v;
                }
            }
        }

        //Show our work!
        i2s_parallel_flip_to_buffer(&I2S1, backbuf_id);
        backbuf_id^=1;
        //Bitplanes are updated, new image shows now.
       //vTaskDelay(100 / portTICK_PERIOD_MS); //animation has an 100ms interval

		apos++;
    	if (apos>=12) apos=0;

    }

Basically i did not know how to write the plane and update the display as per new struct structure that was implemented. I hope you can shed some light as how to write to the struct and properly update the matrix.
Thank you in advance.

Cheers,
TS

Using a 16x32 Display - possible? - Done with virtual panel & with Text and scrolling function

I have a 16x32 HUB75 Display running.
If I use the rainbow example (with original MATIRX_HEIGHT 32, MATRIX_WIDTH 64 and I compile the file - it works, I will see fancy color shades on the display

If I try to work with printing (example: DoubleBufferSwap) text - it didn't work, can't read any characters :-O
If I remove all swapping buffers and use only one buffer for displaying - not readable text is shown

Change (hardcoded) inside EPS32_HUBxxxx .h file height/width to 16 and 32 than I see two lines, to black lines, two lines, .... (see screenshots)

What can I do to use such a 16x32 display?

Thanks in advance
Bernd

P.S I use this display
https://de.aliexpress.com/item/33017477904.html?spm=a2g0o.detail.1000023.16.1fedd556Yw52Zi&algo_pvid=4329f1c0-04d2-43d9-bdfd-7d4ee95e6b40&algo_expid=4329f1c0-04d2-43d9-bdfd-7d4ee95e6b40-52&btsid=9a8bf2b5-334b-45ea-a849-063d7461362e&ws_ab_test=searchweb0_0,searchweb201602_10,searchweb201603_60[AliExpress%2016x32]

IMG_4421
IMG_4422

HEIGHT=16, WIDTH=32
IMG_4424

Column 65 is repeated on column 1

Hello,

I am testing your DMA library, and I am very surprised by the result.
The color management is superior to other libraries, and the flickerings are really reduced.

I find just a small display defect that I can not correct myself, but maybe you have an idea.

When drawing a text or rectangle smaller than the width of the LED panel (less than 64 pixels) the text or drawing is displayed correctly.
But if the text or drawing is larger than the panel, or shifted to the right, the contents of column 65 (which should not be visible) are superimposed on column 1.
This defect is also very visible and annoying if you scroll through the text.

Thank you for telling me if you have a solution, and thank you very much for your work.
Best Regards.
P.B.

Display resetting when using setFont

If I comment out line 43 my project runs... when left as is - the display resets when the print function is called.

What am I missing?

Any help very much appreciated

// Test the RGB64x32MatrixPanel_I2S_DMA setFont Function

#include <Arduino.h>
#include <ESP32-RGB64x32MatrixPanel-I2S-DMA.h>
#include <Fonts/FreeSans9pt7b.h>

RGB64x32MatrixPanel_I2S_DMA matrix;

////////////////////////////////////////////////////////////////////
// Font Test
//
//
// pinout for ESP32 38pin module
//

// R1 | G1
// B1 | GND
// R2 | G2
// B2 | E
// A | B
// C | D
// CLK| LAT
// OE | GND

#define R1 25
#define G1 27
#define BL1 26
#define R2 14 // 21 SDA
#define G2 13 // 22 SDL
#define BL2 12
#define CH_A 23
#define CH_B 19
#define CH_C 5
#define CH_D 17
#define CH_E -1 // assign to pin if using two panels
#define CLK 16
#define LAT 4
#define OE 15

void setup(){

matrix.setFont(&FreeSans9pt7b); // This command causes a reset

// If you experience ghosting, you will need to reduce the brightness level, not all RGB Matrix
// Panels are the same - some seem to display ghosting artefacts at lower brightness levels.
// In the setup() function do something like:

matrix.setPanelBrightness(10); // SETS THE BRIGHTNESS HERE. 60 OR LOWER IDEAL.
matrix.begin(R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK); // setup the LED matrix
matrix.setTextColor(matrix.color444(255, 255, 255)); // r,g,b
matrix.setCursor(6, 7);
matrix.print("Leeds 4");
matrix.setTextColor(matrix.color444(255, 0, 0)); // r,g,b
matrix.setCursor(6, 17);
matrix.print("Man Utd 0");

}

void loop()
{

}

drawIcon

Another small function for the library.
Could I get commit access?

void drawIcon (int *ico, int16_t x, int16_t y, int16_t cols, int16_t rows);

inline void RGB64x32MatrixPanel_I2S_DMA::drawIcon (int *ico, int16_t x, int16_t y, int16_t cols, int16_t rows) {
int i, j;
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
drawPixelRGB565 (x + j, y + i, ico[i * cols + j]);
}
}
}

Power supply and usb connection

Sorry if this is not the right place to ask this question. Is it possible to have the ESP32 connected to the computer USB port while powering the matrix with an AC adapter? Should the ESP32 Vin pin be connected to the AC adapter?

Thanks in advance

64x64 Panel

FYI -

I have tested with a P2.5 64x64 panel with Line E, and H file MATRIX_HEIGHT modified for 64x64

Testing working, and have a plasma test running, but the colors seem slightly different on the left / right side, which looks like image is cut in 2.

I see the code is doing Panel Upper / Panel Lower, will fiddle a little see if I can resolve.

3291553227471_ pic

2x62x23 Panel Color changed in the middle

I have two panels 64x32 panels chained with default pins and an esp32. I can control everything. But the color changed in the middle of each panel (from red to green).(see diagonal Line)

WhatsApp Image 2021-01-13 at 15 02 35

Do anyone now what the problem is?

Settings:

#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module. 
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.

#define NUM_ROWS 2 // Number of rows of chained INDIVIDUAL PANELS
#define NUM_COLS 1 // Number of INDIVIDUAL PANELS per ROW


/**************************
 * Create physical DMA panel class AND virtual (chained) display class.   
 **************************/
#include <ESP32-VirtualMatrixPanel-I2S-DMA.h>
MatrixPanel_I2S_DMA dma_display;
VirtualMatrixPanel       virtualDisp(dma_display, NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, true, true);

Connection ESP<-> Panel
HUB 75 PANEL ESP 32 PIN

+-----------+   
|  R1   G1  |    R1  -> IO25      G1  -> IO26
|  B1   GND |    B1  -> IO27
|  R2   G2  |    R2  -> IO14      G2  -> IO12
|  B2   E   |    B2  -> IO13      E   -> N/A	(required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32 )
|   A   B   |    A   -> IO23      B   -> IO19
|   C   D   |    C   -> IO 5      D   -> IO17
| CLK   LAT |    CLK -> IO16      LAT -> IO 4
|  OE   GND |    OE  -> IO15      GND -> ESP32 GND
+-----------+

Red flickering when two 64x32 panels are chained

What i've done:

  • Verified my wiring is correct using continuity test on multimeter
  • Tried master + all released versions of this library

The displays work fine individually but when connected together the red flickers a lot. I have written this example to demonstrate:

#define MATRIX_WIDTH 128 // These don't work, something that would be nice to fix :)
#define MATRIX_HEIGHT 32

#include <ESP32-RGB64x32MatrixPanel-I2S-DMA.h>
#define MATRIX_WIDTH 128
#define MATRIX_HEIGHT 32
RGB64x32MatrixPanel_I2S_DMA matrix;

void setup()
{ 
  // MUST DO THIS FIRST!
  matrix.begin();  // Use default pins supplied within ESP32-RGB64x32MatrixPanel-I2S-DMA.h
  // matrix.begin(R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN );  // or custom pins

  matrix.fillRect(9,9, 9, 9,  matrix.color565(255,255,255)); // can do this after .begin() only
  matrix.fillRect(18,9, 9, 9,  matrix.color565(255,0,0)); // can do this after .begin() only
  matrix.fillRect(9,18, 9, 9,  matrix.color565(0,255,0)); // can do this after .begin() only
  matrix.fillRect(18,18, 9, 9,  matrix.color565(0,0,255)); // can do this after .begin() only
  Serial.begin(9600);
}

void loop()
{
    Serial.println("Loop");
    delay(1000);
  
}

With just one panel:

image

(Tough to take a good photo, but all rectangles are lit up correctly and don't flicker)

With two panels (chained but width set to 64):

image

Close up of right:

image

When width is set to 128 in the .h file the display is similar to the above picture. There is slightly less flickering.

Would love to get some hints on how to debug this, seems like it could just be a simple change somewhere so I'd love to give fixing it a shot.

FM6126A Hardware Brightness Control

@vortigont - Raising an issue to track your inital investigations into the FM6126A registers.

Can you send a link to one of these panels you bought - it would be interesting to get one of these and also start randomly bit-banging the control registers to see what happens.

If the FM6126A's have hardware brightness control, then that pretty much makes the PWM based brightness redundant - or could be used in combination to massively increase color depth.

I'm also curious as to how fast these registers could be bit-banged, as I might explore the possiblity to embedding the control stuff as part of the DMA buffer itself as well.

Consider changing the name of the library?

I wonder does the "64x32" part of the library name put people off using it? I have used it extensively on a 64x64 and have had no issues. I know several people who have used it on 32x16 panels and it has also worked perfectly

Just a suggestion :)

Please help review RGBPanel library comparison

If you have a bit of time, could I ask you to review this writeup I just did?

The choice of APIs and backend drivers can be a bit confusing, so I've tried to write a summary.
https://github.com/marcmerlin/SmartMatrix_GFX/blob/master/README.md

Could you look it over and send me edits if applicable you can click edit in github and it'll send me a pull request.
Once it looks ok, I'll share it with Adafruit, Louis and you so that each lib can summarize the ecosystem out there and help users make the right choice for their needs.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.