SparkFun Large RGB 8x8 LED Matrix & Controller - scrolling issue
I have a couple of these SparkFun RGB LED Matrix & Controllers (actually I got my second one in today):
http://www.sparkfun.com/commerce/product_info.php?products_id=760
I have some code working that can display characters on them and finally got the routine to scroll them right to left across an 8x8 LED module (haven't tried 2 of them yet).
My code works for scrolling but it requires that the DATA statements·for each character·be back to back. However, without going into the advanced (yet) routine as used in JonnyMac's Badge.sxb and the RoboGames badge...I am looking for another coding technique perhaps as a·LOOKUP table for easier setup. I have seen this done for the BS2 but can't get it right for SX/B.
Attached is my current working code.
Post Edited (T&E Engineer) : 10/23/2007 11:53:25 AM GMT
http://www.sparkfun.com/commerce/product_info.php?products_id=760
I have some code working that can display characters on them and finally got the routine to scroll them right to left across an 8x8 LED module (haven't tried 2 of them yet).
My code works for scrolling but it requires that the DATA statements·for each character·be back to back. However, without going into the advanced (yet) routine as used in JonnyMac's Badge.sxb and the RoboGames badge...I am looking for another coding technique perhaps as a·LOOKUP table for easier setup. I have seen this done for the BS2 but can't get it right for SX/B.
Attached is my current working code.
Post Edited (T&E Engineer) : 10/23/2007 11:53:25 AM GMT
Comments
pattern VAR Byte(65)
Keep in mind that I am using SX Beta software because the SX-28 can only have arrays up to 16 bytes. However, when I make the array larger to accommodate both displays (requireing 64 bytes each) then I quickly run out of RAM space.
pattern VAR Byte(129)
Any ideas on another way to connect (2) 64 byte SPI LED display devices?
Here is what works for 1 SPI LED matrix:
Post Edited (T&E Engineer) : 10/24/2007 12:46:24 PM GMT
That said, I would really urge you to set up an ASCII mapped character set, then feed strings to the character mapper. It will greatly simplify your code for messages. I think we've discussed this? So instead of sending hard-coded bitmaps of the characters in the order of the message, you can send character strings to a function that looks up the correct map for the character and sends it.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
Post Edited (Zoot) : 10/24/2007 5:49:51 PM GMT
On another note, to get the ascii characters to be read in from a data statement, JonnyMac has·written a routine for·the RoboGames badge for·scrolling 5x7 characters (not in my case 8x8). But I would still be happy to use 5x7 characters but the display needs to see 64 bytes·shifted in not 35 bytes. So I modified it a little and will also try this out tonight:
This way it continues loading in 5x7 ascii characters until it reaches 64 bytes and then it dumps it to the display. I don't know if this will work or not but it makes sense at the moment. I will let you all know. If it does work then I should be able to simply change the 65 to a 128 (if your original method for 2 displays works for me as well). Thanks!
·
' tmpW3 = tmpB1 * 5 ' calc character offset
would be
tmpW3 = tmpB1 * 8 ' calc character offset
because you want 8 bytes per character. Then instead of reading and counting BITS like in your original program, just grab the bytes and shift each byte one a time... remember your main dumping "loop" is counting CHARACTERS... this is pseudo code just to illustrate the flow:
Now, keep in mind the above dumps the entire 8 chars to display WITHOUT holding them in memory (which I don't think you'll be able to do). The SXB RoboBadge code DOES hold the display in a buffer, but it's much smaller.
The above could be set to "scroll" by changing the start and end chars of the main loop and one more outside loop:
EDIT -- p.s., I forgot about firstin/firstout -- pseudo code above changed to loop through chars and bytes backwards. Also the above does not include checking for "end of string" and such, or error checking for non-ascii characters, but hopefully it helps in breaking down the flow of things?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
Post Edited (Zoot) : 10/24/2007 7:56:26 PM GMT
It appears that this display does scroll across 2 SPI LED·displays BUT acts strangely when sending more than 64 bytes to the 2 SPI LED displays. I have attached the documentation but it looks straight forward to what I have done and what you stated below seems ok but it is not. If I connect the 2 LED SPI displays with DataOut of the first going to DataIn of the second (and paralleled Clock and ChipSel signals), I get a "ghosted" image of the character breifly on the other 1st display when the data is being shifted onto the 2nd display. I haven't been able to find away to clear this. Ideas?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
This is what is running:
The ghosting problem happens whether I have 1·OR 2 SPI LED displays when you change the DO WHILE tmpB3 < 64 to anything higher (in this case 127 or 128, etc.)
DO WHILE tmpB3 < 127
I do see strange results for anything over 65 or so. I think this is because of the 64 byte buffer in the controller that the documentation (attachment) indicates. If this is the case, why have DataOut?
I also had some problems following your previous posting. In particular:
·How do I find out the data address? Isn't this CharMaps: ? or Ascii_Set:·?
If so then why do you reference CharMaps later?
You can't have a complex line in SX/B like this.
Please explain a little bit more.
Also was I supposed to use this within the SCROLL_LF routine as I previously posted OR is this it's own routine in place of it?
Is there anyway to do 5x7 characters instead of 8x8 (as I would rather use a dataset already made). If not ok, but just asking.
Sorry for all the questions. I just want to understand this clearly.
Thanks so much!
Post Edited (T&E Engineer) : 10/25/2007 12:27:39 AM GMT
How do I find out the data address? Isn't this CharMaps: ? or Ascii_Set: ?
-- it would be something like
Msg1:
DATA "T and E is so great!"
If so then why do you reference CharMaps later?
READ --> from (charMaps+char)*8 into tmpByte2
You can't have a complex line in SX/B like this.
-- that's why I called it pseudo code. Actually, there's an error there -- should be charMaps+(char*8) -- but regardless... what you are doing is reading the first byte from Msg1 -- which is "T" -- that's really a number -- the ASCII number. Presuming your charMaps are ordered like the ASCII chart, you can use the number that *is* "T" to get a data address (offsetting for non-alphanumeric chars if you like, and multiplying by data block size).
In SXB (though I would do this part in ASM -- way way faster to access "arrays" in ASM then SXB) would be something like:
pntr = char * 8 'set pointer to ASCII # of "char" * 8 (for the byte size of each map)
pntr = pntr - "0" 'offset to start of alphanum chars -- note quotes -- this make it the "number" that represents the char "0"
pntr = pntr+charMaps 'add to address of start of charMaps
'--> start reading 8 bytes from pointer
I'll have a chance to look at your program a little later tonight in detail.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
That said, this does NOT do scrolling per se, it just prints characters to the display from text string message. See comments in code regarding why only last two chars of any message will "print". I'll leave it for you to do "sliding window" work -- basically you would wrap my DISPLAY_MSG function in new code that chooses the start and end characters of the string, so instead of dumping characters from the string till "0" is reached, you would, say, start with character 0 and print character 0 and character 1 (two character display), pause, then print characters 1 and 2, etc. till "0" is reached.
The biggest difference in my little piece of code is that nothing is held in buffers -- the characters are dumped straight through. If you do sliding window, this will save you a lot of work.
That said, for cool scrolling (one column at time, for example) you would either need to redo the code so that columns are dumped (I think this will be very tricky since your drivers want pixels L to R, T to
Last but not least, I wasn't thinking straight earlier -- to avoid the whole FIRST IN, FIRST OUT conundrum with characters, if you are using my code, put the LAST display (right most char) on the D line from the Stamp, and put the DOUT from that display to the DIN of the LEFT char. In other words, cascade them in reverse -- if the "first" 8x8 backpack on your display is actually wired "last" in the cascade, then when you dump the FIRST character out, it will end up at that driver.
I sure hope this is helpful. I also can't encourage you enough to buckle down and create your bitmap ASCII art -- I did some characters (see my notes in the code) but remember you need 8 bytes of binary info for each char (not 64 bytes as in your char maps).
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
I will look at it tonight to try and understand what is being done.
Thanks again for your efforts and time!
I'll probably have some questions later on your code.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
So the first Msg1 has red for a color and I see some lines being drawn but just wrong display for what should be A B C.
How about using JonnyMac's BIT routine too (if needed):
·This helped when converting your BS2 DoChar routine for use on the SX/B.
See attached program using these. It uses a 4x4 keypad and lets the user hit the button to display 1-9,0,A-F on the display and it works well.
Remember on the ABC message, you should just see " C" because my routine dumps chars till 0 is reached -- with two chars in the display you would see the RIGHT two most characters. Maybe just try a message with "AB".
The bit buffer routines in the RoboBadge are good, but make sure you are getting good dumps of bitmaps first -- then you can take things up a level by dumping the char maps into the bit buffer rather than straight to display. Work in pieces.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
Thanks again.· However seeing those lines are not a good indication that the letter's are coming out correct. I will post my findings tonight after work.
I can still marquee scroll across from right to left on 1 SPI LED display. The problem is when I connect 2 displays which requires the "DO WHILE tmpB3 < 64" to get set to a higher value like 128. This is when the "ghost" imaging appears offset from the correct scrolling. So I am saying that I can scroll correctly across 2 displays with "DO WHILE tmpB3 < 128" - BUT I also get the "ghost" imaging of the same scrolling faintly offset in the background making the regular scrolling unusable across 2 displays.
I spent many hours on this and other programs in modification and got nowheres. Where can I step back to begin again?
You last program shows just some red lines. I did modify the inner section for JonnyMac's BITVAL routine which then shows alot of fast scrambling pixel data on the display when it finally lands on what looks like "(" (or the 10th character down).· I was thinking there was something not right with the mulitplying times 8 of tmpW3. I'm really lost with all this and previous coding to go through.
- you've got to be able to read text strings with one routine (e.g. DATA "I am cool.", 0) one byte at a time
- once you've got the char byte, read an ascii map with each char as 8 bytes, not 64 bytes as you have in your hand-pixellated messages. Using a byte for each pixel is very inefficient and will chew up all the space is in your SX.
- now that you've got the char, apply it to your buffer (128bits or 16 bytes) one column at a time (this is how the RoboBadge SXB code work -- the buffer is shifted and the next column added). I think you will have some work to do here because you have a larger bitmap -- when one bit is shifted off the left of one byte you need to carry that bit over to the next byte. If I had to guess, this is where the ghosting is coming from -- the column is not being carried over properly
So, following the RoboBadge example, I would create all your ASCII characters (starting with #32) as 8 bytes per character, in columns (i.e., turned sideways). You can even leave most of them blank and just do your first messages with the characters' you've drawn.
Then make sure you can add a single char to the buffer, dump the buffer, see the character. THEN start manipulating the buffer for scrolling.
I think what may be throwing is you the bitmap -- leaving color aside for now -- remember that in a bitmap a 1 means "turn pixel on" and 0 means "off". Your goal here is to NOT turn that single bit (which takes up little space) into a BYTE (with color added) until the moment you shiftout. You want to keep as little as possible in memory. E.g.
[noparse][[/noparse]code]
dispBuffer VAR Byte(16)· '128 bits display buffer
FOR row = 0 TO·15 'loop through BYTES of buffer -- you can't access bits as array
·· pixelMask = %1000_0000 'initialize mask for this row
·· FOR pixel = 0 TO 7 'loop through each byte in this row
····· tmp = dispBuffer(row)
····· tmp = tmp &·pixelMask ·'mask off each bit in turn for this row
····· IF tmp > 0 THEN· 'if the bit in this position is 1, then it's a pixel
············ tmp = 1 + color 'NOW you make it·a byte with the color
······ENDIF ' else it's off and is already 0····
····· SHIFTOUT tmp 'etc.... send to display
·· NEXT
NEXT
[noparse][[/noparse]/code]
Here's the thing you need to think about -- in the above the first pixel to be sent from the buffer would be at the TOP RIGHT of the buffer if you were reading it -- bit0 in row0, and what you really want to send first is the TOP LEFT pixel, which would be BIT7 of ROW8 (the second column, left most bit). So the rub is deciding how to orient your bitmap buffer and the bitmaps in data to begin with. You could consider the display buffer columns, and scan the bits from 7 TO 0 which might work better for you. Going through the buffer as columns to your displays will be tricky though.
Remember the above ONLY takes an existing "image" of the display in BITS (pixels on/off) and dumps it. The second part of all this is adding/changing/manipulating that buffer image so that you get the effects you want (new characters, scrolling). The code from the robo badge· does this here, but you would not OUTPUT it here, you would do that with a routine similar to above.
This code is meant to grab just ONE COLUMN from a "turned sideways" ascii map, shift all the pixels of the display buffer over 1, and add the column to the side. A few things about robobage -- there was the room for an "off screen" column, so the new pixels are put there, then everything is shifted. You don't have the room nor the need for that. I would shift then add the column for scrolling.
[noparse][[/noparse]code]
' you will need to SAVE the last column from this char that you added so that the next time through this routine
'·you can get the next column. If column >= 8 you're done, because there are only 8 cols in a char
······ INC lastCol
······ IF lastCol < 8 THEN 'yer good
DO WHILE cols <·14·· 'let's pretend display buffer is set up as columns, not rows, so you've got 16 columns as bytes
····························· 'only loop through 15 because the last column will be col 14 when you are done
····· tmp1 = cols·+ 1
······dispBuf(tmpB1) = dispBuf(cols)··' shift display columns to the left unless it's last column
LOOP 'now you've got 15 columns at left of display with right column blank
······
······ dispBuf(15) = charBuf(lastCol)··' get the one colum from char --·charBuf as an 8 byte array of the map was set by ascii string function
······ ENDIF
[noparse][[/noparse]/code]
·Not sure if any of this is helpful? I would start backwards and write up routines in small steps -- get your character maps built. Then code the function that dumps a BIT map display buffer (16 bytes) to the display. Don't worry about characters, just that your bitmap is in columns and displays properly.
Then write a function that takes a single byte-stored character and adds it to the display buffer. Then write the function that reads a text string into chars. THEN you know you've got a solid flow:
- read char from string
- add char to display buffer
- print display buffer
If you've got that, then a) it is not hard to write relatively simple code that moves around the display buffer bits before "printing" it, and b) you will know your own buffer and routine organization well enough that manipulating the buffer will not be difficult:
- read char from string
- (manipulate buffer)
- add char (or part of char)·to display buffer
- (manipulate buffer some more)
- print display buffer
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
As far as the ghosting...There is no ghosting until you go past the 64 byte internal buffer of the display device I believe. I think this is what the problem is. I can always get scrolling for either 64 bytes or 128 bytes (e.g. DO WHILE tmpB3 < 65·· or·· DO WHILE tmpB3· <· 129 ). I know you want me to start using 8 bytes vs 64 bytes but I am explaining this from a view point of a past working program for information purposes about the problem.
The problem is that the ghosting ALSO shows with the regular scrolling for anything larger than the 65 bytes. My guess is that from reading the documentation of the display (previously attached), there is an internal buffer of 64 bytes so perhaps this is affecting it. I don't know. Scrolling is fine for either 1 or 2 displays (except for the annoying faint offset ghost scrolling) with the regular normal scrolling.
Thanks for hanging in there with me on this.
AFter your next round of playing, post your running sx/b program and I will try to take a look this weekend.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
DO WHILE tmpB3 < 64
then the top right·LED of the display is always blank (or off) during scrolling. If I change to:
DO WHILE tmpB3 < 65
the top right LED goes off and on correctly while scrolling. If this is the case then this is why I choose 129 which is 1 more than 128 (or logically thinking for a single display 65 is 1 more than 64).
Since I am loading in a bunch of 0's (Ltr_Space) as the first character, I can't tell exactly at what number past 65 the ghosting /flickering occurs at. I have also posted this problem to the SparkFun forum but haven't heard any replies yet. I really don't think I am doing anything wrong in my programming to cause this ghosting / flickering for any number > 65 (or in my case for 2 displays ~129).
As taken from the matrix_backpack.pdf (previously posted):
What about this too?
Is the SPI clock exceeding 125 KHz?
I know the SX-28 is running at 4MHz....but don't know if this is related.
As stated before it scrolls fine on 1 display using my original code routine:
·
I set the DEVICE and FREQ as below:
DEVICE········· SX28, OSC128KHZ, TURBO, STACKX, OPTIONX
FREQ··········· 128_000
It certainly got rid of the ghosting but also brought about another problem. Now the scanning rate is so slow that it redraws too slow so that it is certainly not "smooth" at all - at least with my current program using 64 Bytes not 8 Bytes like Zoot said. Whats weird is that it is ok at higher speeds like 4 MHz with 64 bytes but anything more forget it.
What now?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
Certainly at 128 KHZ it is too slow to do any kind of scrolling (at least using my current program loading in 64 bytes (or more)).
Can anyone else comment on this oddity?
Take a look at this link to the SparkFun forum in which a user wrote a program for the RGB backpack using an aduino USB board. The program states that you have to use 125 KHz which makes sense to what the backpack pdf guide states too:
http://forum.sparkfun.com/viewtopic.php?p=37163#37163
Thanks.
Post Edited (T&E Engineer) : 10/29/2007 2:14:06 AM GMT
125khz SPI -- that's not the frequency of the uController clock, that's the bit rate on clocked data transfers, e.g. SHIFTIN/SHIFTOUT (for SPI) and I2C. The SX/B documentation says that SHIFTIN/SHIFTOUT use a rate of 83khz, independent of uC clock setting (I believe). Far below the max data transfer rate of the backpacks. The forum post you pointed me to refers to a controller where the slowest rate available for SPI 125khz, which means that controller is pushing the envelope on what the backpack can handle. Remember too, that with any clocked data transfer, slower will generally be fine, while faster will not. In this case, unless you are using the speedmult parameter on your SHIFTOUT to jack up the transfer rate, I don't think that's it.
Also be careful not to confuse bit rate on dumping your data with the rate at which things are actually happening the program itself. For example,
1. dump 128 bytes (1024 bits) of data to backpacks at 83khz (default for SHIFTOUT). This is good -- gets your data out there in 1/83 of second, which is ACTUALLY NOT ALL THAT FAST. Think about it -- your MAX refresh rate would be about 83hz (dumping frame after frame of pixels as fast as you can, not counting code overhead). A computer monitor at 83hz would "flicker". But still, it's pretty fast and most of the time you are not dumping frame after frame as fast as you can.
2. now pause 25 ms (or not!) while your eyeball rests. Pausing 25 ms may take 100,000 ticks at 4_000_000 device speed, or 200,000 ticks at 8_000_000 device speed, etc, but it's still 25 ms.
3. go to step 1.
Step 2 is what matters for the pace of your program, scroll speed, etc. Step 1 should always be as quick as possible.
I would look to two places in your current code -- when/where you latch the cascaded shift registers on the backpack, and which rows/columns of your data and/or buffer are being dumped.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
Post Edited (Zoot) : 10/29/2007 3:00:14 AM GMT
It doesn't have to *be* 125khz (the whole point of clocked data transfer is that it is baud and strict time independent -- it doesn't matter how slow the bits come, as long as the clock line pulses when each bit is "ready"). It just has to be less than 125khz.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
OK. now that it has been identified, can we work on your last program which doesn't work at the moment, or take another look at this for scrolling?
Something else I was thinking about -- you don't really need to do 8x8 chars -- you would do 5x8 chars (5 wide, 8 high) which would let you fit a bit more on the display at one time (2.5 characters at a time). Up to you, natch.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST