mrcodetastic/ESP32-HUB75-MatrixPanel-DMA

96x64px matrix (6x 32x32 1/8 scan panels) not displaying the bottom row

mozzhead164 opened this issue ยท 9 comments

Hello @mrfaptastic...first of all a thankyou for putting this library together over many MANY hours work! ๐Ÿ‘

I am having issue with displaying on a set of 6No. 32x32 1/8 scan (so the label says) panels.
Outdoor P6 panel with code P6-3535(27)-8S-HL1.0
Driver Chip - ICN2037BP
Latch Chip - SM5166PC

Trying to use an Adafruit MatrixPortal S3 to drive these panels (So also using custom pin configuration)
Panels are wired according to the below diagram...

Picture1

The library works absolutely fine with 1/2/3 panels all in the same row. Text and Shapes are displayed OK.

Problem arises when I chain another 3 panels underneath to produce a 2 row 96x64px panel.
Again the first three panels still behave, but nothing is displayed on the bottom row of panels.
I have tried many different combinations of the setup variables, and cannot get it to work properly.

I have 'glued' together two of your examples, "Four_Scan_Panel" and "ChainedPanels" - (Code Pasted Below)

Could it be something to do with 'FOUR_SCAN_32PX_HIGH' needing to be 'FOUR_SCAN_64PX_HIGH' instead?
I've tried that and it seems to product garbage results. Code Below.

I have also had to include....

mxconfig.driver   = HUB75_I2S_CFG::ICN2038S;

...To get the panels to work with the IC that they use.

As a test, I have also tried removing the print text functions in loop() and just writing a fillScreen(RED), and interestingly all 6 of the panels light up red. But I cannot get the bottom half (row 2 - panels 4,5,6) of the display to display any text.

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


  #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

  // Panel configuration
  #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 NUM_ROWS 2 // Number of rows of chained INDIVIDUAL PANELS
  #define NUM_COLS 3 // Number of INDIVIDUAL PANELS per ROW
  
  // ^^^ NOTE: DEFAULT EXAMPLE SETUP IS FOR A CHAIN OF TWO x 1/8 SCAN PANELS
    
  // Change this to your needs, for details on VirtualPanel pls read the PDF!
  #define SERPENT true
  #define TOPDOWN true

  #define VIRTUAL_MATRIX_CHAIN_TYPE CHAIN_TOP_RIGHT_DOWN
  // placeholder for the matrix object
  MatrixPanel_I2S_DMA *dma_display = nullptr;

  // placeholder for the virtual display object
  VirtualMatrixPanel  *FourScanPanel = nullptr;
  
  /******************************************************************************
   * Setup!
   ******************************************************************************/
  void setup()
  {
    delay(250);
   
    Serial.begin(115200);
    Serial.println(""); Serial.println(""); Serial.println("");
    Serial.println("*****************************************************");
    Serial.println("*         1/8 Scan Panel Demonstration              *");
    Serial.println("*****************************************************");
  

     // 62x32 1/8 Scan Panels don't have a D and E pin!
     
     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(
                PANEL_RES_X*2,              // DO NOT CHANGE THIS
                PANEL_RES_Y/2,              // DO NOT CHANGE THIS
                NUM_ROWS*NUM_COLS           // DO NOT CHANGE THIS
                ,_pins            // Uncomment to enable custom pins
    );
    
    mxconfig.clkphase = false; // Change this if you see pixels showing up shifted wrongly by one column the left or right.
    
    mxconfig.driver   = HUB75_I2S_CFG::ICN2038S;     // in case that we use panels based on FM6126A chip, we can set it here before creating MatrixPanel_I2S_DMA object
  
    // OK, now we can create our matrix object
    dma_display = new MatrixPanel_I2S_DMA(mxconfig);
  
    // let's adjust default brightness to about 75%
    dma_display->setBrightness8(96);    // range is 0-255, 0 - 0%, 255 - 100%
  
    // Allocate memory and start DMA display
    if( not dma_display->begin() )
      Serial.println("****** !KABOOM! I2S memory allocation failed ***********");

   
    dma_display->clearScreen();
    delay(500);
    
    // create FourScanPanellay object based on our newly created dma_display object
    FourScanPanel = new VirtualMatrixPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, VIRTUAL_MATRIX_CHAIN_TYPE);
    
	  // THE IMPORTANT BIT BELOW!
    FourScanPanel->setPhysicalPanelScanRate(FOUR_SCAN_32PX_HIGH);
  }

  
  void loop() {

      // Print on each chained panel 1/8 module!
      // This only really works for a single horizontal chain
      for (int i = 0; i < NUM_ROWS*NUM_COLS; i++)
      {
        FourScanPanel->setTextColor(FourScanPanel->color565(255, 255, 255));
        FourScanPanel->setCursor(i*PANEL_RES_X + 7, FourScanPanel->height()/3); 
      
        // Red text inside red rect (2 pix in from edge)
        FourScanPanel->print(String(i+1));
        FourScanPanel->drawRect(1,1, FourScanPanel->width()-2, FourScanPanel->height()-2, FourScanPanel->color565(255,0,0));
      
        // White line from top left to bottom right
        FourScanPanel->drawLine(0,0, FourScanPanel->width()-1, FourScanPanel->height()-1, FourScanPanel->color565(255,255,255));
      }

      delay(2000);
      dma_display->clearScreen();
  }

