Split screen marquee/scroll

The Dot Matrix Display (DMD) is a 32x16 array of high-brightness LEDs for visually striking effects. [Product Page]
Brissieboy
Posts: 179
Joined: Fri Sep 20, 2013 7:25 am

Split screen marquee/scroll

Post by Brissieboy » Wed Apr 30, 2014 4:58 am

Here is a little addition to the current DMD library (NOT THE DMD2 LIBRARY).

It enables a mixture of scrolling text and stationary text on the same display. It is a cut-down modified version of dmd.stepMarquee(). It only handles 'normal' horizontal, right to left, single step scrolling. It allow you to specify exactly what group of rows you want to scroll.
This is an additional function to add to the library so that no other library calls are impacted - fully backward compatible.

To use this, add the following function into the DMD.cpp file:

Code: Select all

//**************************************************************************************
// stepSplitMarquee(int topRow, int bottomRow)
// This is a cut-down modification of stepMarquee(). It steps only the rows specified.
// Only horizontal, single step, left scroll is catered for.
// This function allows you to have only a part of the DMD array scrolling, while the
// remainder stays still and is not cleared during scrolling.
//**************************************************************************************

boolean DMD::stepSplitMarquee(int topRow, int bottomRow)
{
  boolean ret=false;
  marqueeOffsetX += -1;  // only scroll horizontally, 1 place left
  if (marqueeOffsetX < -marqueeWidth) { // if text has scrolled off the screen
    marqueeOffsetX = DMD_PIXELS_ACROSS * DisplaysWide; // set up to scroll again from the far right
    drawFilledBox(0, topRow, DisplaysWide*DMD_PIXELS_ACROSS-1, bottomRow, GRAPHICS_INVERSE); // clear the scroll rows
    ret=true; // indicates that this scroll has completed
  }

// This is the main change from the original function.
// It splits the left shift task into rows and bytes within a row to allow rows to be identified
// and treated separately.
  for (int row=topRow ;row<=bottomRow; row++) { // loop for each row in the scroll area
    for (int byteInRow=0; byteInRow<DisplaysWide*4; byteInRow++) { // loop for each byte within a row (4 per DMD across)
      int thisIndex = (DisplaysTotal*4)*(row%16) + (4*DisplaysWide*(row/16)) + byteInRow; //calculate index into screen buffer
      if ((byteInRow%(DisplaysWide*4)) == (DisplaysWide*4) -1) {  // if it's the last byte in a row
        bDMDScreenRAM[thisIndex]=(bDMDScreenRAM[thisIndex]<<1)+1;
        // shift bits left, and puts a '1' in last position (a '1' = LED OFF)
    
      } else {                                            // if it's NOT the last byte in a row
        bDMDScreenRAM[thisIndex]=(bDMDScreenRAM[thisIndex]<<1) +
                    ((bDMDScreenRAM[thisIndex+1] & 0x80) >>7);
        // shift bits left as well as the shifting the MSB of the next byte into the LSB
      }
    }
  }
  // Redraw last char on screen
  // required because 
  int strWidth=marqueeOffsetX;
  for (byte i=0; i < marqueeLength; i++) {
    int wide = charWidth(marqueeText[i]);
    if (strWidth+wide >= DisplaysWide*DMD_PIXELS_ACROSS) {
      drawChar(strWidth, marqueeOffsetY,marqueeText[i],GRAPHICS_NORMAL);
      return ret;
    }
    strWidth += wide+1;
  }
  return ret;
}
and the following lines to the DMD.h file:

Code: Select all

  //Move the marquee left 1 place - special case of stepMarquee()
  // which only scrolls a limited portion of the display 
  boolean stepSplitMarquee(int topRow, int bottomRow);
just after the line "boolean stepMarquee( int amountX, int amountY);"

Here is a little demo sketch to demonstrate what it does and how to use it.

Code: Select all

