Page 1 of 1

Fast&simple streaming from PC screen to 32x32 matrix

Posted: Thu Feb 20, 2014 10:09 pm
by MarkusL
Hi!

I didn't find a simple example to stream live data from my PC screen to the 32x32 panel using an Arduino. Therefore I hacked a small sketch and a Java app that allows streaming with about 12fps. The Java app captures a specific part on the screen (defined with a movable, transparent, window), and prepares the matrix buffer. To reduce the work on the Arduino as much as possible, I have ported some parts of the Adafruit Matrix Library to Java, and perform them on the PC. Hardware setup is equivalent to the Adafruit tutorial.

Here's a video:
http://www.youtube.com/watch?v=BANNED ... e=youtu.be

The Sketch:

Code: Select all

// Fast Serial Screen Streaming, written by Markus Lipp, based on examples from AdaFruit
// BSD license, all text above must be included in any redistribution.

#include <Adafruit_GFX.h>   // Core graphics library
#include <RGBmatrixPanel.h> // Hardware-specific library

#define CLK 11  // MUST be on PORTB! (Use pin 11 on Mega)
#define OE  9
#define LAT 10
#define A   A0
#define B   A1
#define C   A2
#define D   A3
RGBmatrixPanel matrix(A, B, C, D, CLK, LAT, OE, false);

int pos=0;

uint8_t* buffer;
int bufferLength;

void setup() {  
  matrix.begin();
  Serial.begin(250000);
 
  pos=0;
  bufferLength = 1536;
  buffer = matrix.backBuffer();   
}

byte prevVal,val;
void loop() {    
   if (Serial.available())
   {     
      prevVal = val;
      val = Serial.read();          
      //prepare RGB-Matrix buffer (including gamma correction) directly on PC and stream
      if ( (prevVal==0x21 && val==0x8) //magic numbers      
          || pos>=bufferLength)
        {
          pos=0;
        } else
        {
          buffer[pos++]=val;
        }            
   }
}
And here is the Java app. Just start the jar in the bin directory. Move&Scale the small window to define what to stream. Click "enable output" to start streaming.
https://dl.dropboxusercontent.com/u/170 ... Stream.rar
Image

Re: Fast&simple streaming from PC screen to 32x32 matrix

Posted: Fri Feb 21, 2014 1:59 am
by adafruit_support_mike
Nice! Thanks for posting. ;-)

Re: Fast&simple streaming from PC screen to 32x32 matrix

Posted: Sun Feb 23, 2014 12:25 am
by MarkusL
Now with 24bit support and 30hz framerate, using a Teensy! I believe this is a first. To achieve this, I prepare the interleaved, gamma-corrected buffer on the PC and stream it live. I don't use DMA yet, this could reduce CPU even more.

Especially on dark scenes there are still some artifacts on the bottom side, must either be a bug or timing issue.

Sketch for Teensy 3.1:

Code: Select all

/*
* Modified by Markus Lipp adding interleaved buffers, streaming, 32x32 & 24bit support
*
* Based on "_16x32_Matrix R3.0" by Creater Alex Medeiros, http://PenguinTech.tk
* Use code freely and distort its contents as much as you want, just remeber to thank the 
* original creaters of the code by leaving their information in the header. :)
*/

//PortC[0:11] = {15, 22, 23, 9, 10, 13, 11, 12, 28, 27, 29, 30}
//PortD[0:7] = {2, 14, 7, 8, 6, 20, 21, 5}
//Define pins
const uint8_t
//PortC
APIN      = 15, BPIN      = 22, CPIN      = 23, DPIN = 9,
CLOCKPIN  = 10, LATCHPIN  = 13, OEPIN     = 11,
//PortD
R1PIN     = 2, R2PIN     = 8,
G1PIN     = 14, G2PIN     = 6,
B1PIN     = 7, B2PIN     = 20;

uint8_t pinTable[13] = {
  R1PIN,R2PIN,G1PIN,G2PIN,B1PIN,B2PIN,
  APIN,BPIN,CPIN,DPIN,CLOCKPIN,LATCHPIN,OEPIN};

//Addresses 1/8 rows Through a decoder
uint16_t const A = 1, B = 2,C = 4, D=8;
//Acts like a 16 bit shift register
uint16_t const SCLK   = 16;
uint16_t const LATCH  = 32;
uint16_t const OE     = 64;

uint16_t const abcVar[16] = { //Decoder counter var
  0,A,B,A+B,C,C+A,C+B,A+B+C,
  0+D,A+D,B+D,A+B+D,C+D,C+A+D,C+B+D,A+B+C+D};

//Data Lines for row 1 red and row 9 red, ect.
uint16_t const RED1   = 1, RED2   = 8;
uint16_t const GREEN1 = 2, GREEN2 = 16;
uint16_t const BLUE1  = 4, BLUE2  = 32;

const uint8_t SIZEX = 32;
const uint8_t SIZEY = 32;

//Here is where the data is all read
uint8_t interleavedBuffer[SIZEX*SIZEY*4];

//BAM and interrupt variables
boolean actDisplay = false;
uint8_t rowN = 0;
uint16_t BAM;
uint8_t BAMMAX = 7; //now 24bit color! (0-7)


void setup() {
  for(uint8_t i = 0; i < 13; i++){
        pinMode(pinTable[i], OUTPUT);
    }
  timerInit();
  Serial.begin(250000); 
}

uint8_t r,g, prevVal,val;
int dataPos=0;

void loop() {       
   if (Serial.available())
   {     
      prevVal = val;
      val = Serial.read();     
   
      if ( (prevVal==192 && val==192) || dataPos>=4096)
      {
         dataPos=0;
      }
      else
      {
        interleavedBuffer[dataPos++] = val;
      }
   }  
}

IntervalTimer timer1;

#define BAMDUR 2
void timerInit() {
    BAM = 0;
    timer1.begin(attackMatrix,BAMDUR);
}


//Where the PIT calls
//The updating matrix stuff happens here
//each pair of rows is taken through its BAM cycle
//then the rowNumber is increased and id done again
void attackMatrix() {
    uint16_t portData;

    //sets up which BAM the matrix is on
    if(BAM == 0) { timer1.begin(attackMatrix,BAMDUR); } //code takes max 41 microsec to complete
    if(BAM == 1) { timer1.begin(attackMatrix,BAMDUR*2); } //so 42 is a safe number
    if(BAM == 2) { timer1.begin(attackMatrix,BAMDUR*4); }
    if(BAM == 3) { timer1.begin(attackMatrix,BAMDUR*8); }
    if(BAM == 4) { timer1.begin(attackMatrix,BAMDUR*16); }
    if(BAM == 5) { timer1.begin(attackMatrix,BAMDUR*32); }
    if(BAM == 6) { timer1.begin(attackMatrix,BAMDUR*64); }
    if(BAM == 7) { timer1.begin(attackMatrix,BAMDUR*128); }

    portData = 0; // Clear data to enter
    portData |= (abcVar[rowN])|OE; // abc, OE
    portData &=~ LATCH;        //LATCH LOW
    GPIOC_PDOR = portData;  // Write to Port
    
    uint8_t *start = &interleavedBuffer[rowN*SIZEX*8+((7-BAMMAX)+BAM)*32];
    
    for(uint8_t _x = 0; _x < 32; _x++){
          GPIOD_PDOR = start[_x]; // Transfer data
          GPIOC_PDOR |=  SCLK;// Clock HIGH
          GPIOC_PDOR &=~ SCLK;// Clock LOW
    }

    GPIOC_PDOR |= LATCH;// Latch HIGH
    GPIOC_PDOR &=~ OE;// OE LOW, Displays line
    
    
    if(BAM >= BAMMAX) { //Checks the BAM cycle for next time.
    
        if(rowN == 15){
            rowN = 0;
        } else {
            rowN ++;
        }        
        BAM = 0;
        actDisplay = false;
    } else {
        BAM ++;
        actDisplay = true;
    }
}
New video: http://www.youtube.com/watch?v=x0Wcpol7 ... e=youtu.be, http://youtu.be/dmCp1OEAtMU

Updated Java-App, just select Interleaved RGB8 for Teensy as output mode:
https://dl.dropboxusercontent.com/u/170 ... Stream.rar

Re: Fast&simple streaming from PC screen to 32x32 matrix

Posted: Sat Mar 01, 2014 12:22 am
by sbbrain
For the Teensy version of this code, where does timer1.begin() come from? I can't find the declaration of begin() anywhere in the PITimer library. It complies but there is no output.

Re: Fast&simple streaming from PC screen to 32x32 matrix

Posted: Tue Jun 10, 2014 3:59 am
by rp
Hi!
Thanks for sharing this piece of code!
Do you know how I could modify the code so I can use it on more than one 32x32 panel which would be daisy chained?