0

Fast&simple streaming from PC screen to 32x32 matrix
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Fast&simple streaming from PC screen to 32x32 matrix

by MarkusL on Thu Feb 20, 2014 10:09 pm

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=xsS2UHmA ... e=youtu.be

The Sketch:
Code: Select all | TOGGLE FULL SIZE
// 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
MarkusL
 
Posts: 2
Joined: Thu Feb 20, 2014 9:39 pm

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

by adafruit_support_mike on Fri Feb 21, 2014 1:59 am

Nice! Thanks for posting. ;-)
When you void a product warranty, you give up your right to sue the manufacturer if something goes wrong and accept full responsibility for whatever happens next. And then you truly own the product.

adafruit_support_mike
 
Posts: 39365
Joined: Thu Feb 11, 2010 2:51 pm

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

by MarkusL on Sun Feb 23, 2014 12:25 am

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 | TOGGLE FULL SIZE
/*
* 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
MarkusL
 
Posts: 2
Joined: Thu Feb 20, 2014 9:39 pm

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

by sbbrain on Sat Mar 01, 2014 12:22 am

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.

sbbrain
 
Posts: 1
Joined: Mon Dec 02, 2013 5:31 pm

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

by rp on Tue Jun 10, 2014 3:59 am

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?

rp
 
Posts: 1
Joined: Tue Jun 03, 2014 7:00 pm

Please be positive and constructive with your questions and comments.