/*
Test sketch for split screen scrolling
NOTE that this sketch uses the Freetronics version of the DMD library available here:
https://github.com/freetronics/DMD/
but with the additional dmd.stepSplitMarquee() function.

I also suggest that you make sure this has been changed DMD.cpp
change the line:
  SPI.setClockDivider(SPI_CLOCK_DIV128);
to:
  SPI.setClockDivider(SPI_CLOCK_DIV2);  // system clock / 2 = 8MHz SPI CLK to shift registers
This provides a marked improvement in the DMD update time within the interrupt routine.
*/

#include "SPI.h"        
#include "DMD.h"        
#include "TimerOne.h"
#include "SystemFont5x7.h"

#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1

DMD dmd( DISPLAYS_ACROSS , DISPLAYS_DOWN);

void ScanDMD()
{
  dmd.scanDisplayBySPI();
}

void setup()
{
  Timer1.initialize( 4000 );   // I find the default 5000 gives a visible flicker         
  Timer1.attachInterrupt( ScanDMD );  
  dmd.selectFont(SystemFont5x7);
  dmd.clearScreen( true );     // start with a blank screen
}

void loop()
{
  unsigned long time;
  int n;
  boolean ret = false;

  // Show some stationary text on the bottom half, and scrolling text on the top half
  // scrolls 3 times
  dmd.drawString(0,8,"Stays still",11,GRAPHICS_NORMAL); // the stationary string
  dmd.drawMarquee("Scrolling text",14,0,0); // set up the marquee
  time = millis();
  n=0;
  while(n<3) {
    while (!ret) {
      if ((time+30) < millis()) {
        ret = dmd.stepSplitMarquee(0,7); // parameters are the top & bottom rows to be scrolled
        time = millis();
      }
    }
    ret = false;
    n++;
  }
  dmd.clearScreen( true );

  // Now some stationary text on the top half, and scrolling text on the bottom half
  // scrolls for 10 seconds
  dmd.drawString(0,0,"Stays still",11,GRAPHICS_NORMAL); // stationary text
  dmd.drawMarquee("Scrolling text",14,0,8); // set up the marquee
  time = millis();
  while ((millis() - time)<10000){ // loop for 10 seconds
    dmd.stepSplitMarquee(8,15); // only scroll rows 8 to 15
    delay(30);
  } // a slightly different way to loop for stepping the marquee
    // note that this does not test for completion of the scroll, but continues until
    // the 10 second time has expired
  dmd.clearScreen( true );

  // Now a bit of fun
  dmd.drawString(0,-4,"vvvvvvvvvvv",11,GRAPHICS_NORMAL); // note the position is above a single DMD so
                                                         // only part of the text will be visible
  dmd.drawString(0,13,"^^^^^^^^^^^",11,GRAPHICS_NORMAL); // and this is too far down a single DMD so
                                                         // only part will be visible
  // these 2 lines above use partial characters displayed on the screen by placing the text at non-standard positions
  // to give a graphical highlight effect.
  dmd.drawMarquee("Scrolling text",14,0,5);
  time = millis();
  while ((millis() - time)<10000){ // again we will scroll for 10 seconds
    dmd.stepSplitMarquee(5,11); 
    delay(30);
  }
  dmd.clearScreen( true );
}
Of course you will need to exercise a bit of care with placement of text, the size of the text, and the rows you specify to step in the new function. I have added comments throughout to help explain what is going on.

I hope someone else finds a use for it.

UPDATE:
I updated the stepSplitMarquee() code above to allow for multi-dimensional DMD arrays. Original version only worked for single DMD high but multiple DMDs wide.

Brissieboy
Last edited by Brissieboy on Mon Jan 26, 2015 3:14 am, edited 1 time in total.

ariess128
Posts: 1
Joined: Fri Jan 23, 2015 9:32 am

Re: Split screen marquee/scroll

Post by ariess128 » Fri Jan 23, 2015 9:49 am

my led configure is:
#define DISPLAYS_ACROSS 3
#define DISPLAYS_DOWN 2

how to scroll Line-1 and Line 2 stay?

