Go Down

Topic: Max72xxPanel library (Read 1 time) previous topic - next topic

nitinarora

Hello kind people,

I have been a silent lurker for a a while and have by and large been able to resolve my issues with the resolutions posted by the experienced folks here. However I have run into an issue that I am unable to resolve. My idea is to build a 16x64 audio spectrum analyzer. I have the code working for an 8x64 matrix, but my problem is that when using a 16x64 matrix things go crazy. Below is a code snippet that i use to test the matrix:

Code: [Select]

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>

int pinCS = 10; // Attach CS to this pin, DIN to MOSI and CLK to SCK (cf http://arduino.cc/en/Reference/SPI )
int numberOfHorizontalDisplays = 8;
int numberOfVerticalDisplays = 1;


Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);


void setup() {
matrix.setIntensity(15);

// Adjust to your own needs
matrix.setPosition(0, 0, 1); // The first display is at <0, 0>
matrix.setPosition(1, 1, 1); // The second display is at <1, 0>
matrix.setPosition(2, 2, 1); // The third display is at <2, 0>
matrix.setPosition(3, 3, 1); // And the last display is at <3, 0>
matrix.setPosition(4, 4, 1); // And the last display is at <3, 0>
matrix.setPosition(5, 5, 1); // And the last display is at <3, 0>
matrix.setPosition(6, 6, 1); // And the last display is at <3, 0>
matrix.setPosition(7, 7, 1); // And the last display is at <3, 0>

matrix.setPosition(8, 0, 0); // The first display is at <0, 0>
matrix.setPosition(9, 1, 0); // The second display is at <1, 0>
matrix.setPosition(10, 2, 0); // The third display is at <2, 0>
matrix.setPosition(11, 3, 0); // And the last display is at <3, 0>
matrix.setPosition(12, 4, 0); // And the last display is at <3, 0>
matrix.setPosition(13, 5, 0); // And the last display is at <3, 0>
matrix.setPosition(14, 6, 0); // And the last display is at <3, 0>
matrix.setPosition(15, 7, 0); // And the last display is at <3, 0>
//  ...
matrix.setRotation(0, 1);    // The first display is position upside down
matrix.setRotation(1, 1);   
matrix.setRotation(2, 1);   
matrix.setRotation(3, 1);    // The same hold for the last display
matrix.setRotation(4, 1);   
matrix.setRotation(5, 1);   
matrix.setRotation(6, 1);   
matrix.setRotation(7, 1);   
matrix.setRotation(8, 1);    // The first display is position upside down
matrix.setRotation(9, 1);   
matrix.setRotation(10, 1);   
matrix.setRotation(11, 1);    // The same hold for the last display
matrix.setRotation(12, 1);   
matrix.setRotation(13, 1);   
matrix.setRotation(14, 1);   
matrix.setRotation(15, 1);   
}

void loop() {
  // put your main code here, to run repeatedly

matrix.fillScreen(LOW);
for (int x = 0; x<matrix.width(); x++){
       //int temp = amplitude[x];
   for(int y = 0; y<=16;y++){
       matrix.drawLine(x, 16, x, 16 - y, HIGH);
       matrix.write(); // Send bitmap to display
       delay(10);
      }
    }
}


My basic issue is that the arduino-Max72xxPanel seems to refuse to work after 10 modules. I am happy to edit the library source. However I am have no clue where to begin. Can some one one please point me in the correct direction? Appreciate the help.

Thanks
Nitin

INTP

Does the lib mention a limit to number of addresses?

nitinarora

Thank you for the reply. I haven't seen an official citation so honestly I am not sure. I was going through the source code but unfortunately I am not very confident from there either.

Thanks
Nitin.

nitinarora

I spent a considerable amount of time yesterday trying to trouble shoot this. I probably should have been more descriptive in my initial post. My setup is 2 sets of 8 8x8 matrices stacked one on top of the other to make a 16x64 matrix. The first display is the bottom left and this is the one connected to the Arduino. The 8th display is connected to the top left matrix. I had tested the setup with a 8x64 and it would work just fine.

Currently if i edit

Code: [Select]
matrix.drawLine(x, 16, x, 16 - y, HIGH);

to

Code: [Select]
matrix.drawLine(16, 16, 16, 0, HIGH);

the lower half of the display correctly draws a line from the first column of the third display to the top but the top half which I would expect to behave similarly (first column on the 11th display) to be lit up instead has the last column of the 10th display on.

I haven't tried Parola. Does anyone know if it supports simple graphics primitives such as a line?

