mrcodetastic / ESP32-HUB75-MatrixPanel-DMA

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.
MIT License
930 stars 205 forks source link

1/8 Scan Panel support - 64 x 32 panel horizontal lines doubled #154

Closed donnersm closed 2 years ago

donnersm commented 3 years ago

I just tested a panel i just received today. Its a 64 x 32 panel. It looks like the horizontal is not working, lines are doubled in an array of 8 Anyone recognise this or is this a defective panel? (Beside from the defective pixel near one corner)

https://user-images.githubusercontent.com/60584210/126544627-5c615cfe-e9d1-433f-962e-325da9e36a2a.mp4

mrcodetastic commented 2 years ago

You can't use the Aurora demo as is, it uses the underlying library which is 1/16 only.

You will need to merge the Aurora demo code with the new '1_8_ScanPanel.h' example and call this object instead of the underlying dma_display object which is designed electrically for 1/16 panels only.

danieldecesaro commented 2 years ago

Hello @mrfaptastic, I'm using 1/8 scan panels and I'm testing two types of panels with their example firmware. In one of them everything works as expected, but in another there is an error in the coordinates.

The video of the two panels follows.

  1. This one works: IMG_20211122_143101

https://user-images.githubusercontent.com/40169434/142909792-e9c91b03-2da8-442d-bece-91d73ca3fb30.mp4

  1. This one has problems: IMG_20211122_143122

https://user-images.githubusercontent.com/40169434/142909637-3c0ece68-f4d8-4607-8948-7fd5d35881f7.mp4

I'm grateful if you can help me.

Thanks for your work!

Att. Daniel

mrcodetastic commented 2 years ago

Wow. Sorry to say that is yet another 1/8 panel variant with some super weird addressing scheme. They are different panels it seems. Can't help you as I don't have one of these I'm afraid.

It's almost like these Chinese manufacturers try and make a new variant every week.

board707 commented 7 months ago

You need a kind of reverse engineering to determine scan.

muslihrizal commented 7 months ago

You need a kind of reverse engineering to determine scan.

can help with setting the coordinates, still confused

board707 commented 7 months ago

try this

inline VirtualCoords OneEightScanPanel::getCoords(int16_t &x, int16_t &y) {
  VirtualMatrixPanel::getCoords(x, y); // call to base to update coords for chaining approach

  if ( coords.x == -1 || coords.y == -1 ) { // Co-ordinates go from 0 to X-1 remember! width() and height() are out of range!
    return coords;
  }

  if ( (y / 8) == 0) { 
    coords.x += ((coords.x / 32)+1)*32; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
  }
  else {
    coords.x += (coords.x / 32)*32; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer
  }

  // http://cpp.sh/4ak5u
  // Real number of DMA y rows is half reality
  // coords.y = (y / 16)*8 + (y & 0b00000111);   
  coords.y = (y >> 4)*8 + (y & 0b00000111);   

  return coords;
}
board707 commented 7 months ago

sorry, just typo. try this

inline VirtualCoords OneEightScanPanel::getCoords(int16_t &x, int16_t &y) {
  VirtualMatrixPanel::getCoords(x, y); // call to base to update coords for chaining approach

  if ( coords.x == -1 || coords.y == -1 ) { // Co-ordinates go from 0 to X-1 remember! width() and height() are out of range!
    return coords;
  }

  if ( (y & 8) == 0) { 
    coords.x += ((coords.x / 32)+1)*32; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
  }
  else {
    coords.x += (coords.x / 32)*32; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer
  }

  // http://cpp.sh/4ak5u
  // Real number of DMA y rows is half reality
  // coords.y = (y / 16)*8 + (y & 0b00000111);   
  coords.y = (y >> 4)*8 + (y & 0b00000111);   

  return coords;
}
muslihrizal commented 7 months ago

Saya mencoba 1 baris dan 2 panel kolom, sepertinya terlihat normal Gambar 09-02-2024 pukul 23 08 20