dmd.drawString(10,0,"1234567890",10,GRAPHICS_NORMAL);// stay TEXT line 1
dmd.drawMarquee(Text,Long_word,(32*DISPLAYS_ACROSS)-0,16); // Scroll text Line 2
timess=millis();
bool ret =false;

while (!ret)
{
wdt_reset();
if ((timess+100) < millis())
{
ret = dmd.stepSplitMarquee(16,32);
timess = millis();
wdt_reset();
}
}


i try this but not success, can hel me sir? thans..!

Brissieboy
Posts: 179
Joined: Fri Sep 20, 2013 7:25 am

Re: Split screen marquee/scroll

Post by Brissieboy » Sat Jan 24, 2015 2:07 am

ariess128
This split scroll was made for my own specific requirement at the time. It will only work properly with a single DMD in height, but multiple DMDs across. It ignores DISPLAYS_DOWN and just assumes it is 1. This was an oversight on my part, but it suited my needs. Sorry.

There is only a couple of lines where the work is done, and there are some comments that may help, so have a play around with the code.

If I get a chance I will try to have another look at it in the next week or so.

Brissieboy
Posts: 179
Joined: Fri Sep 20, 2013 7:25 am

Re: Split screen marquee/scroll

Post by Brissieboy » Mon Jan 26, 2015 3:17 am

ariess128
I have updated the code in the above message to handle multi-dimensional DMD arrays. I have only tested it with 2 DMDs as that is all I have available at the moment.

Try it with your array. It should now work.

Loki
Posts: 18
Joined: Mon Jul 06, 2015 7:12 pm

Re: Split screen marquee/scroll

Post by Loki » Thu Aug 18, 2016 5:41 pm

Hi I updated your code to start scroll from specific position:

DMD.cpp:

Code: Select all

boolean DMD::stepSplitMarquee(int topRow, int bottomRow,int StartColumn)
{
  boolean ret=false;
  marqueeOffsetX += -1;  // only scroll horizontally, 1 place left
  if (marqueeOffsetX-StartColumn < -marqueeWidth) { // if text has scrolled off the screen
    marqueeOffsetX = DMD_PIXELS_ACROSS * DisplaysWide; // set up to scroll again from the far right
    drawFilledBox(StartColumn, topRow, ((7*32-StartColumn)/32)*DMD_PIXELS_ACROSS-1, bottomRow, GRAPHICS_INVERSE); // clear the scroll rows
    ret=true; // indicates that this scroll has completed
  }

// This is the main change from the original function.
// It splits the left shift task into rows and bytes within a row to allow rows to be identified
// and treated separately.
  for (int row=topRow ;row<=bottomRow; row++) { // loop for each row in the scroll area
    for (int byteInRow=(StartColumn/8); byteInRow<DisplaysWide*4; byteInRow++) { // loop for each byte within a row (4 per DMD across)
      int thisIndex = (DisplaysTotal*4)*(row%16) + (4*DisplaysWide*(row/16)) + byteInRow; //calculate index into screen buffer
      if ((byteInRow%(DisplaysWide*4)) == (DisplaysWide*4) -1) {  // if it's the last byte in a row
        bDMDScreenRAM[thisIndex]=(bDMDScreenRAM[thisIndex]<<1)+1;
        // shift bits left, and puts a '1' in last position (a '1' = LED OFF)
   
      } else {                                            // if it's NOT the last byte in a row
        bDMDScreenRAM[thisIndex]=(bDMDScreenRAM[thisIndex]<<1) + 
                    ((bDMDScreenRAM[thisIndex+1] & 0x80) >>7);
        // shift bits left as well as the shifting the MSB of the next byte into the LSB
      }
    }
  }
  // Redraw last char on screen
  // required because
  int strWidth=marqueeOffsetX;
  for (byte i=0; i < marqueeLength; i++) {
    int wide = charWidth(marqueeText[i]);
    if (strWidth+wide >= DisplaysWide*DMD_PIXELS_ACROSS) {
      drawChar(strWidth, marqueeOffsetY,marqueeText[i],GRAPHICS_NORMAL);
      return ret;
    }
    strWidth += wide+1;
  }
  return ret;
}
DMD.h

