mrcodetastic/ESP32-HUB75-MatrixPanel-DMA

Help with pixel mapping on 64x32 panel.

bug2k19 opened this issue · 18 comments

I have a 64x32 panel which seems to be addressed in blocks of 16x4 pixels and 2 panels of 64x16 one on top of the other.
By creating 16x4 rectangles I can see that the blocks of pixels are mapped as follows, actual output to the right.
64x32_mapping

Using this code produces the following output on the panel.
`#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>

#define R1_PIN 2
#define G1_PIN 12
#define B1_PIN 4
#define R2_PIN 16
#define G2_PIN 27
#define B2_PIN 17

#define A_PIN 5
#define B_PIN 25
#define C_PIN 18
//#define D_PIN 33
#define D_PIN -1
#define E_PIN -1

#define LAT_PIN 32
#define OE_PIN 21
#define CLK_PIN 19

#define PANEL_RES_X 64
#define PANEL_RES_Y 16
#define PANEL_CHAIN 2

MatrixPanel_I2S_DMA *dma_display = nullptr;

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};
delay(10);

HUB75_I2S_CFG mxconfig(
PANEL_RES_X,
PANEL_RES_Y,
PANEL_CHAIN,
_pins
);
delay(10);

dma_display = new MatrixPanel_I2S_DMA(mxconfig);
dma_display->begin();
dma_display->setBrightness8(16);

dma_display->clearScreen();

dma_display->drawRect(16,0, 16, 4, 254);
dma_display->drawRect(112,0, 16, 4, 254);
dma_display->drawRect(0,12, 16, 4, 254);
dma_display->drawRect(96,12, 16, 4, 254);
}

void loop()
{

}`
64x32_panel

How would I modify the output so that the output looks correct?

Hi
Your explanation is not clear
Please show a video with result of this code:

dma_display->clearScreen();
for (int y=0; y < dma_display->height(); y++) {
  for (int x=0; x < dma_display->width(); x++) {
    dma_display->drawPixel(x,y, dma_display->color565(0, 0, 255));
    delay(30);
  }
} 

Thanks for getting back, here's a clip running that code with the following panel settings.

#define PANEL_RES_X 64
#define PANEL_RES_Y 32
#define PANEL_CHAIN 1
panel_1.mp4

Here is the code run with the following panel settings.

#define PANEL_RES_X 64
#define PANEL_RES_Y 16
#define PANEL_CHAIN 2
panel_2.mp4

Thank you!
For second settings (i.e. PANEL_RES_Y 16) try this transform:

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 / 16)+1)*16; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
  }
  else {
    coords.x += (coords.x / 16)*16; // 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;
}

Thanks! I'm an imbecile, where do I add/modify that code?

Please show your full test code (.ino) for second video

Here is the code for that run.

#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>

#define R1_PIN 2
#define G1_PIN 12
#define B1_PIN 4
#define R2_PIN 16
#define G2_PIN 27
#define B2_PIN 17

#define A_PIN 5
#define B_PIN 25
#define C_PIN 18
//#define D_PIN 33
#define D_PIN -1
#define E_PIN -1

#define LAT_PIN 32
#define OE_PIN 21
#define CLK_PIN 19

#define PANEL_RES_X 64
#define PANEL_RES_Y 16
#define PANEL_CHAIN 2

MatrixPanel_I2S_DMA *dma_display = nullptr;

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};
  delay(10);

  HUB75_I2S_CFG mxconfig(
    PANEL_RES_X,
    PANEL_RES_Y,
    PANEL_CHAIN,
    _pins
  );
  delay(10);

  dma_display = new MatrixPanel_I2S_DMA(mxconfig);
  dma_display->begin();
 
  dma_display->setBrightness8(16);
  
  dma_display->clearScreen();

  for (int y=0; y < dma_display->height(); y++) {
    for (int x=0; x < dma_display->width(); x++) {
      dma_display->drawPixel(x,y, dma_display->color565(0, 0, 255));
      delay(30);
    }
  }

//  dma_display->drawRect(16,0, 16, 4, 254);
//  dma_display->drawRect(112,0, 16, 4, 254);
//  dma_display->drawRect(0,12, 16, 4, 254);
//  dma_display->drawRect(96,12, 16, 4, 254);

}

