Skip to main content
Topic: Controller Board for Adafruit's Large RGB Matrix Displays (Read 171348 times) previous topic - next topic

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #15
That's really awesome. The adafruit matrix library has just 12bit and even the FPGA approaches don't achieve 24bit. Great that a Teensy can beat that :)

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #16
Yeah, I've been really impressed by the Teensy 3, and the Freescale Kinetis family of CPUs after starting this project.  I'm going to keep using them in future projects for sure.

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #17
Hi Louis,

Great project! I'm very interested in following the progress on this one :)

I bought a 32x32 matrix and a 32x16 matrix that I took delivery of last week. I planned to use two Sparkfun ("Arduino") Pro Micro boards but found out the hard way that they are not suitable with the Adafruit library. I then switched to a Arduino Nano I had laying around but experienced strange problems with that one too (I later found out that I was maxing out on memory). I ended up using a Mega but can visually see the redrawing on the unbuffered plasma demo and it is definately not a speed demon...

I plan to use the 32x32 in a picture frame and display pixel art (and pixel art animations) but I'm slowly admitting to myself that using an Arduino might be to optimistic (at least with my lack of low level coding experience).

As an alternative I started looking into using the Teensy 3.1 I received a couple of weeks ago. And I'm really exited to read up on your project :)

I understand from the thread that you are planning to sell this as a kit. Are you able to estimate a sales price and would it be made available for shipping to Europe?

- Are you planning on publishing the PCB in the shared projects area on OSHPARK? I think that would be great.
- Will the library support chaining together several matrixes?
- Do you plan to add functions for loading color bitmaps and animations (e.g. GIFs) in your library?
- I think it would be great to add a micro SD card reader on the PCB.
- Would it make sense to make a 12Vin version of the board? The reason I ask is that it's much easier to purchase cheap 12V 2A power adapters than 5V 4A power adapters.

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #18
Quote
I'm very interested in following the progress on this one :)
Thanks for following!

Quote
I plan to use the 32x32 in a picture frame and display pixel art (and pixel art animations)
Sounds like a cool project.  I'm interested to see how pixel art looks at 24-bit color on the display.  Have you seen this on Kickstarter?  You could get some inspiration from that project:
https://www.kickstarter.com/projects/99 ... el-led-art

Quote
Are you able to estimate a sales price and would it be made available for shipping to Europe?
I don't have all the costs added up for packaging and shipping, so I can't set a price yet.  I'll be shipping worldwide.

Quote
Are you planning on publishing the PCB in the shared projects area on OSHPARK? I think that would be great.
Yes, I'll share the board on OSH Park after I'm ready to ship kits to customers.

Quote
Will the library support chaining together several matrixes?
There's just barely enough time to shift 32 pixels worth of data out to the display when outputting the smallest (1/256th) time division of 24-bit color.  Chaining multiple displays from the same controller board would require reducing the color depth at a minimum.  Driving multiple displays at 12-bit or 18-bit color is a possibility, but I haven't looked into it.

I'd like to add the ability for multiple displays to talk to each other over I2C (which is why I added the I2C pull-up resistors on the board), so they can sync what they're drawing to expand the display beyond just one matrix.  I'll look into this idea more for future revisions of the library.

Quote
Do you plan to add functions for loading color bitmaps and animations (e.g. GIFs) in your library?
When the library ships, it will support mono bitmaps (same as the Adafruit library).  I'll add support for full color bitmaps in a future release, but need to figure out the best way to store them and add them to a sketch.  Animations would follow after full color bitmaps. 

GIFs use LZW compression, which requires around 8-16kB RAM to decompress.  There's enough free RAM on the Teensy 3.1 to potentially do the decompression, but it might be significant work to port a LZW library to the Teensy 3.1.

Quote
I think it would be great to add a micro SD card reader on the PCB

There's an SPI port available on the board, and the Teensy 3.x has an SD card library, so adding a SD card is a good idea.  That's a good place to store bitmaps or animations.  The board features are locked down so it won't be a part of this kit, but there's probably an easy way to wire up an adapter.  I'd love to discuss this and the GIF/animation support more.

Quote
Would it make sense to make a 12Vin version of the board? The reason I ask is that it's much easier to purchase cheap 12V 2A power adapters than 5V 4A power adapters.
I wanted to keep this board as simple to assemble, and as low cost as possible, so adding a regulator that supports 4A wasn't a good fit.  Adafruit has a 5V 4A adapter for $15, which seems like a reasonable price to me.
http://www.adafruit.com/products/1466

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #19
Thanks for the quick reply!

