How to change directions on MAX7219 DOT MATRIX

Hey guys, I'm really new to Arduino but I've been building a Spectrum Analyzer with Arduino Nano + MAX7219 dot matrix.
The problem that I'm having is that, instead of buying a 4 in 1 MAX7219 (8x32), I bought 4 (8x8) of them and combined into 1, but by doing that, the direction of the spectrum is wrong and I want to change that but I don't know how. Can someone help me? I can upload the code if someone wants to see it.

This first image is how my project is looking:
image

It's sideways, I need it normal.

We need to see the code. Read the forum guidelines to see how to properly post code and some good information on making a good post.
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.

What is supposed to be displayed?

// Modified code by Christian Suryanto, from (c) 2019 Shajeeb TM
// HAZI TECH
// Updated by Christian Suryanto
// 

#include <arduinoFFT.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <EEPROM.h>

#define HARDWARE_TYPE MD_MAX72XX::ICSTATION_HW                     // Set display type  so that  MD_MAX72xx library treets it properly
#define CLK_PIN   13                                          // Clock pin to communicate with display
#define DATA_PIN  11                                          // Data pin to communicate with display
#define CS_PIN    10                                          // Control pin to communicate with display

#define SAMPLES 64                                           // Must be a power of 2
#define MAX_DEVICES  4                                        // Total number display modules
#define  xres 32                                              // Total number of  columns in the display, must be <= SAMPLES/2
#define  yres 8                                               // Total number of  rows in the display

#define PREV 0xFF02FD // address is FFA25D but 0x is added because this is how the arduino is told that it is HEXADECIMAL.
#define NEXT 0xFFC23D // control stop code
#define PWR 0xFFA25D // control Power

int audio_response = 40;                                      // put a value between 10 and 80. Smaller the number, higher the audio response

double vReal[SAMPLES];
//double vReal2[SAMPLES];
double vImag[SAMPLES];
char data_avgs[xres];

int yvalue;
int displaycolumn , displayvalue;
int peaks[xres];
const int buttonPin = 6;                                      // the number of the pushbutton pin
int state = HIGH;                                             // the current reading from the input pin
int previousState = LOW;                                      // the previous reading from the input pin
int displaymode; 
unsigned long lastDebounceTime = 0;                           // the last time the output pin was toggled
unsigned long debounceDelay = 50;                             // the debounce time; increase if the output flickers

int MY_ARRAY[]={0, 128, 192, 224, 240, 248, 252, 254, 255};   // default = standard pattern
int MY_MODE_1[]={0, 128, 192, 224, 240, 248, 252, 254, 255};  // standard pattern
//int MY_MODE_2[]={0, 128, 64, 32, 16, 8, 4, 2, 1};             // only peak pattern
//int MY_MODE_3[]={0, 128, 192, 160, 144, 136, 132, 130, 129};  // only peak +  bottom point
//int MY_MODE_4[]={0, 128, 192, 160, 208, 232, 244, 250, 253};  // one gap in the top , 3rd light onwards

bool EQ_ON = true; // set to false to disable eq

byte eq1[32] = {40, 45, 50, 60, 65, 70, 75, 95,
               110, 110, 110, 110, 110, 110, 110, 110,
               130, 130, 130, 130, 130, 130, 130, 130,
               145, 155, 170, 180, 215, 220, 245, 255
              };


byte eq2[11] = {40, 70, 75, 110, 110, 140, 145, 220, 220, 230, 250};


MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);   // display object
arduinoFFT FFT = arduinoFFT();                                    // FFT object
 

void setup() {
    //EEPROM.update(1,1);                                           //(memory address, value), RUN THIS FOR THE FIRST TIME
    displaymode = EEPROM.read(1);
    //displaymode = 1;
    ADCSRA = 0b11100101;                                          // set ADC to free running mode and set pre-scalar to 32 (0xe5)
    ADMUX = 0b00000000;                                           // use pin A0 and external voltage reference
    pinMode(buttonPin, INPUT);
    mx.begin();                                                   // initialize display
    mx.control(MD_MAX72XX::INTENSITY, 0);                         // set LED intensity
    delay(50);                                                    // wait to get reference voltage stabilized
}
 
void loop() {
   // ++ Sampling

   int numData;
   double rSum;

   for(int i=0; i<SAMPLES; i++)
    {
      while(!(ADCSRA & 0x10));                                    // wait for ADC to complete current conversion ie ADIF bit set
      ADCSRA = 0b11110101 ;                                       // clear ADIF bit so that ADC can do next operation (0xf5)
      int value = ADC - 512 ;                                     // Read from ADC and subtract DC offset caused value
      value = value / 8;
      vReal[i]= value;                                          // Copy to bins after compressing
      vImag[i] = 0;                         
    }
    // -- Sampling

 
     //++ FFT
    FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
    FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
    // -- FFT

    int step = (SAMPLES)/xres; 

// re-mapping data - Customize by Christian Suryanto ///
    switch (displaymode)
    {
    case 1 :
      {
        numData = 32;
        data_avgs[0] = (vReal[0] + vReal[0])/2;
        data_avgs[1] = (vReal[1] + vReal[63])/2;
        data_avgs[2] = (vReal[2] + vReal[62])/2;
        data_avgs[3] = (vReal[3] + vReal[61])/2;
        data_avgs[4] = (vReal[4] + vReal[60])/2;
        data_avgs[5] = (vReal[5] + vReal[59])/2;
        data_avgs[6] = (vReal[6] + vReal[58])/2;
        data_avgs[7] = (vReal[7] + vReal[57])/2;
        data_avgs[8] = (vReal[8] + vReal[56])/2;
        data_avgs[9] = (vReal[9] + vReal[55])/2;
        data_avgs[10] = (vReal[10] + vReal[54])/2;
        data_avgs[11] = (vReal[11] + vReal[53])/2;
        data_avgs[12] = (vReal[12] + vReal[52])/2;
        data_avgs[13] = (vReal[13] + vReal[51])/2;
        data_avgs[14] = (vReal[14] + vReal[50])/2;
        data_avgs[15] = (vReal[15] + vReal[49])/2;
        data_avgs[16] = (vReal[16] + vReal[48])/2;
        data_avgs[17] = (vReal[17] + vReal[47])/2;
        data_avgs[18] = (vReal[18] + vReal[46])/2;
        data_avgs[19] = (vReal[19] + vReal[45])/2;
        data_avgs[20] = (vReal[20] + vReal[44])/2;
        data_avgs[21] = (vReal[21] + vReal[43])/2;
        data_avgs[22] = (vReal[22] + vReal[42])/2;
        data_avgs[23] = (vReal[23] + vReal[41])/2;
        data_avgs[24] = (vReal[24] + vReal[40])/2;
        data_avgs[25] = (vReal[25] + vReal[39])/2;
        data_avgs[26] = (vReal[26] + vReal[38])/2;
        data_avgs[27] = (vReal[27] + vReal[37])/2;
        data_avgs[28] = (vReal[28] + vReal[36])/2;
        data_avgs[29] = (vReal[29] + vReal[35])/2;
        data_avgs[30] = (vReal[30] + vReal[34])/2;
        data_avgs[31] = (vReal[31] + vReal[33])/2;
      }
      break;

    case 2 :
      {
        numData = 11;
        data_avgs[0] = (vReal[0] + vReal[0])/2;
        data_avgs[1] = (vReal[0] + vReal[0] + vReal[1] + vReal[63]) / 4;
        data_avgs[2] = ( vReal[1] + vReal[63] + vReal[2] + vReal[62] + vReal[3] + vReal[61])/6;
        data_avgs[3] = (vReal[2] + vReal[62] + vReal[3] + vReal[61] + vReal[4] + vReal[60])/6;
        data_avgs[4] = (vReal[5] + vReal[59] + vReal[6] + vReal[58] + vReal[7] + vReal[57])/6;
        data_avgs[5] = (vReal[8] + vReal[56] + vReal[9] + vReal[55] + vReal[10] + vReal[54] + vReal[11] + vReal[53])/8;
        data_avgs[6] = (vReal[12] + vReal[52] + vReal[13] + vReal[51] + vReal[14] + vReal[50] + vReal[15] + vReal[49])/8;
        data_avgs[7] = (vReal[16] + vReal[48] + vReal[17] + vReal[47] + vReal[18] + vReal[46])/6;
        data_avgs[8] = (vReal[19] + vReal[45] + vReal[20] + vReal[44] + vReal[21] + vReal[43] + vReal[22] + vReal[42])/8;
        data_avgs[9] = (vReal[23] + vReal[41] + vReal[24] + vReal[40] + vReal[25] + vReal[39] + vReal[26] + vReal[38] + vReal[27] + vReal[37])/10;
        data_avgs[10] = (vReal[28] + vReal[36] + vReal[29] + vReal[35] + vReal[30] + vReal[34] + vReal[31] + vReal[33])/8;
      }
      break;
    }
// re-mapping data - Customize by Christian Suryanto ///

    for(int i=0; i<numData; i++)
    {
      data_avgs[i] = data_avgs[i] / 2;
      if (EQ_ON)
        switch (displaymode)
        {
          case 1 : data_avgs[i] = (data_avgs[i]) * (float)(eq1[i]) / 100; //apply eq filter
          break;
          
          case 2 : data_avgs[i] = (data_avgs[i]) * (float)(eq2[i]) / 100; //apply eq filter
          break;
        }

      data_avgs[i] = constrain(data_avgs[i],0,audio_response);              // set max & min values for buckets
      data_avgs[i] = map(data_avgs[i], 0, audio_response, 0, yres);         // remap averaged values to yres
      
      yvalue=data_avgs[i];

      peaks[i] = peaks[i]-1;    // decay by one light
      if (yvalue > peaks[i]) 
          peaks[i] = yvalue ;
      yvalue = peaks[i];    
      displayvalue=MY_MODE_1[yvalue];
      
      switch (displaymode)
      {
        case 1: 
        {
          displaycolumn=31-i;
          mx.setColumn(displaycolumn, displayvalue);                // for left to right
        }
        break;
        case 2: 
        {
          displaycolumn=31-(3*i);
          mx.setColumn(displaycolumn-1, displayvalue);                // for left to right
          mx.setColumn(displaycolumn, displayvalue);                // for left to right
        }
        break;
      }
     }
     // -- send to display according measured value 
     
    displayModeChange ();                                       // check if button pressed to change display mode
}