Again would much appreciate if someone can point me in the correct direction. I am happy to invest time in trying to modify the library, but a pointer to the correct place would help immensely.

Thanks
Nitin

Grumpy_Mike

Quote
My basic issue is that the arduino-Max72xxPanel seems to refuse to work after 10 modules.
You got decoupling caps on all those modules?

nitinarora

You got decoupling caps on all those modules?
As fate would have it, I am replying to this from work and all of last night and whatever little time I had in the morning I was kicking myself in the rear reminding myself of the article on your website that has helped me so much in the past about the absolute need for proper decoupling. The modules were the prefabricated type and did have the 0.1uf ceramics but no electrolytics. Added individual 10uf as recommended by the data sheet and viola.

That along with this:

http://forum.arduino.cc/index.php?topic=268670.0


where you highlight the need for proper line termination sorted things out for me. I did order a few buffers because I might scale this up a bit but two lessons learned:

1. Decoupling is not optional.
2. Listen to Mike.


Thank you for all the help. On to the next challenge!! Boy is physics an unforgiving master.

oh! and did I mention - Listen to Mike, he knows what he is talking about!!!!!!!


Thank you
Nitin

Grumpy_Mike

Quote
Boy is physics an unforgiving master.
But at least she is consistent  :)

Glad I could help in getting it sorted.

nitinarora

But at least she is consistent  :)

Glad I could help in getting it sorted.
True. And as it stands today, I believe consistency is what the world needs more of. A lot more!!

I look forward to learning more here.

Cheers!!

nitinarora

Hi,

Apologies in advance for a longish post but I want to put in as much details as I can. I was not sure if I should start a new topic since the question relates to the same project but involves the code and I did not want to cross post.

The idea of the project was to make a 16x64 audio spectrum analyzer with the FFT running on a laptop on processing sending data to an HC-05 BT module to a standalone Arduino that drives the Max7219 displays. I have been able to verify that the 8x8 modules work fine. The processing code that I am using is adapted from here:

https://github.com/snskreationz/Real-Time-RGB-Matrix-Spectrum-Analyzer


Code: [Select]
import processing.serial.*;
//import processing.sound.*;
import ddf.minim.analysis.*;
import ddf.minim.*;


Minim minim;
AudioInput in;
FFT fft;
int buffer_size = 4096;
float sample_rate = 200000;
int freq_width = 150;
int bands = 64;
Serial port1;
float[] spectrum = new float[bands];
int [ ]freq_array = {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};
float[] freq_height = {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};

void settings()
{
 size(512, 360);
}
void setup() {
 
  background(255);
    
  // Create an Input stream which is routed into the Amplitude analyzer
  minim = new Minim(this);
  
  // start the Audio Input
  in = minim.getLineIn(Minim.MONO,buffer_size, sample_rate);
  
  // patch the AudioIn
  // create an FFT object that has a time-domain buffer
  // the same size as line-in's sample buffer
  fft = new FFT(in.bufferSize(), in.sampleRate());
  // Tapered window important for log-domain display
  fft.window(FFT.HAMMING);
  port1 = new Serial (this, "COM5", 115200);
}      