The code above produces the below output

Picture5

Then, when I change the config to have;

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

The output then looks like this

Picture6

Why are you not flipping the bottom row 6,5,4) upside down so that row is (4,5 6) (with all panels flipped around)?

Then you can use a much shorter cable.

That's that serpentine is:

#define SERPENT true

Read the chained panels documentation pdf for the graphical examples.

@mrfaptastic I have done as you asked and flipped the bottom row of tiles so they are all now upside down.
I am still getting the same output as the first image of my matrix, nothing displayed at all on the bottom row.

But interestingly, you can see a patch of white pixels on the bottom left of Panel 1 - as if its printing all of the bottom panel contents onto these few pixels, would you say that is correct from what you can see?

The SERPENT and TOPDOWN variables are both set HIGH

  #define SERPENT true
  #define TOPDOWN true

Can you see anything else in my code above that would prevent the bottom row from displaying?

There must be some bug in the virtual matrix class pixel remapping logic with 1/4 scan panels.

Actually, these defines aren't used anymore:

#define SERPENT true 
#define TOPDOWN true

What example did you copy from that still had these? I thought I removed all references to this.

Can you please read the chain panels pdf?

Those two defines were from the 'Four_Scan_Panel' example, which I copied the entire source into PlatformIO before adding in the relevant parts from the 'ChainedPanels' example.

I have read the PDF a few times and have therefore added the below statement, which can be seen in the code in my first message.

#define VIRTUAL_MATRIX_CHAIN_TYPE CHAIN_TOP_RIGHT_DOWN

Also from the PDF, these two below examples seem to contradict each other.

Screenshot 2024-01-30 151652

Screenshot 2024-01-30 151658

Where Example 1) shows the ESP connected at the top right, with Panel 1 also at the top right (Using Top-Right-Down)
Then the second image shows Top-Right-Down configuration, but the Top right panel is #9 in that example...is that right?

Anyway, is there any way I can isolate the problem that you are suggesting?
The board I am using is the Adafruit MatrixPortal S3 - which is a pain in the a*se to program, I am still unable to get any debug output from the serial monitor, it just stays blank. That's another issue - but its slowing my progress.
...is there an easy way to slow down pushing out panel updates so that the scan is viewable by eye?

Also waiting for the supplier to send me a datasheet for the panels. So should have more details in the coming days.

I'll take a look. It's most certainly some bug with the VirtualMatrix class. 1/4 Scan support has always been a bit of hack, but given when you only have one row of output, all six panel display something, the class VirtualMatrix must be re-mapping the pixels intended for the bottom row into non-existent co-ordinates, and thus, they remain black.

Yes, absolutely makes sense to me. Let me know if I can do anything to assist in any way!
Drop us your Paypal if you want and I will drop you some coin ๐Ÿ‘

I have come back to this project after some months away, I still can't find a solution to this problem.

The library code seems to be printing to pixels that are out of the coordinate bounds of the screen.

I have written a simple test loop which just iterates drawPixel() over the x axis and then the y.