` #define PANEL_RES_X 64 // Jumlah piksel lebar setiap modul panel INDIVIDU. #define PANEL_RES_Y 32 // Jumlah piksel tinggi setiap modul panel INDIVIDU.

  #define NUM_ROWS 1 // Number of rows of chained INDIVIDUAL PANELS
  #define NUM_COLS 2 // Number of INDIVIDUAL PANELS per ROW
  #define PANEL_CHAIN NUM_ROWS*NUM_COLS    // total number of panels chained one to another

  // Change this to your needs, for details on VirtualPanel pls read the PDF!
  #define SERPENT true
  #define TOPDOWN true

`

IMG_20240209_212221

board707 commented 7 months ago

Hi Where you added my virtual co-ordinates code that I wrote to help you two weeks ago?

board707 commented 7 months ago

Please show your ESP32-HUB75-VirtualMatrixPanel-I2S-DMA.h file

board707 commented 7 months ago

As I see, you use a ESP32-HUB75-VirtualMatrixPanel-I2S-DMA.h file from a quite old library version. This file does not include a standard coordinate transformations for connecting multiple panels. Try adding this part of the code from the latest version.

@mrfaptastic Why is getCoords() method specified as private in new versions of the library? This make it difficult to inherit from a VirtualMatrixPanel class and will not allow user to create your own variants of the method...

mrcodetastic commented 7 months ago

Feel free to raise a pull request to fix that. You are right, it does not make sense to have it private.

muslihrizal commented 7 months ago

Thank you, it can turn on normally

![Uploading IMG_20240210_213940.jpg…]()

FabioRoss commented 1 month ago

found this wierd 32x32 1/8 scan panel and tried to get it to work with virtual panel class but wasn't able to.

Found out that it works by dividing it into two 16px wide columns and X coordinate sets the position of Y by adding either 16 or 32 to send lines to second half of the scan or second column of the screen

I had to add 64 to every X to make it show in the panel, i think it's because of the chaining that i set up accordingly to previous comments up here

weird_led_panel_32_32

//Libraries for LED Matrix Panel
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
#include <ESP32-VirtualMatrixPanel-I2S-DMA.h>

//-- PINS --//

//LED Matrix Panel Control Pins
#define R1_PIN  25 //32
#define G1_PIN  33
#define B1_PIN  32 //25
#define R2_PIN  14 //26
#define G2_PIN  27
#define B2_PIN  26 //14
#define A_PIN   16
#define B_PIN    4
#define C_PIN    0
#define D_PIN   -1 //2
#define E_PIN   -1 //17
#define LAT_PIN 12
#define OE_PIN  13
#define CLK_PIN 15

//LED Matrix Panel Data
#define MATRIX_WIDTH  32    // Number of pixels wide of each INDIVIDUAL panel module. 
#define MATRIX_HEIGHT 32    // Number of pixels tall of each INDIVIDUAL panel module.
#define PANEL_RES_X   32    // Number of pixels wide of each INDIVIDUAL panel module. 
#define PANEL_RES_Y   32    // Number of pixels tall of each INDIVIDUAL panel module.
#define PANEL_CHAIN    2    // Total number of panels chained one to another

//-- VARIABLES --//

MatrixPanel_I2S_DMA *dma_display = nullptr;