Code: Select all

    //Move the marquee left 1 place - special case of stepMarquee()
  // which only scrolls a limited portion of the display
  boolean stepSplitMarquee(int topRow, int bottomRow,int StartColumn);
video: https://youtu.be/wRZnh1gXbrU

Thank you for your Code

arroba0611
Posts: 2
Joined: Fri Jan 25, 2019 2:13 pm

Re: Split screen marquee/scroll

Post by arroba0611 » Fri Jan 25, 2019 2:46 pm

Greetings and very interesting s the topics of this forum, I review the information in this post and modify the files DMD.h and DMD.cpp of the library and run the example code, everything compiled well, now the problem is that in the modules led is not displayed anything, I tried other example with the DMD library and the same problem does not see anything, To test the connections, I tried another example with the library DMD2 and if it works.

What I need to know is that it does not display anything with the DMD library because I need to use the functionality of: "stepSplitMarquee", this modification seems very useful to me.

Brissieboy
Posts: 179
Joined: Fri Sep 20, 2013 7:25 am

Re: Split screen marquee/scroll

Post by Brissieboy » Fri Jan 25, 2019 10:57 pm

Did you try your setup with the standard unmodified DMD library using some of the supplied examples? If that works, then there is a problem with the changes. If it still does not work there is probably a problem with your sketch or your hardware setup. Are you using a Uno?
If you are still having problems, maybe post your sketch.

arroba0611
Posts: 2
Joined: Fri Jan 25, 2019 2:13 pm

Re: Split screen marquee/scroll

Post by arroba0611 » Mon Jan 28, 2019 8:46 pm

Thank you for your reply, Fortunately everything works fine, I made the changes in the DMD.h and DMD.cpp libraries for "Split screen marquee / scroll" and I poor with the sample code: "Test sketch for split screen scrolling" and everything works fine.


According to this example what it does is to keep the fixed text that is below and the text in movement is up, or the opposite:
https://www.dropbox.com/s/23l8896fyc972 ... 0.JPG?dl=0



What I need is something different from this, I need that the fixed text is on the left and the text in movement on the right or the opposite:
https://www.dropbox.com/s/79v9q88iu46xg ... T.jpg?dl=0


Please your help to visualize the text in this way, I am not sure if it is necessary to change parameters or modify something additional the library ??

Brissieboy
Posts: 179
Joined: Fri Sep 20, 2013 7:25 am

Re: Split screen marquee/scroll

Post by Brissieboy » Mon Jan 28, 2019 10:41 pm

I think you can achieve what you are after by using the DMD2 library - have a play with that one. I have not done a lot with that so can't really help with that.
There is no mod to the DMD library that will do it for you as far as I am aware, but it would certainly be possible to do it.

UNO_ONU
Posts: 6
Joined: Sun Jul 14, 2019 4:17 am

Re: Split screen marquee/scroll

Post by UNO_ONU » Sun Jul 14, 2019 7:48 am

Hi there,
My first post here, and very new to Arduino also.
As a first project I've picked the DMD display to go with and so far so good, I've got it running a message and
can also input Serial via Bluetooth and an Android App. Something I found on hackster.io I think.
Though I'd like to add some changes, when I can work out what to do, that may be a while yet.

Anyway Brissieboy, VIC snowfieldsboy here, I've been reading many of your posts and Notes etc, well done !
I just tried to make the changes to the DMD library as suggested above but I must have a different Library.
I'm using DMD-Master, I have DMD2 also, and my IDE keeps telling me I have more than one DMD Library.
I included the DMD.cpp part but when it came to the DMD.h part, my DMD.h file has no word "boolean" in the file.
It seems there are quite a few variations of DMD library around. I think I have even more somewhere but not installed as yet.
So do I need yet another DMD Library for this to work ?

Cheers

Post Reply