[solved/video] 8x8 RGB serial port with decent framerate (Colorduino)

Hi all, i've recently started a thread http://arduino.cc/forum/index.php/topic,69235.0.html about getting frame data through to the arduino.

Now i realized that my problem is bigger than thought because it won't really work with the shiptPWM library.

Is there any solution yet on how i could drive a 8x8 RGB matrix in 255 brightness steps per color directly by feeding frames through serial port with some kind of interactive framerate?

For now my basic setup consists of an 8x8 matrix connected through 4 daisy chained 8 bit shift registers.

Cheers!

The first problem is driving your display with the required specifications. Do you have software on the arduino that shows anything on the matrix?

You have two software problems to tackle: how to scan through the columns or rows (multiplexing your array), and how to pulse in the time domain (levels of brightness)

I've set up my own 8x8 R/G display using shift registers that manages 4-bit (16 levels) of brightness per color channel. It does this all on the arduino itself, with no input from a PC. This is only possible because one whole frame only takes up 64 bytes in memory, plus an additional 64 bytes of decoded serial output for the shift registers.

Your 8-bit per channel will require 3 bytes per pixel, giving 192 bytes for a single frame. If you adapt my method of calculating the shift register data, it will take another 192 bytes of data to feed the shift registers. Obviously that's not much of a problem if you're being fed this data by the PC, but your code has to start somewhere.

Since you're not doing any actual rendering on the arduino, it's possible to store both framebuffers in memory with room to spare. Let's tackle the serial data that you must output to the shift registers first. Suppose you have the following test screen you want to output: all 64 pixels one color: #0080FF, or 0% Red, 50% Green, 100% Blue. What does this really mean? If we want 256 levels of brightness, then that really means 0/255 Red, 128/255 Green, and 255/255 Blue. So the arduino must have an internal timer that counts from 0 to 255 for each frame and either turns on or off the appropriate pixel. Look up Bit Angle Modulation because it makes more mathematical sense than simple PWM, but requires a little more understanding of bitshifting.

8x8 RGB is really 8x24, yes? I would go with SPI to 4 shift registers:
1 for row to say drive common anode high, could be a 74HC595 with Allegro UDN2982 transister array to supply the high voltage.
and 3 74LV595 for the columns to bring the shared cathode low (with current limit resistor for 16mA ofsink current) for example.
74LS595 for24mA of sink current.

So a common data out, common clock, 4 unique output clock signal, SPI will allow those 4 bytes to go out really fast.

If common cathode, the 74LS595 along the 24 anodes, and ULN2803 to sink the common cathode per row.
I'd do a picture, but my contacts are getting really dry. Off to bed ...

On his other post it sounds like his 8x24 matrix is already constructed with four shift registers, but he doesn't mention sink or source drivers.

Oh, I didn't read the other thread; where it looks like I was already commenting.

Should have just had this discussion as part of that thread.

Yeah i guess i should have just renamed the other thread and kept this conversation there.... :confused:

Anyways, i've decided that with my limited knowledge and inefficient coding i'll give an external product a try:

the colorduino shieldfrom ITead Studio which is quite similar to seedstudios rainbowduino but cheaper as it comes as a shield.
http://iteadstudio.com/store/index.php?main_page=product_info&cPath=18&products_id=312

it's a shield for the arduino that has hardware PWM for handling an 8x8 RGB matrix, which should give me more ressources on the arduino to code a good serial interface.

Let's see if I have any luck with that.
If anyone wants to, i will keep you posted on how it goes as soon as i receive the hardware.

Cheers!

Zuluriney:
the colorduino shieldfrom it's a shield for the arduino that has hardware PWM for handling an 8x8 RGB matrix, which should give me more ressources on the arduino to code a good serial interface.

Note that the color shield and the colorduino are two different things. The Colorduino is an Arduino with the LED driver hardware incorporated. The color shield is extra hardware for the Arduino to drive LEDs.

I'm playing around with the Colorduino myself, and it is a nice piece of kit.

Yes, that's why i bought it...so i don't have to do the PWM in software and to have more ressources for the rest of the code.

Buying a Full colorduino would be more expensive, i can do that as soon as i have any progress in my project.
What i'm doing is an LED Coffe table (yes, everybody is doing that ^^) which is able to receive live animations from a PC, so all processing, be it audio visualizing, or maybe an ambilight system is done on the outside and the table only serves as a display.

Yes..the computer has to be running, but it is anyways, so no loss there ^^

damn...just noticed that i bought it from Hong Kong....that could take a while...does anyone have any experience with delivery times? i was told it's gonna take up to 4 weeks to Germany.. :confused:

Alright, i've received the shield yesterday so today i started coding. it works as i wanted so far but i get only about 16 frames/sec. does anyone have suggestions to optimize my serial interface?

the frame of 192 pixels is split in half so that each half fits in arduino rx buffer

START_TOP_FRAME is byte(254)
START_BTM_FRAME is byte(253)
FRAME_HALF_END is byte(255)

which means, i can use brightness values from 0 - 252.

the processing code woks as follows:

loop{
-send START_TOP_FRAME -> send raw 96 pixels of data -> send FRAME_HALF_END -> listen
-arduino sends back START_TOP_FRAME as ack that top half was received
-send START_BTM_FRAME -> send raw 96 pixels of data -> send FRAME_HALF_END -> listen
-arduino sends back START_BTM_FRAME as ack that bottom half was received
}

so far i have tried

  • disabling the colorduino interrupt, which hasn't had any effect on the performance -> means that it's not the bottleneck
  • at 57600 b/s transfer rate the framerate is pretty much the same, which excludes too slow serial
  • the rxComplete function doesn't take much time either

which leaves me with the conclusion that the raw code in the loop() function needs optimizing. Or maybe another totally different approach? maybe compression of some sorts?

i'll be really glad about any advice! :slight_smile:

#include <Colorduino.h>

unsigned char buffer[] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251};
int i = 0;

void setup(){
  
  Serial.begin(115200);
  
  Colorduino.Init(); // initialize the board
  unsigned char whiteBalVal[3] = {34,63,63}; // for LEDSEE 6x6cm round matrix
  Colorduino.SetWhiteBal(whiteBalVal);
}

void rxComplete(){
  for(int i = 0; i<8; i++){
     for(int j = 0; j<8; j++){
       Colorduino.SetPixel(i, j, buffer[i*3*8+j*3+0], buffer[i*3*8+j*3+1], buffer[i*3*8+j*3+2]);
     }
  }
  Colorduino.FlipPage();
}

#define FRAME_TOP_START  254
#define FRAME_BTM_START  253
#define FRAME_HALF_END  255

void loop(){ 
  byte rxbyte = Serial.read();
  switch(rxbyte){
    // beginning of top half
    case FRAME_TOP_START: {
      i = 0;
      //while not end of half-frame
      while(Serial.peek() < FRAME_HALF_END){
        while(Serial.available() < 2) delay(1);
        buffer[i++] = Serial.read();
      }
      Serial.flush();
      Serial.write(FRAME_TOP_START);
      break;
    }
    // beginning of bottom half
    case FRAME_BTM_START: {
      i = 96;
      //while not end of half-frame
      while(Serial.peek() < FRAME_HALF_END){
        while(Serial.available() < 2) delay(1);
        buffer[i++] = Serial.read();
      }
      Serial.flush();
      Serial.write(FRAME_BTM_START);
      rxComplete();
      break;
    }      
  }
}

guess what...you CAN change the arduino RX BUFFER size !!!

#define RX_BUFFER_SIZE 256 <- in HardwareSerial.cpp

i guess it won't work on all models because of RAM issues but the ATmega328 works. It also depends on how much RAM you will be spending in you program.

anyways, now that the whole image fits in one buffer there's no need for splitting anymore..
which boosts the framerate to somewhere around 21. still somehow low i think ... i've read about some optimized serial libraries and will continue reading, maybe i can do it better..

and i will continue updating here ^^

cheers!

btw here's the code, i don't think i can simplify anything...

#define FRAME_START  255
#define FRAME_END  254

void loop(){
  if(Serial.available() > 0){
    byte rxbyte = Serial.read();
    if(rxbyte == FRAME_START){
        i = 0;
        //while not end of half-frame
        while(Serial.peek() < FRAME_END){
          while(Serial.available() < 2) delayMicroseconds(1);
          buffer[i++] = Serial.read();
        }
        Serial.flush();
        Serial.write(FRAME_END);
        rxComplete();
    }
  }
}

Yaaaaay! Works!

right now the simplest way to test was screen capture, captured a 200x200 region and scaled it to 8x8, with the diffuser it makes for quite classy entertainment :stuck_out_tongue:
the colors are quite good thanks to the built in white balance setting in the colorduino. i had to set all colors to a pretty low level, which dims the image to a point where it becomes more similar to a computer screen and still allows for 253 brightness values, score!

transfer rate is about 15 fps due to the heavy screenshooting on the pc. the usual 22fps i get out of it should be enough for a wide range of applications.

cheers!

here are some first pictures, a video of the thing in action will follow:)

Stats:
100Hz refresh rate, around 20fps with 254 Brightness levels through serial.

Wow I'm working on something similar but have come across a problem: I am not quite sure how to use PWM with shift registers which are connected to my 8x8 rgb led matrix. I did some research and found Elco's shiftPWM library however I could not find the code for the shiftMatrixPWM library that everyone's talking about. Could you please let me know how you did it or specifically where I can find the shiftMatrixPWM code? Much appreciated.

nataliew, the ShiftMatrixPWM library is buried in the ShiftPWM thread. Here is a link to the latest version in the thread.

Hope this will help you. Look through the rest of that thread, there is some good information in it.

Thanks! Just looking through the code, I'm confused why there is a row latch pin and also a column latch pin. My 4 shift registers for my 4x4 rgb matrix are currently daisy-chained and I can control each led... but am I meant I separate the latch pin for the common anodes from the latch pin for the cathodes for the shiftMatrixPWM to work?

Thanks Milamber! I've read through the forum that you had linked me. I'm still a bit confused as to why there is a columnLatch and a rowLatch in the shiftMatrixPWM.

I've got a 4x4 matrix with me which uses four 595s (one for each rgb colour and one for the common anode). This means I have a latch, clock and data pin that needs to be connected to the Arduino Uno. How should I connect it up using the shiftMatrixPWM? Or more specifically, what should I be assigning the rowLatch and columnLatch pins to?

Much appreciated.