void testScreen() {
  for (int x=0; x < 16; x++) {

    // Red 8 Rows left column
    dma_display->drawPixel(64+(x),0,dma_display->color565(255, 0, 0)); // ROW 1
    dma_display->drawPixel(64+(x),1,dma_display->color565(210, 0, 0)); // ROW 2
    dma_display->drawPixel(64+(x),2,dma_display->color565(180, 0, 0)); // ROW 3
    dma_display->drawPixel(64+(x),3,dma_display->color565(150, 0, 0)); // ROW 4
    dma_display->drawPixel(64+(x),4,dma_display->color565(125, 0, 0)); // ROW 5
    dma_display->drawPixel(64+(x),5,dma_display->color565(90, 0, 0)); // ROW 6
    dma_display->drawPixel(64+(x),6,dma_display->color565(60, 0, 0)); // ROW 7
    dma_display->drawPixel(64+(x),7,dma_display->color565(40, 0, 0)); // ROW 8
    // Red 8 Rows right column
    dma_display->drawPixel(64+32+(x),0,dma_display->color565(255, 0, 0)); // ROW 1
    dma_display->drawPixel(64+32+(x),1,dma_display->color565(210, 0, 0)); // ROW 2
    dma_display->drawPixel(64+32+(x),2,dma_display->color565(180, 0, 0)); // ROW 3
    dma_display->drawPixel(64+32+(x),3,dma_display->color565(150, 0, 0)); // ROW 4
    dma_display->drawPixel(64+32+(x),4,dma_display->color565(125, 0, 0)); // ROW 5
    dma_display->drawPixel(64+32+(x),5,dma_display->color565(90, 0, 0)); // ROW 6
    dma_display->drawPixel(64+32+(x),6,dma_display->color565(60, 0, 0)); // ROW 7
    dma_display->drawPixel(64+32+(x),7,dma_display->color565(40, 0, 0)); // ROW 8

    // Green 8 Rows left column
    dma_display->drawPixel(64+16+x,0,dma_display->color565(0, 255, 0)); // ROW 9
    dma_display->drawPixel(64+16+x,1,dma_display->color565(0, 210, 0)); // ROW 10
    dma_display->drawPixel(64+16+x,2,dma_display->color565(0, 180, 0)); // ROW 11
    dma_display->drawPixel(64+16+x,3,dma_display->color565(0, 150, 0)); // ROW 12
    dma_display->drawPixel(64+16+x,4,dma_display->color565(0, 125, 0)); // ROW 13
    dma_display->drawPixel(64+16+x,5,dma_display->color565(0, 90, 0)); // ROW 14
    dma_display->drawPixel(64+16+x,6,dma_display->color565(0, 60, 0)); // ROW 15
    dma_display->drawPixel(64+16+x,7,dma_display->color565(0, 40, 0)); // ROW 16
    // Green 8 Rows right column
    dma_display->drawPixel(64+16+32+x,0,dma_display->color565(0, 255, 0)); // ROW 9
    dma_display->drawPixel(64+16+32+x,1,dma_display->color565(0, 210, 0)); // ROW 10
    dma_display->drawPixel(64+16+32+x,2,dma_display->color565(0, 180, 0)); // ROW 11
    dma_display->drawPixel(64+16+32+x,3,dma_display->color565(0, 150, 0)); // ROW 12
    dma_display->drawPixel(64+16+32+x,4,dma_display->color565(0, 125, 0)); // ROW 13
    dma_display->drawPixel(64+16+32+x,5,dma_display->color565(0, 90, 0)); // ROW 14
    dma_display->drawPixel(64+16+32+x,6,dma_display->color565(0, 60, 0)); // ROW 15
    dma_display->drawPixel(64+16+32+x,7,dma_display->color565(0, 40, 0)); // ROW 16

    // Blue 8 Rows left column
    dma_display->drawPixel(64+x,8,dma_display->color565(0, 0, 255)); // ROW 17
    dma_display->drawPixel(64+x,9,dma_display->color565(0, 0, 210)); // ROW 18
    dma_display->drawPixel(64+x,10,dma_display->color565(0, 0, 180)); // ROW 19
    dma_display->drawPixel(64+x,11,dma_display->color565(0, 0, 150)); // ROW 20
    dma_display->drawPixel(64+x,12,dma_display->color565(0, 0, 125)); // ROW 21
    dma_display->drawPixel(64+x,13,dma_display->color565(0, 0, 90)); // ROW 22
    dma_display->drawPixel(64+x,14,dma_display->color565(0, 0, 60)); // ROW 23
    dma_display->drawPixel(64+x,15,dma_display->color565(0, 0, 40)); // ROW 24
    // Blue 8 Rows right column
    dma_display->drawPixel(64+32+x,8,dma_display->color565(0, 0, 255)); // ROW 17
    dma_display->drawPixel(64+32+x,9,dma_display->color565(0, 0, 210)); // ROW 18
    dma_display->drawPixel(64+32+x,10,dma_display->color565(0, 0, 180)); // ROW 19
    dma_display->drawPixel(64+32+x,11,dma_display->color565(0, 0, 150)); // ROW 20
    dma_display->drawPixel(64+32+x,12,dma_display->color565(0, 0, 125)); // ROW 21
    dma_display->drawPixel(64+32+x,13,dma_display->color565(0, 0, 90)); // ROW 22
    dma_display->drawPixel(64+32+x,14,dma_display->color565(0, 0, 60)); // ROW 23
    dma_display->drawPixel(64+32+x,15,dma_display->color565(0, 0, 40)); // ROW 24

    // White 8 Rows left column
    dma_display->drawPixel(64+16+x,8,dma_display->color565(255, 255, 255)); // ROW 25
    dma_display->drawPixel(64+16+x,9,dma_display->color565(210, 210, 210)); // ROW 26
    dma_display->drawPixel(64+16+x,10,dma_display->color565(180, 180, 180)); // ROW 27
    dma_display->drawPixel(64+16+x,11,dma_display->color565(150, 150, 150)); // ROW 28
    dma_display->drawPixel(64+16+x,12,dma_display->color565(125, 125, 125)); // ROW 29
    dma_display->drawPixel(64+16+x,13,dma_display->color565(90, 90, 90)); // ROW 30
    dma_display->drawPixel(64+16+x,14,dma_display->color565(60, 60, 60)); // ROW 31
    dma_display->drawPixel(64+16+x,15,dma_display->color565(40, 40, 40)); // ROW 32
    // White 8 Rows right column
    dma_display->drawPixel(64+16+32+x,8,dma_display->color565(255, 255, 255)); // ROW 25
    dma_display->drawPixel(64+16+32+x,9,dma_display->color565(210, 210, 210)); // ROW 26
    dma_display->drawPixel(64+16+32+x,10,dma_display->color565(180, 180, 180)); // ROW 27
    dma_display->drawPixel(64+16+32+x,11,dma_display->color565(150, 150, 150)); // ROW 28
    dma_display->drawPixel(64+16+32+x,12,dma_display->color565(125, 125, 125)); // ROW 29
    dma_display->drawPixel(64+16+32+x,13,dma_display->color565(90, 90, 90)); // ROW 30
    dma_display->drawPixel(64+16+32+x,14,dma_display->color565(60, 60, 60)); // ROW 31
    dma_display->drawPixel(64+16+32+x,15,dma_display->color565(40, 40, 40)); // ROW 32
  }
}