void draw() {
  background(255);
    
for(int k=0; k<64; k++){
freq_array[k] = 0;
}

 fft.forward(in.mix);
 
  freq_height[0] = fft.calcAvg((float) 0, (float) 30);
  freq_height[1] = fft.calcAvg((float) 31, (float) 60);
  freq_height[2] = fft.calcAvg((float) 61, (float) 100);
  freq_height[3] = fft.calcAvg((float) 101, (float) 150);
  freq_height[4] = fft.calcAvg((float) 151, (float) 200);
  freq_height[5] = fft.calcAvg((float) 201, (float) 250);
  freq_height[6] = fft.calcAvg((float) 251, (float) 300);
  freq_height[7] = fft.calcAvg((float) 301, (float) 350);
  freq_height[8] = fft.calcAvg((float) 351, (float) 400);
  
  for(int n = 9; n < 63; n++)
  {
  freq_height[n] = fft.calcAvg((float) (351+(freq_width*(n-9))), (float) (500+(freq_width*(n-9))));
  }
  
  freq_height[63] = (fft.calcAvg((float) 20, (float) 60));
  
  float x = 8;
  float y = 3;
  for(int j=0; j<64; j++){    
    freq_height[j] = freq_height[j]*(log(x)/y);
    x = x + (x);
  }
  
  for(int j=0; j<64; j++){    
    if (freq_height[j] < 2000 && freq_height[j] > 180){freq_array[j] = 16;}
    else{ if (freq_height[j] <= 180 && freq_height[j] > 160){freq_array[j] = 15;}
    else{ if (freq_height[j] <= 160 && freq_height[j] > 130){freq_array[j] = 14;}
    else{ if (freq_height[j] <= 130 && freq_height[j] > 110){freq_array[j] = 13;}
    else{ if (freq_height[j] <= 110 && freq_height[j] > 90){freq_array[j] = 12;}
    else{ if (freq_height[j] <= 90 && freq_height[j] > 70){freq_array[j] = 11;}
    else{ if (freq_height[j] <= 70 && freq_height[j] > 60){freq_array[j] = 10;}
    else{ if (freq_height[j] <= 60 && freq_height[j] > 50){freq_array[j] = 9;}
    else{ if (freq_height[j] <= 50 && freq_height[j] > 40){freq_array[j] = 8;}
    else{ if (freq_height[j] <= 40 && freq_height[j] > 30){freq_array[j] = 7;}
    else{ if (freq_height[j] <= 30 && freq_height[j] > 20){freq_array[j] = 6;}
    else{ if (freq_height[j] <= 20 && freq_height[j] > 15){freq_array[j] = 5;}
    else{ if (freq_height[j] <= 15 && freq_height[j] > 11){freq_array[j] = 4;}
    else{ if (freq_height[j] <= 11 && freq_height[j] > 8){freq_array[j] = 3;}
    else{ if (freq_height[j] <= 8 && freq_height[j] > 5){freq_array[j] = 2;}
    else{ if (freq_height[j] <= 5 && freq_height[j] > 2){freq_array[j] = 1;}
    else{ if (freq_height[j] <= 2 && freq_height[j] > 0){freq_array[j] = 0;}
  }}}}}}}}}}}}}}}}}
  
    String sta = "M";
    String aa = str(freq_array[0]);
    String bb = str(freq_array[1]);
    String cc = str(freq_array[2]);
    String dd = str(freq_array[3]);
    String ee = str(freq_array[4]);
    String ff = str(freq_array[5]);
    String gg = str(freq_array[6]);
    String hh = str(freq_array[7]);
    String ii = str(freq_array[8]);
    String jj = str(freq_array[9]);
    String kk = str(freq_array[10]);
    String ll = str(freq_array[11]);
    String mm = str(freq_array[12]);
    String nn = str(freq_array[13]);
    String oo = str(freq_array[14]);
    String pp = str(freq_array[15]);
    String qq = str(freq_array[16]);
    String rr = str(freq_array[17]);
    String ss = str(freq_array[18]);
    String tt = str(freq_array[19]);
    String uu = str(freq_array[20]);
    String vv = str(freq_array[21]);
    String ww = str(freq_array[22]);
    String xx = str(freq_array[23]);
    String yy = str(freq_array[24]);
    String zz = str(freq_array[25]);
    String aaa = str(freq_array[26]);
    String bbb = str(freq_array[27]);
    String ccc = str(freq_array[28]);
    String ddd = str(freq_array[28]);
    String eee = str(freq_array[30]);
    String fff = str(freq_array[31]);
    String ggg = str(freq_array[32]);
    String hhh = str(freq_array[33]);
    String iii = str(freq_array[34]);
    String jjj = str(freq_array[35]);
    String kkk = str(freq_array[36]);
    String lll = str(freq_array[37]);
    String mmm = str(freq_array[38]);
    String nnn = str(freq_array[39]);
    String ooo = str(freq_array[40]);
    String ppp = str(freq_array[41]);
    String qqq = str(freq_array[42]);
    String rrr = str(freq_array[43]);
    String sss = str(freq_array[44]);
    String ttt = str(freq_array[45]);
    String uuu = str(freq_array[46]);
    String vvv = str(freq_array[47]);
    String www = str(freq_array[48]);
    String xxx = str(freq_array[49]);
    String yyy = str(freq_array[50]);
    String zzz = str(freq_array[51]);
    String aaaa = str(freq_array[52]);
    String bbbb = str(freq_array[53]);
    String cccc = str(freq_array[54]);
    String dddd = str(freq_array[55]);
    String eeee = str(freq_array[56]);
    String ffff = str(freq_array[57]);
    String gggg = str(freq_array[58]);
    String hhhh = str(freq_array[59]);
    String iiii = str(freq_array[60]);
    String jjjj = str(freq_array[61]);
    String kkkk = str(freq_array[62]);
    String llll = str(freq_array[63]);
    String com = ",";
    String newl = "\n";
    String send1 = sta + com + aa + com + bb + com + cc + com + dd + com + ee + com + ff + com + gg + com + hh + com + ii + com + jj + com + kk + com + ll + com + mm + com + nn + com + oo + com + pp + com + qq + com + rr + com + ss + com + tt + com + uu + com + vv + com + ww + com + xx + com + yy + com + zz + com + aaa + com + bbb + com + ccc + com + ddd + com + eee + com + fff + com + ggg + com + hhh + com + iii + com+ jjj + com + kkk + com + lll + com + mmm + com + nnn + com + ooo + com + ppp + com + qqq + com + rrr + com + sss + com + ttt + com + uuu + com + vvv + com + www + com + xxx + com + yyy + com + zzz + com + aaaa + com + bbbb + com + cccc + com + dddd + com + eeee + com + ffff + com + gggg + com + hhhh + com + iiii + com + jjjj + com + kkkk + com + llll + newl;
    port1.write(send1);
    port1.clear();
}

