Pages: [1] 2   Go Down
Author Topic: Scrolling matrix display  (Read 3196 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
God Member
*****
Karma: 2
Posts: 854
Arduino rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm working on making a scrolling LED matrix display.  I'm storing a 1-bit bitmap of the entire display content that's being scrolled in ram and then using a moving pointer to update the display with a portion of the ram area.  It my own idea, but I don't know if I'm reinventing the wheel or there's a better way to do it.  It's working beautifully; the problem is that I'm burning way too much ram with this technique.  A 100-character message will use 600 bytes of ram with my 5x7 font, which seems excessive when the MCU only has 1 or 2k.

What do people normally do to implement a scrolling display?

Logged

Gosport, UK
Offline Offline
Faraday Member
**
Karma: 21
Posts: 3113
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

They keep the message data in the flash memory area, rather than in SRAM. See http://arduino.cc/en/Reference/PROGMEM
Logged

0
Offline Offline
God Member
*****
Karma: 2
Posts: 854
Arduino rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

They keep the message data in the flash memory area, rather than in SRAM. See http://arduino.cc/en/Reference/PROGMEM

I'm using program memory to store font and symbols, but for the actual message, I'm dynamically building it at run time.
Logged

Yorkshire England
Offline Offline
Sr. Member
****
Karma: 2
Posts: 267
Arduino good init
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You must have some kind of array that represents the led matrix? this is 8x8? so at any one time you only need to read the sizeof matrix from PROGMEM.
Logged

Show Your Work
Offline Offline
Edison Member
*
Karma: 14
Posts: 1095
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm working on making a scrolling LED matrix display.  I'm storing a 1-bit bitmap of the entire display content that's being scrolled in ram and then using a moving pointer to update the display with a portion of the ram area.  It my own idea, but I don't know if I'm reinventing the wheel or there's a better way to do it.  It's working beautifully; the problem is that I'm burning way too much ram with this technique.  A 100-character message will use 600 bytes of ram with my 5x7 font, which seems excessive when the MCU only has 1 or 2k.

What do people normally do to implement a scrolling display?

You are taking your message which is in RAM and decoding it with the font which is in flash to precreate a bitmap which is necessarily large, in RAM.

Why?

I have a scroller and I do basically what you do but there is no problem decoding the text via the font on the fly with no need to store the bitmap anywhere except in the driver/shift registers.  The Arduino is fast enough for that, at least it was for me with 6 8x8 displays.

http://arduino.cc/forum/index.php?action=dlattach;topic=115559.0;attach=26003





« Last Edit: September 22, 2012, 11:26:31 pm by JoeN » Logged

I have only come here seeking knowledge. Things they would not teach me of in college.

0
Offline Offline
God Member
*****
Karma: 2
Posts: 854
Arduino rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have a scroller and I do basically what you do but there is no problem decoding the text via the font on the fly with no need to store the bitmap anywhere except in the driver/shift registers.  The Arduino is fast enough for that, at least it was for me with 6 8x8 displays.

Very nice looking display.  That's what I'm working on, currently I have one 8x8 matrix on breadboard wired as you described and I just ordered some PCBs for 7219 backpacks to build a row of modules, exactly what you have but I haven't decided how many modules I'll use yet.

Is your actual display as choppy as the video?  I thought about decoding the font on the fly but figured it would make the timing more difficult and just feel kludgy in code.  Are you using a blocking delay or using millis() to make sure the time interval between updating the display is constant?  Being more careful with the time between updates could make your scroll more smoothly.

Right now, my code is incredibly simple, I don't even need to read all the symbols from the font.  For a time display when I want a colon, I just set 2 columns to 0x24, and to make the colon blink seamlessly as it scrolls, I can blank and reset those 2 columns every second.  Replicating that functionality without the buffered bitmap would be difficult.  Same goes for any scrolling animations.

Anyway, thanks for your reply, I guess you've given me the right answer, which is to work out the more complicated code.  Either that or upgrade my mega168 to a 328 and limit my messages to 150 characters or so smiley.


Edit:  I didn't notice you posted code at first, I just read through it, it's not quite as difficult as I thought, so I really should spend some time trying to do it that way (at least if I don't want animations).   I'm a bit confused by your triple loop, is it because your font is storing columns but you're updating the displays as rows so you're twisting around bits?

Is the delay(10) after the for i loop the only time keeping?  If so, is it scrolling as fast as it's able right now?
« Last Edit: August 30, 2012, 04:11:06 pm by Oracle » Logged

Show Your Work
Offline Offline
Edison Member
*
Karma: 14
Posts: 1095
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It is choppy and I was not able to determine why exactly.  The delay is to slow it down, it's not timekeeping.  At first I thought the problem was that the amount of time through the loop was variable so I got the time at the start of the loop using the micros() function call and delayed the end of the loop variably as 10000 micros - the number of microseconds spent in the loop to make sure the time for every loop iteration was constant (10ms).  However, that did nothing at all to fix the problem nor did some other stuff I tried before I benched it for the time being.  Still not sure if it is the way I am using the MAX chips or what, but it doesn't seem to be because of variable execution time.  The fact is, those bitwise operations are very fast and execute in constant time so I don't think that is part of the problem at all.  All the other stuff is integer looping and comparison, these should all get translated to one clock instructions.  Maybe it is in the driver library, or maybe it wasn't really designed for scrolling.  I am not sure yet.

I just wanted to demonstrate that you can use bitmap operations to figure out "what bit you are on" when displaying text from a bitmapped font rather than blowing it up into a huge array in advance.
Logged

I have only come here seeking knowledge. Things they would not teach me of in college.

Show Your Work
Offline Offline
Edison Member
*
Karma: 14
Posts: 1095
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As far as the loops.  You can see the data is being sent to the MAX chips using the MAX library here:

lc.setRow(i, j, outputbyte);

So the outer loop i determines the display, it runs 0 to 5.  (the comment says "loop through our 8 displays" this is wrong)

The center loop j determine which row we are on, it runs 0 to 7.  The MAX library sets a row at a time with a bitmapped byte.

The inner loop k sets up that byte so it too runs from 0 to 7.  It copies bits from the font map for the current character into the output byte that will be sent to the MAX chip.  It also does work to determine when we have advanced past the current character using the font length array or have advanced past the end of the message itself.

Too bad the MAX chips can't be used as "dumb" shift registers.  You could just send a new column of data and let the last one fall off the most significant end of the register.  Instead you are sending the whole damn dataset every time you want to advance the display a column.


« Last Edit: August 30, 2012, 04:44:50 pm by JoeN » Logged

I have only come here seeking knowledge. Things they would not teach me of in college.

Norfolk UK
Offline Offline
Faraday Member
**
Karma: 67
Posts: 2514
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have attached some test code I used to perfect monochrome scrolling and the use of PROGMEM. The output routine is currently configured for testing on the Rainbowduino but was intended for MAX7219 chips. The final code went into a 16x8 MAX7219 driven matrix and would support 24x8 as it stands and *maybe 56x8 with minimal modification. *I say maybe because I'm not sure how fast it would scroll.

* ScrollTest3.ino (13.81 KB - downloaded 41 times.)
Logged

There is no such thing as a stupid question but there are a lot of inquisitive idiots.

Monterey CA
Offline Offline
Sr. Member
****
Karma: 1
Posts: 323
Addicted to Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I am using JoeN's code for scrolling text and I was wondering if you ever fixed the choppiness?  I was also wondering if there was a way using your code to display text that is short enough to display without scrolling?

I am little confused how your loops only which char is which in the array.

I am able to send text from the serial port and display it using your code. Thank you for posting it.

I am using a 24x8.)

Thanks.
Logged

Current Projects:                    Arduinos:
Security Robot Tank               Uno
Security Robot II 4WD            Mega2560

http://mobilewill.blogspot.com

Monterey CA
Offline Offline
Sr. Member
****
Karma: 1
Posts: 323
Addicted to Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I sort of got it to work. I created a new function that doesn't loop and resets the counters. Still can't get it to finish cleanly. What is a good way for it to stop when all the characters are displayed? Here is what I have.

Code:
void staticDisplay()
{
  
curcharix = 0;
curcharbit = 0;
curcharixsave = 0;
curcharbitsave = 0;
curcharixsave2 = 0;
curcharbitsave2 = 0;

clearDisplay();
  

  
    for (i=devCount-1;i>=0;i--) // Loop through our 8 displays
    {
      for (j=0;j<8;j++) // Set up rows on current  display
      {      
        byte outputbyte = 0;
  
        curchar = msg[curcharix];
  
        curcharixsave = curcharix;
        curcharbitsave = curcharbit;
      
        for (k=7;k>=0;k--) // Copy over data for 8 columns to current row and send it to current display
        {
          // This byte is the bitmap of the current character for the current row
          byte currentcharbits = Font8x5[((curchar-32)*8)+j];
      
          if (currentcharbits & (1<<curcharbit))
            outputbyte |= (1<<k);
      
          // advance the current character bit of current character
      
          curcharbit ++;
      
          if (curcharbit > lentbl_S[curchar-32]) // we are past the end of this character, so advance.
          {
            curcharbit = 0;
            curcharix += 1;
            if (curcharix+1 > msgsize) curcharix=0; //This is what I was playing with.
            curchar = msg[curcharix];
          }
        }
      
        lc.setRow(i, j, outputbyte);
        
    

        if (j != 7) // if this is not the last row, roll back advancement, if it is, leave the counters advanced.
        {
          curcharix = curcharixsave;
          curcharbit = curcharbitsave;
        }

      }
    }

  

  
}


Logged

Current Projects:                    Arduinos:
Security Robot Tank               Uno
Security Robot II 4WD            Mega2560

http://mobilewill.blogspot.com

Monterey CA
Offline Offline
Sr. Member
****
Karma: 1
Posts: 323
Addicted to Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I got it to work. Here it is in case anyone needs it

Code:
void staticDisplay()
{
  
curcharix = 0;
curcharbit = 0;
curcharixsave = 0;
curcharbitsave = 0;
curcharixsave2 = 0;
curcharbitsave2 = 0;

clearDisplay();
  
bool endFlag = false;
  
    for (i=devCount-1;i>=0;i--) // Loop through our X displays
    {
      for (j=0;j<8;j++) // Set up rows on current  display
      {      
        byte outputbyte = 0;
  
        curchar = msg[curcharix];
  
        curcharixsave = curcharix;
        curcharbitsave = curcharbit;
      
        for (k=7;k>=0;k--) // Copy over data for 8 columns to current row and send it to current display
        {
          // This byte is the bitmap of the current character for the current row
          byte currentcharbits = Font8x5[((curchar-32)*8)+j];
      
          if (currentcharbits & (1<<curcharbit))
            outputbyte |= (1<<k);
      
          // advance the current character bit of current character
      
          curcharbit ++;
      
          if (curcharbit > lentbl_S[curchar-32]) // we are past the end of this character, so advance.
          {
            curcharbit = 0;
            curcharix += 1;
            if (curcharix+1 > msgsize) k=-1; //This end the current display
            curchar = msg[curcharix];
            
          }
        }
      
        lc.setRow(i, j, outputbyte);
        
       if (endFlag) return;

        if (j != 7) // if this is not the last row, roll back advancement, if it is, leave the counters advanced.
        {
          curcharix = curcharixsave;
          curcharbit = curcharbitsave;
          if (curcharix+1 > msgsize) endFlag=true; //sets that we are done and exit after the next iteration
        }

      }
    }

  

  
}
Logged

Current Projects:                    Arduinos:
Security Robot Tank               Uno
Security Robot II 4WD            Mega2560

http://mobilewill.blogspot.com

Show Your Work
Offline Offline
Edison Member
*
Karma: 14
Posts: 1095
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I just noticed this message was back up on the list.  Over the weekend, I soldered up this project on a pad per hole veroboard with a standalone ATMega328P replacing the Arduino on the board itself.  I also increased the number of displays and 7219s to 8.  I am going to rework the software soon to try to get rid of that scrolling choppiness bug.   I think I may have to bypass the MAX7219 library and bitbang the chips myself.   Hopefully I can figure it out.  Glad you got it to work for you.
« Last Edit: September 17, 2012, 02:25:59 pm by JoeN » Logged

I have only come here seeking knowledge. Things they would not teach me of in college.

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 534
Posts: 26969
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

" I think I may have to bypass the MAX7219 library and bitbang the chips myself."
I would suggest using SPI.transfer() to send data to the MAX7129's. That will help your speed a lot.
Send out 64 bytes as one burst at whatever rate you update the display, with all devices daisy chained:
Code:
digitalWrite(SS_pins, LOW)
for (x=0; x<64; x=x+1){
SPI.transfer(displayArray[x]);
}
digitalWrite(SS_pins, HIGH);

speed it up more by using direct port manipulation to set & clear SS_pins:
Code:
PORTB = PORTB & B11111110; //clear bit 0
PORTB + PORTB | B00000001;  // set bit 0
make it really fast by skipping the for:next looping and just use 64 SPI.tranfers in a row
Code:
void loop(){
currentMillis = millis();
if ( (currentMillis - previousMillis) >=2){ // 2mS elapsed?
// The following will be quick - (1/16,000,000 * 64 bytes * 8 bits/byte)* 10? for reading the array = 0.3mS ??
previousMillis = previousMillis+2;
PORTB = PORTB & B11111110; //clear bit 0, use whatever port/bit you have - such as the SS/D10 pin
SPI.transfer(displayArray[0]);
SPI.transfer(displayArray[1]);
SPI.transfer(displayArray[2]);
:
:
SPI.transfer(displayArray[61]);
SPI.transfer(displayArray[62]);
SPI.transfer(displayArray[63]);
PORTB + PORTB | B00000001;  // set bit 0
}
//update your array however you're going to
}
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Show Your Work
Offline Offline
Edison Member
*
Karma: 14
Posts: 1095
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am saving on memory by having no display buffer at all.  The code generates the bits from the display message, display font, and current position every time it sends data to the MAX7219 chips, which is every time it scrolls a column over.  But all of that interface code I can use, thank you.
Logged

I have only come here seeking knowledge. Things they would not teach me of in college.

Pages: [1] 2   Go Up
Jump to: