[SOLVED] How to scroll data with multiple 8x8 LED matrix modules?

Go To Last Post
26 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

 

I'm trying to find a simple way to scroll data in multiple 8x8 LED matrix modules. So far I can scroll anything but it synchronized with the other modules.

 

I want to control the flow of the data as if I want; for example, to scroll a text so it should start from the first module moving to the last.

 

As in this YouTube video:

https://www.youtube.com/watch?v=e_pY-uGkDFA&t=17s

 

I downloaded the code provided in the link, but it's a set a libraries and the main class is really complicated and has a lot of functions. Of course, it would be very useful to understand all those libraries :)

 

Anyway, here's the code I developed to do the basic things and the most important is to scroll a text to any direction.

 

In `led_scroll()` I set the loop for 32 to see if I can provide a space between the start and the end of the scroll process.

 

void SPI_Init(void);
void SPI_TX_s16(uint16_t data);
void SPI_TX_m16(uint16_t data, uint8_t cnt);
void MAX7219_init(void);
void draw(void);
void led_scroll(void);
void clr(void);

uint8_t Alphabet[208]=
{
0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x7e, 0x0, //A
0x3e, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x3e, 0x0, //B
0x3c, 0x42, 0x2, 0x2, 0x2, 0x42, 0x3c, 0x0    ,//C
0x3e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x0, //D
0x7e, 0x2, 0x2, 0x7e, 0x2, 0x2, 0x7e, 0x0     ,//E
0x2, 0x2, 0x2, 0x3e, 0x2, 0x2, 0x7e, 0x0,      //F
0x3c, 0x42, 0x62, 0x2, 0x2, 0x42, 0x3c, 0x0,   //G
0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x0, //H
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0, //I
0x18, 0x24, 0x20, 0x20, 0x20, 0x20, 0x70, 0x0, //J
0x22, 0x12, 0xa, 0x6, 0xa, 0x12, 0x22, 0x0,    //K
0x7e, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0,       //L
0x41, 0x41, 0x41, 0x49, 0x55, 0x63, 0x41, 0x0, //M
0x41, 0x61, 0x51, 0x49, 0x45, 0x43, 0x41, 0x0, //N
0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x0, //O
0x2, 0x2, 0x2, 0x3e, 0x42, 0x42, 0x3e, 0x0,    //P
0xbc, 0x62, 0x52, 0x42, 0x42, 0x42, 0x3c, 0x0,//Q
0x62, 0x12, 0xa, 0x3e, 0x42, 0x42, 0x3c, 0x0,  //R
0x1c, 0x22, 0x4, 0x8, 0x10, 0x22, 0x1c, 0x0,   //S
0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x3e, 0x0,       //T
0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x0, //U
0x8, 0x14, 0x22, 0x41, 0x41, 0x41, 0x41, 0x0,  //V
0x63, 0x55, 0x49, 0x41, 0x41, 0x41, 0x41, 0x0, //W
0x41, 0x22, 0x14, 0x8, 0x14, 0x22, 0x41, 0x0,  //X
0x8, 0x8, 0x8, 0x8, 0x14, 0x22, 0x41, 0x0,     //Y
0x3e, 0x2, 0x4, 0x8, 0x10, 0x20, 0x3e, 0x0    //Z
 };

uint8_t s=0,i,l,k,row,col,data_buffer[64];
uint16_t data;

void setup() {
  SPI_Init();
  MAX7219_init();
 }

void loop() {
clr();
led_scroll();
_delay_ms(200);
}

/////////////////////////////////////////////////
            // SPI functions //
////////////////////////////////////////////////
void SPI_Init(void)
{
  DDRB |= (1<<DDB3)|(1<<DDB5)|(1<<DDB2); // DDB3 MOSI, DDB5 SCrow, DDB2 SS
  SPCR = (1<<SPE)|(1<<MSTR);  // SPI enable, Master Mode
}
void SPI_TX_s16(uint16_t data)
{
  PORTB &= ~(1<<PB2);
  SPDR = data>>8;
  while(!(SPSR & (1<<SPIF)));
  SPDR = data;
  while(!(SPSR & (1<<SPIF)));
  PORTB |= (1<<PB2);
}