void stop()
{
  in.close();
  minim.stop();
  super.stop();
}


Continued below:

nitinarora

And the arduino side:

Code: [Select]
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>

int pinCS = 10;
int numberOfHorizontalDisplays = 8;
int numberOfVerticalDisplays = 2;
int amplitude[64] = {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};
boolean Cleared = true;
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

void setup() {

matrix.fillScreen(LOW);
matrix.write();
matrix.setIntensity(15);

matrix.setRotation(0, 1);  
matrix.setRotation(1, 1);    
matrix.setRotation(2, 1);    
matrix.setRotation(3, 1);    
matrix.setRotation(4, 1);    
matrix.setRotation(5, 1);    
matrix.setRotation(6, 1);    
matrix.setRotation(7, 1);  
matrix.setRotation(8, 1);    
matrix.setRotation(9, 1);
matrix.setRotation(10, 1);
matrix.setRotation(11, 1);
matrix.setRotation(12, 1);
matrix.setRotation(13, 1);
matrix.setRotation(14, 1);
matrix.setRotation(15, 1);
Serial.begin(115200);
delay(1000);
}

void loop() {
  
  if(Serial.read() == ('M')){
    for(int j=0; j<64; j++){
    amplitude[j]=Serial.parseInt();    
    }
   }  
  
  if(Serial.read()=='\n'){
    matrix.fillScreen(LOW);
    for (int x = 0; x<matrix.width(); x++){
       int temp = amplitude[x];
       matrix.drawLine(x, 16, x, 16 - temp, HIGH);
     }      
    matrix.write();
    for (int a = 0; a<64; a++){
      amplitude[a] = 0;
    }
   }
}


I understand that this can be improved by leaps and bounds but I was using this to prototype the system and have run into a problem. If I constraint the freq_height array values to a range of 0 - 8 by reducing the resolution, everything seems to work fine. Alternatively if I reduce the volume on the laptop thereby reducing the overall range of the values in the array things seem to work fine as well.

However as soon as I try to use the full resolution of 16 on max volume such that the freq_array has multiple double digit values the system simply hangs. I can see the last displayed frame on the matrix and that's it. I tried to use the BT module with SoftwareSerial (I do not have a Mega ATM) at a much lower baud rate and can see that the string reaches the Arduino. So I believe that I am parsing the string all wrong. I read through this:

https://forum.arduino.cc/index.php?topic=288234.0

but was unable to adapt the code to parse my incoming data (essentially M followed by 64 comma separated values ending in a new line). Although I can not understand why the above works with relatively small values in the freq_array.

I would really appreciate some help on this since I seem to have reached the end of my intellectual capacity.

Thanks
Nitin

Grumpy_Mike

#10
Aug 22, 2017, 10:19 am Last Edit: Aug 22, 2017, 10:20 am by Grumpy_Mike
Yes the code could be very greatly improved it is very turged.

The problem on the Arduino side is that if you read an M from the serial port you then assume that their are 64 values to read and they might not all have arrived.


On the processing side you are being very wasteful sending the data as strings and giving the Arduino a lot more to do in converting that string into an int value.

If you only send int values then you cut down one hell of a lot of work the system has to do. Note your Arduino serial buffer is only 64 bytes anyway.

nitinarora

Quote
Yes the code could be very greatly improved it is very turged.
Apologies for asking for help on such code but I am trying to get a proof of concept going and will optimize once I can get my head around this.

Quote
On the processing side you are being very wasteful sending the data as strings and giving the Arduino a lot more to do in converting that string into an int value.