void loop()
{
    
}

Save this as .ino file and try to run


#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>

class OneEightScanPanel : public VirtualMatrixPanel
{
  public:
    using VirtualMatrixPanel::VirtualMatrixPanel; // inherit VirtualMatrixPanel's constructor(s)

  protected:
    /* Convert Real World 'VirtualMatrixPanel' co-ordinates (i.e. Real World pixel you're looking at
       on the panel or chain of panels, per the chaining configuration) to a 1/8 panels
       double 'stretched' and 'squished' coordinates which is what needs to be sent from the
       DMA buffer.
       Note: Look at the One_Eight_1_8_ScanPanel code and you'll see that the DMA buffer is setup
       as if the panel is 2 * W and 0.5 * H !
    */
    VirtualCoords getCoords(int16_t &x, int16_t &y);

};
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 / 16)+1)*16; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
  }
  else {
    coords.x += (coords.x / 16)*16; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer
  }

 
  coords.y = (y >> 4)*8 + (y & 0b00000111);   


  return coords;
}

#define R1_PIN 2
#define G1_PIN 12
#define B1_PIN 4
#define R2_PIN 16
#define G2_PIN 27
#define B2_PIN 17

#define A_PIN 5
#define B_PIN 25
#define C_PIN 18
//#define D_PIN 33
#define D_PIN -1
#define E_PIN -1

#define LAT_PIN 32
#define OE_PIN 21
#define CLK_PIN 19

#define PANEL_RES_X 64
#define PANEL_RES_Y 32
#define PANEL_CHAIN 1

MatrixPanel_I2S_DMA *dma_display = nullptr;

// placeholder for the virtual display object
  OneEightScanPanel  *OneEightMatrixDisplay = nullptr;

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};
  delay(10);

  HUB75_I2S_CFG mxconfig(
    PANEL_RES_X*2,
    PANEL_RES_Y/2,
    PANEL_CHAIN,
    _pins
  );
  delay(10);

  dma_display = new MatrixPanel_I2S_DMA(mxconfig);
  dma_display->begin();
 
  dma_display->setBrightness8(16);
  
  dma_display->clearScreen();
  OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);

  for (int y=0; y < PANEL_RES_Y; y++) {
    for (int x=0; x < PANEL_RES_X; x++) {
      OneEightMatrixDisplay->drawPixel(x,y, dma_display->color565(0, 0, 255));
      delay(30);
    }
  }


}

void loop()
{
    
}

I get an error on compiling, line4.

error: expected class-name before '{' token
 {
 ^

Please show the error message in full

fix_test:4:1: error: expected class-name before '{' token
 {
 ^
fix_test:6:11: error: 'VirtualMatrixPanel' has not been declared
     using VirtualMatrixPanel::VirtualMatrixPanel; // inherit VirtualMatrixPanel's constructor(s)
           ^~~~~~~~~~~~~~~~~~
fix_test:16:5: error: 'VirtualCoords' does not name a type
     VirtualCoords getCoords(int16_t &x, int16_t &y);
     ^~~~~~~~~~~~~
fix_test:19:8: error: 'VirtualCoords' does not name a type
 inline VirtualCoords OneEightScanPanel::getCoords(int16_t &x, int16_t &y) {
        ^~~~~~~~~~~~~
/mnt/code/esp32/test/fix_test/fix_test.ino: In function 'void setup()':
fix_test:87:65: error: 'NUM_ROWS' was not declared in this scope
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                 ^~~~~~~~
fix_test:87:75: error: 'NUM_COLS' was not declared in this scope
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                           ^~~~~~~~
fix_test:87:111: error: 'SERPENT' was not declared in this scope
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                                                               ^~~~~~~
/mnt/code/esp32/test/fix_test/fix_test.ino:87:111: note: suggested alternative: 'ENOENT'
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                                                               ^~~~~~~
                                                                                                               ENOENT
fix_test:87:120: error: 'TOPDOWN' was not declared in this scope
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                                                                        ^~~~~~~
/mnt/code/esp32/test/fix_test/fix_test.ino:87:120: note: suggested alternative: 'ENETDOWN'
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                                                                        ^~~~~~~
                                                                                                                        ENETDOWN
fix_test:87:127: error: new initializer expression list treated as compound expression [-fpermissive]
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                                                                               ^
fix_test:91:30: error: 'class OneEightScanPanel' has no member named 'drawPixel'
       OneEightMatrixDisplay->drawPixel(x,y, dma_display->color565(0, 0, 255));
                              ^~~~~~~~~
exit status 1
expected class-name before '{' token

include the header

#include <ESP32-VirtualMatrixPanel-I2S-DMA.h>

at the start of the code

I still get errors, apologies, I've had very little to do with c++ over the years.

#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
#include <ESP32-VirtualMatrixPanel-I2S-DMA.h>

class OneEightScanPanel : public VirtualMatrixPanel
{
  public:
    using VirtualMatrixPanel::VirtualMatrixPanel; // inherit VirtualMatrixPanel's constructor(s)

  protected:
    /* Convert Real World 'VirtualMatrixPanel' co-ordinates (i.e. Real World pixel you're looking at
       on the panel or chain of panels, per the chaining configuration) to a 1/8 panels
       double 'stretched' and 'squished' coordinates which is what needs to be sent from the
       DMA buffer.
       Note: Look at the One_Eight_1_8_ScanPanel code and you'll see that the DMA buffer is setup
       as if the panel is 2 * W and 0.5 * H !
    */
    VirtualCoords getCoords(int16_t &x, int16_t &y);

};
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 / 16)+1)*16; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
  }
  else {
    coords.x += (coords.x / 16)*16; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer
  }

 
  coords.y = (y >> 4)*8 + (y & 0b00000111);   


  return coords;
}