Quote
Sounds like a cool project.  I'm interested to see how pixel art looks at 24-bit color on the display.  Have you seen this on Kickstarter?  You could get some inspiration from that project:
I looked into his V1 last year and V2 a couple of days ago. I love what he's been able to come up with but the pricing is sadly out of the range I'm comfortable spending on a pixel art frame. I believe I'm under $55 (delivered) for my 32x32 matrix, Teensy 3.1, SD card reader, 12V A adapter and step down converter (=inside wife approval range ;)).

Another great Kickstarter is the Game Frame (sadly I'm not allowed to include the URL due to being a new user on this forum). You should look into it :)

Quote
I don't have all the costs added up for packaging and shipping, so I can't set a price yet.  I'll be shipping worldwide.
Thanks for the info. I'll be looking out for it then :)

Quote
Yes, I'll share the board on OSH Park after I'm ready to ship kits to customers.
Great!

Quote
There's just barely enough time to shift 32 pixels worth of data out to the display when outputting the smallest (1/256th) time division of 24-bit color.  Chaining multiple displays from the same controller board would require reducing the color depth at a minimum.  Driving multiple displays at 12-bit or 18-bit color is a possibility, but I haven't looked into it.
LOL. I knew I was pushing it when I asked for it ;) But it would be great with the possibility even with reduced color depth/refresh rate.

Quote
I'd like to add the ability for multiple displays to talk to each other over I2C (which is why I added the I2C pull-up resistors on the board), so they can sync what they're drawing to expand the display beyond just one matrix.  I'll look into this idea more for future revisions of the library.
I2C chaining is definately a workaround to the problem.

Quote
When the library ships, it will support mono bitmaps (same as the Adafruit library).  I'll add support for full color bitmaps in a future release, but need to figure out the best way to store them and add them to a sketch.  Animations would follow after full color bitmaps. 
 
GIFs use LZW compression, which requires around 8-16kB RAM to decompress.  There's enough free RAM on the Teensy 3.1 to potentially do the decompression, but it might be significant work to port a LZW library to the Teensy 3.1.
I'm working on a Processing 2.0 script for converting GIF/PNG/JPG to a text file with the "raw" uint8_t based values used in the Adafruit Matrix buffer for "fast" loading of pixel art graphics. I'm using parts of the code from the drawPixel function but I need to look into some of the language differences between Arduino and Processing for the more advanced bit processing features in the Adafruit code that I'm unfamiliar with (my programming skills are rusty. It was more than 15 years since I had programmed C/C++ when I got into Arduino last year).

Quote
There's an SPI port available on the board, and the Teensy 3.x has an SD card library, so adding a SD card is a good idea.  That's a good place to store bitmaps or animations.  The board features are locked down so it won't be a part of this kit, but there's probably an easy way to wire up an adapter.  I'd love to discuss this and the GIF/animation support more.
Bitmaps/animation storage was my reasoning as well :) It should be really easy to hook up a SD card reader, but adding the needed hardware to the PCB in a later revision would not add a lot of complexity/cost and would add flexibility and look tidier.

A often used way to "fake" support for (GIF based) bitmap animations is to save each frames as separate bitmap files and include information about the frame rate used in the (GIF) animation. But it would be great if the Teensy has enough grunt to pull it of from the original GIF without any pre-conversion.

[code]I wanted to keep this board as simple to assemble, and as low cost as possible, so adding a regulator that supports 4A wasn't a good fit.  Adafruit has a 5V 4A adapter for $15, which seems like a reasonable price to me.[/quote]
That's fully understandable. 5V 4A adapters are not expensive. If one wants to use a 12v adapter a separate step down converter is both cheap and small (and I have one laying around waiting to be dropped into my build).

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #20
Quote
I love what he's been able to come up with but the pricing is sadly out of the range I'm comfortable spending on a pixel art frame. I believe I'm under $55 (delivered) for my 32x32 matrix, Teensy 3.1, SD card reader, 12V A adapter and step down converter
That's a great price, you must have a good source for the matrix display. Even at Sparkfun (cheaper displays than Adafruit), you couldn't get a display plus Teensy 3.1 for $55 before shipping.

Quote
Another great Kickstarter is the Game Frame
Cool, that's new to me.  I like the square pixels.  I don't like the cost.

Quote
Driving multiple displays at 12-bit or 18-bit color is a possibility, but I haven't looked into it.
Quote
But it would be great with the possibility even with reduced color depth/refresh rate.
I'll keep that in mind for future releases of the library.

