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
881 stars 195 forks source link

P8 40x20 1/5S #637

Open mjmokhtar opened 4 weeks ago

mjmokhtar commented 4 weeks ago

I have a panel led p8 40x20 with scan 1/5 Gambar WhatsApp 2024-06-04 pukul 12 00 24_0cd6bb91 Gambar WhatsApp 2024-06-04 pukul 12 00 15_3c156d00

i've using 1/4 scan for tried here this code from example

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

// Panel configuration
#define PANEL_RES_X 40 // Number of pixels wide of each INDIVIDUAL panel module.
#define PANEL_RES_Y 20 // Number of pixels tall of each INDIVIDUAL panel module.

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

#define SERPENT true
#define TOPDOWN false

// placeholder for the matrix object
MatrixPanel_I2S_DMA *dma_display = nullptr;

// placeholder for the virtual display object
VirtualMatrixPanel *FourScanPanel = nullptr;

void setup() {
delay(250);

Serial.begin(115200);
Serial.println(""); Serial.println(""); Serial.println("");
Serial.println("*****************************************************");
Serial.println("*         1/8 Scan Panel Demonstration              *");
Serial.println("*****************************************************");

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
);

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::FM6126A; // in case that we use panels based on FM6126A chip, we can set it here before creating MatrixPanel_I2S_DMA object

// Create our matrix object
dma_display = new MatrixPanel_I2S_DMA(mxconfig);

// 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 (!dma_display->begin())
    Serial.println("****** !KABOOM! I2S memory allocation failed ***********");

dma_display->clearScreen();
delay(500);

// Create FourScanPanel object based on our newly created dma_display object
FourScanPanel = new VirtualMatrixPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y);

// THE IMPORTANT BIT BELOW!
FourScanPanel->setPhysicalPanelScanRate(FOUR_SCAN_16PX_HIGH);

}

void loop() {

 for (int i = 0; i < FourScanPanel->height(); i++)
  {
    for (int j = 0; j < FourScanPanel->width(); j++)
    {
      FourScanPanel->drawPixel(j, i, FourScanPanel->color565(255, 0, 0));
      delay(30);
    }
  }

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

} // end loop

and here is result

https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/assets/108962994/39fedaa6-8371-4268-add3-1f0a8ad40afa

this coordinate is still random may I need your help to fix it

thanks

board707 commented 4 weeks ago

Please use our old code from this post, changing the matrix width and height to 40 x 20. Replace the getCoords() function with code below and show the video:

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;
  }

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

       coords.y = (coords.y / 10) * 5 + (coords.y % 5);
  return coords;
}
mjmokhtar commented 4 weeks ago

https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/assets/108962994/ae6c43fc-6132-4231-88d8-e67811c1aa3b

here is result and here a code

/* Use a custom Virtual Display class to re-map co-ordinates such that they draw
   correctly on a 32x16 1/4 Scan panel (or chain of such panels).
*/
#include "ESP32-VirtualMatrixPanel-I2S-DMA.h"

/* ================================================== */
// 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

};

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;
  }

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

       coords.y = (coords.y / 10) * 5 + (coords.y % 5);
  return coords;
}

/* ================================================== */
// Panel configuration
#define PANEL_RES_X 40 // Number of pixels wide of each INDIVIDUAL panel module. 
#define PANEL_RES_Y 20 // Number of pixels tall of each INDIVIDUAL panel module.

#define NUM_ROWS 1 // Number of rows of chained INDIVIDUAL PANELS
#define NUM_COLS 1 // 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 false
#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
EightPxBasePanel   *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::FM6126A;     // 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(40);    // 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 EightPxBasePanel ((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y,    VIRTUAL_MATRIX_CHAIN_TYPE);

  // THE IMPORTANT BIT BELOW!
  // FOUR_SCAN_16PX_HIGH
  // FOUR_SCAN_32PX_HIGH
// **** You don't need to set PhysicalPanelScanRate when use your own virtual panel class
  //FourScanPanel->setPhysicalPanelScanRate(FOUR_SCAN_16PX_HIGH);
}

// Test the pixel mapping - fill the panel pixel by pixel
void loop() {

  for (int i = 0; i < FourScanPanel->height(); i++)
  {
    for (int j = 0; j < FourScanPanel->width(); j++)
    {

      FourScanPanel->drawPixel(j, i, FourScanPanel->color565(255, 0, 0));
      delay(30);
    }
  }

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

} // end loop
board707 commented 4 weeks ago

Thanks Now change the getCoords() this way:

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;
  }

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

       coords.y = (coords.y / 10) * 5 + (coords.y % 5);
  return coords;
}
mjmokhtar commented 4 weeks ago

https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/assets/108962994/e8e0dc52-afad-4ed3-b378-78407aa72f0d

here is result

board707 commented 4 weeks ago

It looks the same pattern as in your 32x16 s4 panel Try this:

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;
  }

const uint8_t pixBase =8;
if (((coords.y / 5)%2) == 0)
          {
            coords.x = (coords.x / pxbase)*2*pxbase   + 7 - (coords.x & 0x7);
        }
        else
        {
           coords.x += ((coords.x / pxbase) + 1) * pxbase; 
        }

       coords.y = (coords.y / 10) * 5 + (coords.y % 5);
  return coords;
}
mjmokhtar commented 4 weeks ago

https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/assets/108962994/dd81938a-1a99-4042-963a-d137f9f68d9b

finally thank you so much

can you teach me how to know how to manipulate the coordinates of led?

board707 commented 4 weeks ago

can you teach me how to know how to manipulate the coordinates of led?

After setting the virtual panel class, you can use a natural panel coordinates. You have using it already in your loop:

for (int i = 0; i < FourScanPanel->height(); i++)
  {
    for (int j = 0; j < FourScanPanel->width(); j++)
    {
      FourScanPanel->drawPixel(j, i, FourScanPanel->color565(255, 0, 0));
      delay(30);
    }
  }
mjmokhtar commented 4 weeks ago

yes i mean when the first time, the coordinate of led panel was not in position, how should we know to write this code

const uint8_t pixBase =8;
if (((coords.y / 5)%2) == 0)
          {
            coords.x = (coords.x / pxbase)*2*pxbase   + 7 - (coords.x & 0x7);
        }
        else
        {
           coords.x += ((coords.x / pxbase) + 1) * pxbase; 
        }

       coords.y = (coords.y / 10) * 5 + (coords.y % 5);
  return coords;
board707 commented 4 weeks ago

See the discussion #622, this is a brief guide where I explained how and what I do when I add a new panel. I have my own library (not for ESP32), when writing it I tested dozens of panels of different sizes and coordinate transformations. With my library, I can run panels with almost any size, scan factor and coordinate pattern.