void setup() {
  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(
      MATRIX_WIDTH*2,   // module width
      MATRIX_HEIGHT/2,   // module height
      PANEL_CHAIN,    // Chain length
      _pins // pin mapping
    );

  mxconfig.clkphase = false;
  mxconfig.i2sspeed = mxconfig.HZ_20M;
  mxconfig.min_refresh_rate = 240;
  mxconfig.double_buff = true;

// Display Setup
  dma_display = new MatrixPanel_I2S_DMA(mxconfig);
  dma_display->begin();
  dma_display->setBrightness8(255);

  dma_display->clearScreen();
  testScreen();
  dma_display->flipDMABuffer();
}

void loop() {
}
board707 commented 1 month ago

You don't need such complex conversions. If your matrix virtually corresponds to a 64x16 panel (twice in width and half the height of the real 32x32) - then this configuration is supported by the library out of the box,

FabioRoss commented 1 month ago

Unfortunately i tried the virtual panel solution as per FourScanPanel example and it was not working, hence my calculations...will try to experiment further but after a full day of messing with the virtual panel class i couldn't get the panel to work properly

board707 commented 1 month ago

Unfortunately, the FourScanPanel example slightly buggy. Do you read my tutorial https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/discussions/622 ? I also advise you to look at #635 , starting from 5-6th message

FabioRoss commented 1 month ago

Unfortunately, the FourScanPanel example slightly buggy. Do you read my tutorial #622 ? I also advise you to look at #635 , starting from 5-6th message

Thank you very much! I did not know this existed!