#define R1_PIN 2
#define G1_PIN 12
#define B1_PIN 4
#define R2_PIN 16
#define G2_PIN 27
#define B2_PIN 17

#define A_PIN 5
#define B_PIN 25
#define C_PIN 18
//#define D_PIN 33
#define D_PIN -1
#define E_PIN -1

#define LAT_PIN 32
#define OE_PIN 21
#define CLK_PIN 19

#define PANEL_RES_X 64
#define PANEL_RES_Y 32
#define PANEL_CHAIN 1

MatrixPanel_I2S_DMA *dma_display = nullptr;

// placeholder for the virtual display object
  OneEightScanPanel  *OneEightMatrixDisplay = nullptr;

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};
  delay(10);

  HUB75_I2S_CFG mxconfig(
    PANEL_RES_X*2,
    PANEL_RES_Y/2,
    PANEL_CHAIN,
    _pins
  );
  delay(10);

  dma_display = new MatrixPanel_I2S_DMA(mxconfig);
  dma_display->begin();
 
  dma_display->setBrightness8(16);
  
  dma_display->clearScreen();
  OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);

  for (int y=0; y < PANEL_RES_Y; y++) {
    for (int x=0; x < PANEL_RES_X; x++) {
      OneEightMatrixDisplay->drawPixel(x,y, dma_display->color565(0, 0, 255));
      delay(30);
    }
  }


}

void loop()
{
    
}
/mnt/code/esp32/test/fix_test/fix_test.ino: In member function 'VirtualCoords OneEightScanPanel::getCoords(int16_t&, int16_t&)':
fix_test:21:37: error: 'virtual VirtualCoords VirtualMatrixPanel::getCoords(int16_t, int16_t)' is private within this context
   VirtualMatrixPanel::getCoords(x, y); // call to base to update coords for chaining approach
                                     ^
In file included from /mnt/code/esp32/test/fix_test/fix_test.ino:2:
/mnt/code/Arduino/libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/src/ESP32-VirtualMatrixPanel-I2S-DMA.h:174:22: note: declared private here
 inline VirtualCoords VirtualMatrixPanel::getCoords(int16_t virt_x, int16_t virt_y)
                      ^~~~~~~~~~~~~~~~~~