The panel lights up the top row of panels, but the second row stays dark.
I have printed the coordinates out to Serial monitor at different stages of the getCoords() function:
I have only printed rows 0 and 32 to be more concise.

 0) req.xy ( 0,  0) . chain.xy ( 64,  0) ... Physical.xy: (160,  0) 
 0) req.xy ( 1,  0) . chain.xy ( 65,  0) ... Physical.xy: (161,  0) 
 0) req.xy ( 0,  0) . chain.xy ( 64,  0) ... Physical.xy: (160,  0) 
 0) req.xy ( 2,  0) . chain.xy ( 66,  0) ... Physical.xy: (162,  0) 
 0) req.xy ( 1,  0) . chain.xy ( 65,  0) ... Physical.xy: (161,  0) 
 0) req.xy ( 3,  0) . chain.xy ( 67,  0) ... Physical.xy: (163,  0) 
 0) req.xy ( 2,  0) . chain.xy ( 66,  0) ... Physical.xy: (162,  0) 
 0) req.xy ( 4,  0) . chain.xy ( 68,  0) ... Physical.xy: (164,  0) 
 0) req.xy ( 3,  0) . chain.xy ( 67,  0) ... Physical.xy: (163,  0) 
 0) req.xy ( 5,  0) . chain.xy ( 69,  0) ... Physical.xy: (165,  0) 
 0) req.xy ( 4,  0) . chain.xy ( 68,  0) ... Physical.xy: (164,  0) 
 0) req.xy ( 5,  0) . chain.xy ( 69,  0) ... Physical.xy: (165,  0) 
 0) req.xy (58,  0) . chain.xy (122,  0) ... Physical.xy: (250,  0) 
 0) req.xy (59,  0) . chain.xy (123,  0) ... Physical.xy: (251,  0) 
 0) req.xy (58,  0) . chain.xy (122,  0) ... Physical.xy: (250,  0) 
 0) req.xy (60,  0) . chain.xy (124,  0) ... Physical.xy: (252,  0) 
 0) req.xy (59,  0) . chain.xy (123,  0) ... Physical.xy: (251,  0) 
 0) req.xy (61,  0) . chain.xy (125,  0) ... Physical.xy: (253,  0) 
 0) req.xy (60,  0) . chain.xy (124,  0) ... Physical.xy: (252,  0) 
 0) req.xy (62,  0) . chain.xy (126,  0) ... Physical.xy: (254,  0) 
 0) req.xy (61,  0) . chain.xy (125,  0) ... Physical.xy: (253,  0) 
 0) req.xy (63,  0) . chain.xy (127,  0) ... Physical.xy: (255,  0) 
 0) req.xy (62,  0) . chain.xy (126,  0) ... Physical.xy: (254,  0) 
 0) req.xy (63,  0) . chain.xy (127,  0) ... Physical.xy: (255,  0) 
 1) req.xy ( 0, 32) . chain.xy ( 63, 31) ... Physical.xy: (127, 16) 
 1) req.xy ( 1, 32) . chain.xy ( 62, 31) ... Physical.xy: (126, 16) 
 1) req.xy ( 0, 32) . chain.xy ( 63, 31) ... Physical.xy: (127, 16) 
 1) req.xy ( 2, 32) . chain.xy ( 61, 31) ... Physical.xy: (125, 16) 
 1) req.xy ( 1, 32) . chain.xy ( 62, 31) ... Physical.xy: (126, 16) 
 1) req.xy ( 3, 32) . chain.xy ( 60, 31) ... Physical.xy: (124, 16) 
 1) req.xy ( 2, 32) . chain.xy ( 61, 31) ... Physical.xy: (125, 16) 
 1) req.xy ( 4, 32) . chain.xy ( 59, 31) ... Physical.xy: (123, 16) 
 1) req.xy ( 3, 32) . chain.xy ( 60, 31) ... Physical.xy: (124, 16) 
 1) req.xy ( 5, 32) . chain.xy ( 58, 31) ... Physical.xy: (122, 16) 
 1) req.xy ( 4, 32) . chain.xy ( 59, 31) ... Physical.xy: (123, 16) 
 1) req.xy ( 5, 32) . chain.xy ( 58, 31) ... Physical.xy: (122, 16) 
 1) req.xy (58, 32) . chain.xy (  5, 31) ... Physical.xy: ( 37, 16) 
 1) req.xy (59, 32) . chain.xy (  4, 31) ... Physical.xy: ( 36, 16) 
 1) req.xy (58, 32) . chain.xy (  5, 31) ... Physical.xy: ( 37, 16) 
 1) req.xy (60, 32) . chain.xy (  3, 31) ... Physical.xy: ( 35, 16) 
 1) req.xy (59, 32) . chain.xy (  4, 31) ... Physical.xy: ( 36, 16) 
 1) req.xy (61, 32) . chain.xy (  2, 31) ... Physical.xy: ( 34, 16) 
 1) req.xy (60, 32) . chain.xy (  3, 31) ... Physical.xy: ( 35, 16) 
 1) req.xy (62, 32) . chain.xy (  1, 31) ... Physical.xy: ( 33, 16) 
 1) req.xy (61, 32) . chain.xy (  2, 31) ... Physical.xy: ( 34, 16) 
 1) req.xy (63, 32) . chain.xy (  0, 31) ... Physical.xy: ( 32, 16) 
 1) req.xy (62, 32) . chain.xy (  1, 31) ... Physical.xy: ( 33, 16) 
 1) req.xy (63, 32) . chain.xy (  0, 31) ... Physical.xy: ( 32, 16) 

The req.xy is the x,y coords passed to drawPixel()
The chain.xy is virt_x and virt_y
The Physical.xy is coords.x and coords.y

Can you spot any weird behaviour in this output?
..and would that lead to any other test code that I could upload to the board to test why this is happening?

It seems that once the 2nd row of panels is reached, the Y coordinates are wrapping back around to 31->0 instead of going between 32->63

The library code seems to be printing to pixels that are out of the coordinate bounds of the screen.

Yes, it seems the bug in VirtualMatrixPanel::getCoords() function line 405.

In the code for FOUR_SCAN_32PX_HIGH panels the line:

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

accidentally used virt_y instead of coords.y.

As a result, if your configuration uses a multiple rows of panels, the coords.y becomes greater than the real height of the panel.
The solution is to change the line of 405 as:

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

@mozzhead164
Could you please check this assumption?