void displayModeChange() {
  int reading = digitalRead(buttonPin);
  if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) // works only when pressed
  {
    switch (displaymode) 
     {
      case 1:    //       move from mode 1 to 2
        displaymode = 2;
        mx.clear();
        delay(200);
        EEPROM.update(1,2); 
        break;
      case 2:    //       move from mode 2 to 3
        displaymode = 1;
        mx.clear();
        delay(200);
        EEPROM.update(1,1); 
        break;
    }
    lastDebounceTime = millis();
  }
  previousState = reading;
}

This is the code!
And It's supposed to be displayed like that below, not sideways.

Did you get the display to work right using any of the MD_MAX72xx library example code?

Have you tried other hardware types.

It is required to rotate the image in each 8x8 matrix by 90 degrees by coordinate transformation in the code. Not too complicated task.
But first you need to know how it is displayed now, it’s hard to understand from your pictures. It would be nice if you can to light the pixel with coordinates x=7, y=7 and show the picture.

Ok, I'll try that

Yes, it all works, but everything shown in the display is rotated. Even scrolling text with parola library

Yes, but all they do is invert the image, not rotate.

I've found what I want in the MD_MAX72xx library, but its not working.

This is on the library, it has options to rotate the display.
image

void setup() {
    //EEPROM.update(1,1);                                           //(memory address, value), RUN THIS FOR THE FIRST TIME
    displaymode = EEPROM.read(1);
    //displaymode = 1;
    ADCSRA = 0b11100101;                                          // set ADC to free running mode and set pre-scalar to 32 (0xe5)
    ADMUX = 0b00000000;                                           // use pin A0 and external voltage reference
    pinMode(buttonPin, INPUT);
    mx.begin();                                                   // initialize display
    mx.transform(MD_MAX72XX::TRC);
    mx.control(MD_MAX72XX::INTENSITY, 0);                         // set LED intensity
    delay(50);                                                    // wait to get reference voltage stabilized
}

I added "mx.transform(MD_MAX72XX::TRC)" to the function but it does nothing to the display, it remains the same thing. Any ideas what could it be?

In which case it would help if you had the proper FC_16 modules instead of those old ones you are using:

Hopefully @marco_c will pop in and help. :grin:

1 Like
#define HARDWARE_TYPE MD_MAX72XX::ICSTATION_HW 

Your hardware type is wrong. You will need to change this #define to reflect your hardware. The modules you have are GENERIC type.

Please read the documentation for the MD_MAX72xx library or this blog post https://arduinoplusplus.wordpress.com/2017/04/14/parola-a-to-z-adapting-for-different-hardware/.

Yes, that got it working, and I've read the documentation as well, thanks a lot for the help!
I could've swore I tested all the hardware types, but apparently not.

image

I can't send videos, but it's working correclty now.

In case it is not obvious, Marco is the author of the software you are using. :grin:

1 Like

Oh, that's cool! :laughing:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.