The code works but i have to figure out how to correct the coordinates, i'm not too sure how the code reads

mrcodetastic commented 1 month ago

Unfortunately, the FourScanPanel example slightly buggy. Do you read my tutorial https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/discussions/622 ? I also advise you to look at #635 , starting from 5-6th message

Is there anything that could be fixed with a pull request?

board707 commented 1 month ago

@mrcodetastic Thank you, honesty speaking, I am not sure. You have already accepted two of my PR for VirtualPanel class, perhaps there is still something to correct there, I will take a look.

FabioRoss commented 1 month ago

@mrcodetastic @board707

I was able to get my panel to work correctly but i only tested it on a single panel chain and it doesn't follow the structure of the other expressions because i couldn't understand them, i'll post my code in case anyone gets the same panel

panel is a 32x32 outdoor with MP5020GP chip, it is a 1/8 scan with only ABC pins, D and E are GND

sorry if the code isn't great

/* ================================================== */
// Define custom class derived from VirtualMatrixPanel
class EightPxBasePanel : public VirtualMatrixPanel
{
  public:
    using VirtualMatrixPanel::VirtualMatrixPanel; // inherit VirtualMatrixPanel's constructor(s)

  protected:

    VirtualCoords getCoords(int16_t x, int16_t y);  // custom getCoords() method for specific pixel mapping

};

// define custom getCoords() method for specific pixel mapping
inline VirtualCoords EightPxBasePanel ::getCoords(int16_t x, int16_t y) {

  coords = VirtualMatrixPanel::getCoords(x, y); // first call base class method to update coords for chaining approach

  if ( coords.x == -1 || coords.y == -1 ) { // Co-ordinates go from 0 to X-1 remember! width() and height() are out of range!
    return coords;
  }

  //right half screen column
  if ((coords.x & 16) != 0) {
    coords.x += 16;
  }

  //top half of the screen
  if (coords.y < 16) {
    if ((coords.y & 8) != 0) {
      coords.x += 16;
      coords.y -= 8;
    }
  } else { //bottom half of the screen
    coords.y -= 8;
    if ((coords.y & 16) != 0) {
      coords.x += 16;
      coords.y -= 8;
    }
  }

/*
Serial.print(coords.x);
Serial.print(", ");
Serial.println(coords.y);
*/

return coords;
}
/* ================================================== */

i have a 1/16 scan 64x64 panel coming soon which should have a similar chip, i'll keep you updated in case it needs custom coordinates calculations so that we can check/add support for that kind of outdoor panels if you want :)

board707 commented 1 month ago

we can add support for outdoor panels if you want :)

Thank you, but outdoor panels already supported by the library :)

The main issue that almost each panel model even with the same dimensions and scan has its own pixel mapping. The mapping that you found above for your 32x32 s8 panel may not be suitable for another 32x32 scan8 panel.

Your above code for handling coordinates can be simplified if you use the pixelbase trick as in my tests. According to your code, your panel's pixelbase is 16

FabioRoss commented 1 month ago

The main issue that almost each panel model even with the same dimensions and scan has its own pixel mapping. The mapping that you found above for your 32x32 s8 panel may not be suitable for another 32x32 scan8 panel.

i see, makes sense!

Your above code for handling coordinates can be simplified if you use the pixelbase trick as in my tests. According to your code, your panel's pixelbase is 16

thank you, sorry i couldn't understand much what was going on in those calculations and after a bunch of failed tries i started from scratch...i will try to use your code with pixelbase 16 :)

sorry for slight change of topic: what does

//mxconfig.driver = HUB75_I2S_CFG::FM6126A;     
//mxconfig.driver = HUB75_I2S_CFG::ICN2038S;
//mxconfig.driver = HUB75_I2S_CFG::FM6124;
//mxconfig.driver = HUB75_I2S_CFG::MBI5124;

act on?

in the beginning i thought i could solve the coordinates problem by changing the driver chip, i tried FM6126A and FM6124 but nothing changed and the LEDs were working great with both (aside from coordinates referencing), so that left me confused