fix_test:23:8: error: 'VirtualCoords VirtualMatrixPanel::coords' is private within this context
   if ( coords.x == -1 || coords.y == -1 ) { // Co-ordinates go from 0 to X-1 remember! width() and height() are out of range!
        ^~~~~~
In file included from /mnt/code/esp32/test/fix_test/fix_test.ino:2:
/mnt/code/Arduino/libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/src/ESP32-VirtualMatrixPanel-I2S-DMA.h:147:19: note: declared private here
     VirtualCoords coords;
                   ^~~~~~
fix_test:23:26: error: 'VirtualCoords VirtualMatrixPanel::coords' is private within this context
   if ( coords.x == -1 || coords.y == -1 ) { // Co-ordinates go from 0 to X-1 remember! width() and height() are out of range!
                          ^~~~~~
In file included from /mnt/code/esp32/test/fix_test/fix_test.ino:2:
/mnt/code/Arduino/libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/src/ESP32-VirtualMatrixPanel-I2S-DMA.h:147:19: note: declared private here
     VirtualCoords coords;
                   ^~~~~~
fix_test:24:12: error: 'VirtualCoords VirtualMatrixPanel::coords' is private within this context
     return coords;
            ^~~~~~
In file included from /mnt/code/esp32/test/fix_test/fix_test.ino:2:
/mnt/code/Arduino/libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/src/ESP32-VirtualMatrixPanel-I2S-DMA.h:147:19: note: declared private here
     VirtualCoords coords;
                   ^~~~~~
fix_test:29:5: error: 'VirtualCoords VirtualMatrixPanel::coords' is private within this context
     coords.x += ((coords.x / 16)+1)*16; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
     ^~~~~~
In file included from /mnt/code/esp32/test/fix_test/fix_test.ino:2:
/mnt/code/Arduino/libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/src/ESP32-VirtualMatrixPanel-I2S-DMA.h:147:19: note: declared private here
     VirtualCoords coords;
                   ^~~~~~
fix_test:29:19: error: 'VirtualCoords VirtualMatrixPanel::coords' is private within this context
     coords.x += ((coords.x / 16)+1)*16; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
                   ^~~~~~
In file included from /mnt/code/esp32/test/fix_test/fix_test.ino:2:
/mnt/code/Arduino/libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/src/ESP32-VirtualMatrixPanel-I2S-DMA.h:147:19: note: declared private here
     VirtualCoords coords;
                   ^~~~~~
fix_test:32:5: error: 'VirtualCoords VirtualMatrixPanel::coords' is private within this context
     coords.x += (coords.x / 16)*16; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer
     ^~~~~~
In file included from /mnt/code/esp32/test/fix_test/fix_test.ino:2:
/mnt/code/Arduino/libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/src/ESP32-VirtualMatrixPanel-I2S-DMA.h:147:19: note: declared private here
     VirtualCoords coords;
                   ^~~~~~
fix_test:32:18: error: 'VirtualCoords VirtualMatrixPanel::coords' is private within this context
     coords.x += (coords.x / 16)*16; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer
                  ^~~~~~
In file included from /mnt/code/esp32/test/fix_test/fix_test.ino:2:
/mnt/code/Arduino/libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/src/ESP32-VirtualMatrixPanel-I2S-DMA.h:147:19: note: declared private here
     VirtualCoords coords;
                   ^~~~~~
fix_test:36:3: error: 'VirtualCoords VirtualMatrixPanel::coords' is private within this context
   coords.y = (y >> 4)*8 + (y & 0b00000111);
   ^~~~~~
In file included from /mnt/code/esp32/test/fix_test/fix_test.ino:2:
/mnt/code/Arduino/libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/src/ESP32-VirtualMatrixPanel-I2S-DMA.h:147:19: note: declared private here
     VirtualCoords coords;
                   ^~~~~~
fix_test:39:10: error: 'VirtualCoords VirtualMatrixPanel::coords' is private within this context
   return coords;
          ^~~~~~
In file included from /mnt/code/esp32/test/fix_test/fix_test.ino:2:
/mnt/code/Arduino/libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/src/ESP32-VirtualMatrixPanel-I2S-DMA.h:147:19: note: declared private here
     VirtualCoords coords;
                   ^~~~~~
/mnt/code/esp32/test/fix_test/fix_test.ino: In function 'void setup()':
fix_test:88:65: error: 'NUM_ROWS' was not declared in this scope
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                 ^~~~~~~~
fix_test:88:75: error: 'NUM_COLS' was not declared in this scope
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                           ^~~~~~~~
fix_test:88:111: error: 'SERPENT' was not declared in this scope
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                                                               ^~~~~~~
/mnt/code/esp32/test/fix_test/fix_test.ino:88:111: note: suggested alternative: 'ENOENT'
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                                                               ^~~~~~~
                                                                                                               ENOENT
fix_test:88:120: error: 'TOPDOWN' was not declared in this scope
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                                                                        ^~~~~~~
/mnt/code/esp32/test/fix_test/fix_test.ino:88:120: note: suggested alternative: 'ENETDOWN'
   OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
                                                                                                                        ^~~~~~~
                                                                                                                        ENETDOWN
exit status 1
'virtual VirtualCoords VirtualMatrixPanel::getCoords(int16_t, int16_t)' is private within this context

Sorry, it seems my solution required too many changes...
I'm sorry, in another discussion I gave this solution to a person and it worked.

Is there a location I can find the workaround?

getCoords(int16_t, int16_t)' is private within this context

@bug2k19 - if you understand, try to make method getCoords() public in VirtualMatrixPanel class

I got it working by changing some of the code in the ESP32-VirtualMatrixPanel-I2S-DMA.h header file, it's not an elegant solution, but works for the panel I have.

inline VirtualCoords VirtualMatrixPanel::getCoords(int16_t virt_x, int16_t virt_y)
{
	
#if !defined NO_GFX
	// I don't give any support if Adafruit GFX isn't being used.
	
    if (virt_x < 0 || virt_x >= _width || virt_y < 0 || virt_y >= _height) // _width and _height are defined in the adafruit constructor
    {                             // Co-ordinates go from 0 to X-1 remember! otherwise they are out of range!
        coords.x = coords.y = -1; // By defalt use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer
        return coords;
    }
#else
	
    if (virt_x < 0 || virt_x >= _virtualResX || virt_y < 0 || virt_y >= _virtualResY) // _width and _height are defined in the adafruit constructor
    {                             // Co-ordinates go from 0 to X-1 remember! otherwise they are out of range!
        coords.x = coords.y = -1; // By defalt use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer
        return coords;
    }
	
#endif

    if(virt_x<16)
      virt_x=virt_x+16;
    else
      if(virt_x<32)
        virt_x=virt_x+32;
      else
        if(virt_x<48)
          virt_x=virt_x+48;
        else
          if(virt_x<64)
            virt_x=virt_x+64;
    if(virt_y<8)
      virt_y=virt_y;
    else
      if(virt_y<16)
        {
        virt_y=virt_y-8;
        virt_x=virt_x-16;
        }
      else
        if(virt_y<24)
          virt_y=virt_y-8;
        else
          if(virt_y<32)
            {
            virt_y=virt_y-16;
            virt_x=virt_x-16;
            }
    
    coords.x = virt_x; 
    coords.y = virt_y;
    
    return coords;
}

64x32_panel_b

Great!

But take the note, that your solution will works only with a single panel.

Could you please replace your function with code below and test?

inline VirtualCoords VirtualMatrixPanel::getCoords(int16_t virt_x, int16_t virt_y)
{
	
#if !defined NO_GFX
	// I don't give any support if Adafruit GFX isn't being used.
	
    if (virt_x < 0 || virt_x >= _width || virt_y < 0 || virt_y >= _height) // _width and _height are defined in the adafruit constructor
    {                             // Co-ordinates go from 0 to X-1 remember! otherwise they are out of range!
        coords.x = coords.y = -1; // By defalt use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer
        return coords;
    }
#else
	
    if (virt_x < 0 || virt_x >= _virtualResX || virt_y < 0 || virt_y >= _virtualResY) // _width and _height are defined in the adafruit constructor
    {                             // Co-ordinates go from 0 to X-1 remember! otherwise they are out of range!
        coords.x = coords.y = -1; // By defalt use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer
        return coords;
    }
	
#endif

coords.x = virt_x; coords.y = virt_y; 

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

 
  coords.y = ( virt_y >> 4)*8 + ( virt_y & 0b00000111);   


  return coords;
}

Thanks, I realise it was a hack just to get this panel working. Your new code also works correctly with this panel.