If you only send int values then you cut down one hell of a lot of work the system has to do. Note your Arduino serial buffer is only 64 bytes anyway.
Super thanks for this. To get to think of it I need only a byte (?)/channel since I will send values from 0 - 16 only. So 64 bytes in all. Could you please let me know if this line of thought is correct? This would fit nicely within the 64 byte serial buffer?

Also on the processing side if I change the freq_array to byte, is there a way to send the byte array in a single go or would I need to run a loop to send the individual values?

As always much appreciate the help!!

Thanks
Nitin

Grumpy_Mike

Quote
Could you please let me know if this line of thought is correct? This would fit nicely within the 64 byte serial buffer?
Yes this is the right lines.

With processing you always need to run through a loop to send an array.

nitinarora

As an update to this, as suggested by Mike, I updated my Arduino code to the following:

Code: [Select]
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>

int pinCS = 10; // Attach CS to this pin, DIN to MOSI and CLK to SCK (cf http://arduino.cc/en/Reference/SPI )
int numberOfHorizontalDisplays = 8;
int numberOfVerticalDisplays = 2;

const byte numBytes = 64;
byte receivedBytes[numBytes] = {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};
boolean newData = false;

Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

void setup() {

matrix.fillScreen(LOW);
matrix.write();
matrix.setIntensity(1);

matrix.setRotation(0, 1);    // The first display is position upside down
matrix.setRotation(1, 1);   
matrix.setRotation(2, 1);   
matrix.setRotation(3, 1);   
matrix.setRotation(4, 1);   
matrix.setRotation(5, 1);   
matrix.setRotation(6, 1);   
matrix.setRotation(7, 1);   
matrix.setRotation(8, 1);   
matrix.setRotation(9, 1);
matrix.setRotation(10, 1);
matrix.setRotation(11, 1);
matrix.setRotation(12, 1);
matrix.setRotation(13, 1);
matrix.setRotation(14, 1);
matrix.setRotation(15, 1);   // The same hold for the last display
Serial.begin(19200);
delay(1000);
 }

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    byte rc;
 
 if (Serial.available() > 0) {
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedBytes[ndx] = rc;
                ndx++;
                /*if (ndx >= numBytes) {
                    ndx = numBytes - 1;
                }*/
            }
            else {
                //receivedBytes[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }
      else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
  }
}
void showNewData() {
    if (newData == true) {     
        matrix.fillScreen(LOW);
         //matrix.write();
        for (int b = 0; b<matrix.width(); b++){
         int temp = int (receivedBytes[b]);
         int temp1 = min(16, temp);
         matrix.drawLine(b, 16, b, 16 - temp, HIGH);
         }
         matrix.write();
         
         for (int a = 0; a<64; a++){
          receivedBytes[a] = 0;
          }
        newData = false;
   
    }
   
}

void loop() { // run over and over
    recvWithStartEndMarkers();
    showNewData(); 
  }


This is all thanks to:

https://forum.arduino.cc/index.php?topic=288234.0

nitinarora

In order to simply test the system I used a processing sketch:

Code: [Select]
import processing.serial.*;
import ddf.minim.analysis.*;
import ddf.minim.*;

Minim minim;
AudioInput in;
FFT fft;
int buffer_size = 4096;
float sample_rate = 200000;
int freq_width = 150;
int bands = 64;
Serial port1;
float[] spectrum = new float[bands];
byte []freq_array = {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};
float[] freq_height = {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};
char start = '<';
char end = '>';

void settings()
{
 size(512, 360);
}
void setup() {
  background(255);
  port1 = new Serial (this, "COM7", 19200);
}      

void draw() {
  background(255);
  
  for(int j=0; j<64; j++){    
  freq_array[j] = byte(random(0,17));
  }
 port1.write(start);
 port1.write(freq_array);
 port1.write(end);
}

void stop()
{
  in.close();
  minim.stop();
  super.stop();
}


Now, the original idea was to have this working wireless with an HC05 module. But to first validate the system I simply used an FTDI basic board to hook up the standalone arduino to the computer running the processing sketch.

The problem that I am currently facing is that this seems to work just fine at 19200 baud but the display is laggy (essentially out of sync with the music). If I use a higher baud, say 38400, the display simply hangs at random (the arduino side) even when running the above processing test sketch.

However, adding a small delay at the end of port1.write(end) (40ms was the minimum I could go to), the  system seems to work fine. While this solution somewhat works, I am wondering if someone could help me understand this behavior and if there is a way around this.

Thanks
Nitin

Go Up