// this function to send data to a specific LED module
void SPI_TX_m16(uint16_t data, uint8_t cnt)
{
  PORTB &= ~(1<<PB2);
  uint8_t i;
  for (i=0;i<4;i++)
  {
      if (i==cnt)
      {
          SPDR = data>>8;
          while(!(SPSR & (1<<SPIF)));
          SPDR = data;
          while(!(SPSR & (1<<SPIF)));
      }
      else
      {
          SPDR = 0x00>>8;
          while(!(SPSR & (1<<SPIF)));
          SPDR = data;
          while(!(SPSR & (1<<SPIF)));
      }
  }
  PORTB &= ~(1<<PB2);
  PORTB |= (1<<PB2);
}

/////////////////////////////////////////////////
            // MAX7219 functions //
////////////////////////////////////////////////

void MAX7219_init(void)
{
  SPI_TX_s16(0x0A00); // intensity
  SPI_TX_s16(0x0900); // decode mode
  SPI_TX_s16(0x0B07); // scan limit
  SPI_TX_s16(0x0F00);
  SPI_TX_m16(0x0C01,4); // shutdown on
}

void led_scroll(void)
{
    col=0;
    for (i=0;i<32;i++)
    {
        SPI_TX_s16(data = (1<<8) | (0x0f<<col++));
        _delay_ms(300);
    }
}

void clr(void)
{
    for (i=1;i<9;i++)
    SPI_TX_m16(data = i<<8 | (0x00),4);
}

 

This topic has a solution.

Last Edited: Sun. Apr 1, 2018 - 08:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

wolfrose wrote:
I can scroll anything but it synchronized with the other modules.  

I don't understand what you mean by that - why is it a problem?

 

What "modules" are you using?

 

Post a block diagram and/or schematic of your setup.

 

Instruction here: https://www.avrfreaks.net/comment...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I posted the problem on a YouTube video:

https://www.youtube.com/watch?v=inkpl3XPE6Y

Last Edited: Sun. Feb 18, 2018 - 08:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 3

Divide your problem into smaller ones-
Can you write data reliably to all of the modules?
If you can do this, then your problem is nothing to do with leds, modules, spi etc - the problem is how to arrange your data and present it correctly.
Sit down with a pencil and paper and draw your data structures. Then draw how you want the next step and so on. Formulate a set of operations that do what you require. Then write the code to perform these operations. It is just like moving bottles or boxes.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My current progress is I could move array buffer along the 4 modules which is nice, but my goal is to scroll any data bit by bit just like those nice projects on YouTube :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

We already understand what you want. Follow the process i outlined and you should be able to make progress. Or there are plenty of examples on the interwebs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm studying one of the examples written in C++, it's a nice not so complicated code.

 

I have a question about some parts of the code, here's one of them:

 

This is the constructor of the library in the .h file.

class MaxMatrix
{
  private:
    byte data;
    byte load;
    byte clock;
    byte num;
    byte buffer[8];

    void reload();

  public:
    MaxMatrix(byte data, byte load, byte clock, byte num);

    void init();
    void clear();
    void setCommand(byte command, byte value);
    void setIntensity(byte intensity);
    void setColumn(byte col, byte value);
    void setColumnAll(byte col, byte value);
    void setDot(byte col, byte row, byte value);
    void writeSprite(int x, int y, const byte* sprite);

    void shiftLeft(bool rotate = false, bool fill_zero = true);
    void shiftRight(bool rotate = false, bool fill_zero = true);
    void shiftUp(bool rotate = false);
    void shiftDown(bool rotate = false);
};

The author initialized buffer by 8 bytes.

 

but the question in this part of the .cpp file:

void MaxMatrix::clear()
{
	for (int i=0; i<8; i++)
		setColumnAll(i,0);

	for (int i=0; i<80; i++)
		buffer[i] = 0;
}

The second for loop, the index is going out of the original buffer size! Why is that? The indexing is 80, so it should go throw 80 bytes of the buffer, but the original size of the buffer is only 8 bytes.

 

 

Last Edited: Mon. Feb 19, 2018 - 11:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'd suggest it is a defect. Note you've given only a small  amount of information. If you'd given us the original link to the code we might be able to investigate further. As to why - ask the author.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

https://github.com/riyas-org/max7219

 

This is the link, I learned some techniques from this library, it's nice, written in C++. I just have to understand how he does the scroll and shifting of different directions.

 

Now, I reached to shift a complete byte to the matrix module, next I have to know how to shift it bit by bit, I can do that but the sequence of shifting doesn't go to the next module which is my main problem for now.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

wolfrose wrote:
This is the constructor of the library in the .h file.

class MaxMatrix
{
  private:
    byte data;
    byte load;
    byte clock;
    byte num;
    byte buffer[8];

    void reload();

...

 

The author initialized buffer by 8 bytes.

 

but the question in this part of the .cpp file:

void MaxMatrix::clear()
{
	for (int i=0; i<8; i++)
		setColumnAll(i,0);

	for (int i=0; i<80; i++)
		buffer[i] = 0;
}

The second for loop, the index is going out of the original buffer size! Why is that? The indexing is 80, so it should go throw 80 bytes of the buffer, but the original size of the buffer is only 8 bytes.

I would say that 80 accidentally got changed to 8 by you, this is what MaxMatrix.h actually has:

class MaxMatrix
{
  private:
    byte data;
    byte load;
    byte clock;
    byte num;
    byte buffer[80]; ...

 

 

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Tue. Feb 20, 2018 - 09:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, that’s five minutes of my life wasted chasing ghosts.
Wolfy- why do you make things so complicated for yourself? You’re too concerned with the code and haven’t considered the method.
Is this thread going to go the same way as your others where we sit in an irrational loop?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

larryvc wrote:
I would say that 80 accidentally got changed to 8 by you, this is what MaxMatrix.h actually has:

class MaxMatrix
{
  private:
    byte data;
    byte load;
    byte clock;
    byte num;
    byte buffer[80]; ...

 

 

 

You're right, so what's the reason of this size?

Last Edited: Thu. Feb 22, 2018 - 09:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
You’re too concerned with the code and haven’t considered the method.

+1

 

wolfrose wrote:
what's the reason ... ?

Again, you need to ask the author of the code that question!

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Well, that’s five minutes of my life wasted chasing ghosts. Wolfy- why do you make things so complicated for yourself? You’re too concerned with the code and haven’t considered the method. Is this thread going to go the same way as your others where we sit in an irrational loop?

 

I'm really concerned of the code, and for the last weeks I couldn't figure out how to scroll data along matrix modules, my loss is bigger than yours :)

 

I know I waste a lot of time and I don't know why it's very complicated to me? I wish I can finish this one so I can more on to wireless and Bluetooth modules, I'm really wasting my time where the problem is really easy and boys in high school can do it.

 

Such little problems block my progress in programming, i don't why small issues stop me for days and weeks, some took months. And all is in C, I didn't even move to C++, java or python. But I can't leave this and go for a different platform e.g. raspberry pie without mastering everything in C. When I think like this, I just remember my self that C is very important in embedded systems and it's not worth so much to go for other programming language.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Your problem is that you are trying to leap straight into writing code without first having a proper understanding of what that code needs to achieve!

 

Way back in #4, Kartman wrote:
Sit down with a pencil and paper and draw your data structures. Then draw how you want the next step and so on. Formulate a set of operations that do what you require. Then write the code to perform these operations. It is just like moving bottles or boxes.

Note that actually writing code is the last thing you do!

 

Design first - code last.

 

 

EDIT

 

Kartman wrote:
 draw your data structures.

Actually, don't even start with data structures - they come later in the design.

 

Start by drawing what needs to happen on the LEDs themselves.

 

Once you have that, then (and only then) start thinking about what data structure(s) might be appropriate to achieve the requirement.

 

And there's no need to draw the entire 4-module display - you should be able to get it from just 2 modules, and then extend that as required.

 

It will probably also be helpful to draw what is actually happening with your current code - that will help you to think about where it's going wrong ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Fri. Feb 23, 2018 - 10:51 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In #2, awneil wrote:
What "modules" are you using?

You never answered that.

 

Your function name suggests that https://www.maximintegrated.com/en/products/power/display-power-control/MAX7219.html is involved - but that's just the driver, and tells us nothing about how the LEDs are arranged.

 

Post a block diagram and/or schematic of your setup.

and you never did that.

 

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Your comments don’t make much sense. The problem is the same whether you use a raspberry pi or you use basic,python,algol 60,c++ or even C.
You’re concentrating on the wrong thing. As a professional, we’re taught a process to cope with complexity. Some people naturally use a process and most need to be taught. Look at a bricklayer laying bricks - does he just place bricks willy nilly or does he have a process that he follows that ensures his bricks are straight and vertical?

Last Edited: Fri. Feb 23, 2018 - 01:30 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Sit down with a pencil and paper and draw ...

If you really have an aversion to such old-school tools as pencil and paper, and feel compelled to use a keyboard and screen, the you could equally do this exercise in Excel:

 

https://www.avrfreaks.net/forum/spreadsheets-are-really-awesome-tools

 

I would have to admit that the ease of copy-and-paste on a computer does make things easier for repetitive patterns like this ...

 

 

Other spreadsheet programs are available.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

wolfrose wrote:
This is the constructor of the library in the .h file.
What you then quote after that is NOT the constructor - it's the class declaration ??

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
We already understand what you want. Follow the process i outlined and you should be able to make progress. Or there are plenty of examples on the interwebs.

 

Well, I've looked into different libraries. I learned some techniques so I got back to improve my function.

 

This is the best I could do for now:

 

This is what I'm working on, I know there are problems and I'm trying to fix them.

 

void draw(void)
{
    uint32_t map_buffer=0;                              // data buffer map to load data into it and then shift this register
                                                        // and copy the updated data to array bytes and load them to the displays
    int8_t i,k;
    uint8_t data_reg[4] = {0xff,0xff,0xff,0xff};        // random data to write
    uint8_t dis_buf[4];                                 // display buffers, when data in map_buffer is shifted, the result is copied in this array

    for (i=0;i<4;i++)
    map_buffer |= data_reg[i] << i*8;                   // loading data into map_buffer

    for (col=0;col<32;col++)                             // to shift the 32 columns of the 32-bit map_buffer
    {
        map_buffer >>= 1;                               // start shifting the data by 1 pixel
        for (i=0;i<4;i++)
        dis_buf[i] = map_buffer >> i*8;                 // loading shifted data into display buffers
        for (row=1;row<9;row++)                         // for 8 matrix rows
        {
            SPI_TX_m16(data = (row<<8) | (dis_buf),4);  // here is the problem I want to send the content of the 4-byte array
        }_delay_ms(1000);
    }
}

 

And thank you Mr Kartman, I did like what you told me and got out with interesting approaches :)

 

 

 

Last Edited: Sat. Feb 24, 2018 - 07:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry for the late answer, this is the same one I have with 4 modules.

Image result for led dot matrix 4 modules

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OMG I did it!

 

With this function:

void draw(void)
{
    uint32_t map_buffer=0;int8_t i,k;
    uint8_t data_reg[4] = {0xaa,0xbb,0xff,0xff};      // random data to write
    uint8_t dis_buf[4],no_device,no_col;s=0;l=3;

    for (i=0;i<4;i++)
    map_buffer |= data_reg[i] << i*8;                 // loading data into map_buffer

    for (col=0;col<32;col++)                          // for 8 matrix columns
    {
        map_buffer >>= 1;                            // start shifting the data by 1 pixel
        for (i=0;i<4;i++)
        dis_buf[i] = map_buffer >> i*8;              // loading shifted data into display buffers
        for (i=0;i<4;i++)
        {
            for (row=1;row<9;row++)                 // for 8 matrix rows
            {
                SPI_TX_m(data = (row<<8) | (dis_buf[i]),i);
            }
        }_delay_ms(1000);
    }
}

 

That's absolutely amazing :)

 

Thank you all!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I m trying to port your code to Mikroc AVR, but I  don't understand 1=3

uint8_t dis_buf[4],no_device,no_col;s=0;l=3;

Could you help me ?

 

Best regards.

 

Francis

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Errr, it’s actually a lowercase L. It looks like it isn’t even used.

Last Edited: Wed. Mar 27, 2019 - 09:03 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

Thank you I thought the same.

 

Best regards

 

Francis

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Apart from i,j,k (and maybe x,y,z ?) as commonly used loop iterators I'd steer clear of single letter variable names.