Quote
I'm working on a Processing 2.0 script for converting GIF/PNG/JPG to a text file with the "raw" uint8_t based values used in the Adafruit Matrix buffer for "fast" loading of pixel art graphics.
Do you intend to compile these into a sketch, or send them via serial so the graphics can be changed without recompiling? 

I think Adafruit's library is using 5-6-5 color, so you have to do some shifting and masking to convert.  I'm using 3 bytes per pixel, one byte per color, so it should be easy to draw from an array of uint8_t RGB values.

Code: [Select]
typedef struct rgb24 {
  uint8_t red;
  uint8_t green;
  uint8_t blue;
} rgb24;

void drawPixel(int16_t x, int16_t y, rgb24 color);

Quote
adding the needed hardware to the PCB in a later revision would not add a lot of complexity/cost and would add flexibility and look tidier.
I'll keep this in mind for when I start work on a new version of the board (well after I ship the kit and library)

Quote
That's fully understandable. 5V 4A adapters are not expensive. If one wants to use a 12v adapter a separate step down converter is both cheap and small (and I have one laying around waiting to be dropped into my build)
Do you have a link to an example?  I did some searching and didn't find a small cheap step-down converter that can handle 4A output.

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #21
Quote
That's a great price, you must have a good source for the matrix display. Even at Sparkfun (cheaper displays than Adafruit), you couldn't get a display plus Teensy 3.1 for $55 before shipping.
I took a chance and got it through AliExpress.

Quote
Cool, that's new to me.  I like the square pixels.  I don't like the cost.
Me too to both. But at the same time he has spent a great deal of time and take a lot of pride in the quality of the finished product so it's understandable that the pricing gets high.

Quote
Do you intend to compile these into a sketch, or send them via serial so the graphics can be changed without recompiling?
I hadn't thought about sending the data through serial. Great input :) I thought about using the Mega and compile the files in the sketch or alternatively wire up a SD card reader and read the files from there for added flexibility. But I really don't want a bulky Mega sitting on the back of the display/frame and are uncertain how much I can push the Nano. Teensy and your library is looking like a much better solution if I want to go beyond mostly static frames.

Quote
I think Adafruit's library is using 5-6-5 color, so you have to do some shifting and masking to convert.  I'm using 3 bytes per pixel, one byte per color, so it should be easy to draw from an array of uint8_t RGB values.
The GFX library is using 565, but the matrix buffer is using 444. In addition the color bits in the buffer are shifted around in a strange way (to me) and handled differently between the bitplanes (you'll see it if you look into the drawPixel function). I'm starting to understand it now but it was a big leap for a rusty rookie like me.

Quote
Do you have a link to an example?  I did some searching and didn't find a small cheap step-down converter that can handle 4A output.
I think that the step down converter from eBay I have laying around actually can't handle the load come to think about it, but I have read that KIM-055L based step down converters are able to handle a high constant load (but I know little about the quality).

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #22
Good Stuff Louis,

My teensy turned up today but I am still waiting on my 16x32 panel, it should be here next week. Pretty excited to try out all your hard work!

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #23
I've been following this topic with great interest, and I will surely buy a few kits. Can't wait!

In the meanwhile, I've ordered a 16x32 and a 32x32 matrix from aliexpress /store/814152 (I'm a new user, can't post a proper URL) at very good prices just in case someone is interested. Still waiting for the Teensys...

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #24
lcunha: I bought my panels from the same store :) Very pleased with the panels.

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #25
Which of the models did you buy? P5 or P6?, are those the same as adafruit/sparkfun panels?

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #26
The P6s are the same as Adafruit's: 192mmx96mm (32x16) and 192mmx192mm (32x32) and 1/8 driving. Some (all?) P5s are 1/16 driving and I believe, please correct me if I'm wrong, that these would need changes in the library to work.

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #27
I bought the P6 versions. The 16x32 is 1/8 and the 32x32 is 1/16.

I'm finalizing my Processing script for converting GIF/PNG/JPG to the Adafruit matrix buffer format. I have images up and running but it seems like the 4/4/4 down conversion of colors are very harsh to some of the test images I'm using (or a bug or two might still be lurking in the code).

I plan on releasing the script as soon as I have managed to tidy it up a little bit (the code is not a pretty sight at the moment) and looked into the color down conversion issue.

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #28
I loaded another test image and quickly noticed that my problem with the colors where worse than I initially tought.

The culprit seems to be my adaption of the bit manipulation routines found in Adafruit's drawPixel function in the RGBMatrixPanel.cpp file. I believe it can be related to the way the original code uses pointers/references and the way I have converted the code to Processing and/or the way I handle binary data.

Here is the current Processing code:
Code: [Select]
PImage image;
String imageName = "test.gif";
String saveDir = "./imageFiles/";
PrintWriter outputMatrix;
int [][] matrixbuff= new int [3][32];

void setup() {
  selectInput("Select a file to process:", "imageName");
}

void imageName(File selection) {
  if (selection == null) {
    println("Window was closed or the user hit cancel.");
  }
  else {
    println("User selected " + selection.getAbsolutePath());
    // Do note that the file used is from the hardcoded reference in the top of this file and not the file selection dialog - need more code to handle it correctly
    image = loadImage(imageName);
    size(image.width, image.height);
    outputMatrix = createWriter(saveDir + "image.h");
    //    outputMatrix = createWriter(saveDir + imageName.substring(0, (imageName.length()-4)) + ".h");
    background(0, 0, 0);
    image(image, 0, 0);

    outputMatrix.println("// Generated by Processing script");
    outputMatrix.println("// Original file: " + imageName);
    outputMatrix.println("// Size: " + image.width + "x" + image.height + "px");
    outputMatrix.println("#include <avr/pgmspace.h>");
    outputMatrix.println("static const uint8_t PROGMEM image[] = {");

    //Convert all pixels from original color > 5/6/5 > 4/4/4 > matrix buffer format and save to file
    //Can be done much more elegantly but I'm to rusty/lazy to do it properly at the moment
    for (int y = 0; y < 16; y++) {
      println("y:" + y);
      for (int x = 0; x < 32; x++) {
        print("x:" + x + " y:");

        int limit;
        int nPlanes = 4;

        int c;
        int r;
        int g;
        int b;
        int c16;
        int r16;
        int g16;
        int b16;

        // Convert original color to 5/6/5 format
        color tempColor = image.get(x, y);
        int red = tempColor >> 16 & 0xFF;
        int green = tempColor >> 8 & 0xFF;
        int blue = tempColor & 0xFF;
        float alpha = alpha(tempColor);

        if (alpha == 255) {
          c = Color565(red, green, blue);
        }
        else {
          c = Color565(0, 0, 0);
        }

        tempColor = image.get(x, y+16);
        red = tempColor >> 16 & 0xFF;
        green = tempColor >> 8 & 0xFF;
        blue = tempColor & 0xFF;
        alpha = alpha(tempColor);

        if (alpha == 255) {
          c16 = Color565(red, green, blue);
        }
        else {
          c16 = Color565(0, 0, 0);
        }

        // Matrix needs 4/4/4. Pluck out relevant bits from 5/6/5 while separating into R,G,B:
        // Upper half

        r =  c >> 12;        // RRRRrggggggbbbbb
        g = (c >>  7) & 0xF; // rrrrrGGGGggbbbbb
        b = (c >>  1) & 0xF; // rrrrrggggggBBBBb

        //quick and dirty graytone gradient hack to figure out whats wrong with my adaption of the bit manipulation routines
        //r = g = b = y;

        println(y + " Color:" + c + ",B" + binary(r, 4) + binary(g, 4) + binary(b, 4) + ",0x" + hex(r, 1) + ",0x" + hex(g, 1) + ",0x" + hex(b, 1) + ",");

        // Matrix needs 4/4/4. Pluck out relevant bits from 5/6/5 while separating into R,G,B:
        // Lower half
        r16 =  c16 >> 12;        // RRRRrggggggbbbbb
        g16 = (c16 >>  7) & 0xF; // rrrrrGGGGggbbbbb
        b16 = (c16 >>  1) & 0xF; // rrrrrggggggBBBBb
        println("    y:" + (y + 16) + " Color:" + c16 + ",B" + binary(r16, 4) + binary(g16, 4) + binary(b16, 4) + ",0x" + hex(r16, 1) + ",0x" + hex(g16, 1) + ",0x" + hex(b16, 1) + ",");

        // Data for the upper half of the display is stored in the lower bits of each byte.
        // Plane 0 is a tricky case -- its data is spread about, stored in least two bits not used by the other planes.
        matrixbuff[2][x] &= ~unbinary("00000011");          // Plane 0 R,G mask out in one op
        if (boolean(r & 1)) matrixbuff[2][x] |= unbinary("00000001");  // Plane 0 R: 64 bytes ahead, bit 0
        if (boolean(g & 1)) matrixbuff[2][x] |= unbinary("00000010");  // Plane 0 G: 64 bytes ahead, bit 1
        if (boolean(b & 1)) {
          matrixbuff[1][x] |= unbinary("00000001");  // Plane 0 B: 32 bytes ahead, bit 0
        }
        else {
          matrixbuff[1][x] &= ~unbinary("00000001");  // Plane 0 B unset; mask out
        }

        // The remaining three image planes are more normal-ish.
        // Data is stored in the high 6 bits so it can be quickly
        // copied to the DATAPORT register w/6 output lines.

        // Loop counter stuff
        limit = 1 << nPlanes;
        for (int bit = 2; bit < limit; bit <<= 1) {
          matrixbuff[0][x] &= ~unbinary("00011100");            // Mask out R,G,B in one op
          if (boolean(r & bit)) matrixbuff[0][x] |= unbinary("00000100");  // Plane N R: bit 2
          if (boolean(g & bit)) matrixbuff[0][x] |= unbinary("00001000");  // Plane N G: bit 3
          if (boolean(b & bit)) matrixbuff[0][x] |= unbinary("00010000");  // Plane N B: bit 4
        }

        // Data for the lower half of the display is stored in the upper
        // bits, except for the plane 0 stuff, using 2 least bits.
        matrixbuff[0][x] &= ~unbinary("00000011");              // Plane 0 G,B mask out in one op
        if (boolean(r16 & 1)) {
          matrixbuff[1][x] |= unbinary("00000010"); // Plane 0 R: 32 bytes ahead, bit 1
        }
        else {
          matrixbuff[1][x] &= ~unbinary("00000010"); // Plane 0 R unset; mask out
        }
        if (boolean(g16 & 1)) matrixbuff[0][x] |=  unbinary("00000001"); // Plane 0 G: bit 0
        if (boolean(b16 & 1)) matrixbuff[0][x] |=  unbinary("00000010"); // Plane 0 B: bit 0

        // Loop counter stuff

        for (int bit = 2; bit < limit; bit <<= 1) {
          matrixbuff[0][x] &= ~unbinary("11100000");                        // Mask out R,G,B in one op
          if (boolean(r16 & bit)) matrixbuff[0][x] |= unbinary("00100000");  // Plane N R: bit 5
          if (boolean(g16 & bit)) matrixbuff[0][x] |= unbinary("01000000");  // Plane N G: bit 6
          if (boolean(b16 & bit)) matrixbuff[0][x] |= unbinary("10000000");  // Plane N B: bit 7
        }
        println("    Buffer0:0x" + hex(matrixbuff[0][x], 2) + " Buffer1:0x" + hex(matrixbuff[1][x], 2) + " Buffer2:0x" + hex(matrixbuff[2][x], 2));
      }
      for (int x = 0; x < image.width; x++) {
        outputMatrix.print("0x" + hex(matrixbuff[0][x], 2) + ",");
      }
      outputMatrix.println("");
      for (int x = 0; x < image.width; x++) {
        outputMatrix.print("0x" + hex(matrixbuff[1][x], 2) + ",");
      }
      outputMatrix.println("");
      for (int x = 0; x < image.width; x++) {
        outputMatrix.print("0x" + hex(matrixbuff[2][x], 2) + ",");
      }     
      outputMatrix.println("");
    }
    outputMatrix.println("};"); 
    outputMatrix.flush();
    outputMatrix.close();
  }
}

int Color565(int r, int g, int b) {
  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

Re: Controller Board for Adafruit's Large RGB Matrix Display

Reply #29
Sorry I didn't jump in earlier, I stopped getting topic update notification emails, not sure why.

[quote author="lcunha"]The P6s are the same as Adafruit's: 192mmx96mm (32x16) and 192mmx192mm (32x32) and 1/8 driving.[/quote]

I see the 32x32 LED display listed as 1/8 scan.  I wouldn't trust that spec.
http://http://www.aliexpress.com/store/product/good-quality-led-module-p6-indoor-fullcolor-192-192-smd-led-module-in-alibaba/814152_1598164078.html

There's a good chance that it's just a mistake, though there are some 32x32 displays that have two separate input connectors, each with 1/8 scan driving half the display.  Hopefully it's not one of these displays.  Though there's a chance my library could support those displays - by chaining the two separate 16x32 display halves together through a ribbon cable - but it's not something I plan on supporting right away.  There's a picture of one of these displays here (first picture on the page):
http://http://learn.adafruit.com/32x16-32x32-rgb-led-matrix/wiring-the-32x32-matrix

The library will support 16x32 (1/8 scan) and 32x32 (1/16 scan) when I release it.