Shop OBEX P1 Docs P2 Docs Learn Events
SparkFun Large RGB 8x8 LED Matrix & Controller - scrolling issue — Parallax Forums

SparkFun Large RGB 8x8 LED Matrix & Controller - scrolling issue

T&E EngineerT&E Engineer Posts: 1,396
edited 2007-11-07 23:20 in General Discussion
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
«1

Comments

  • T&E EngineerT&E Engineer Posts: 1,396
    edited 2007-10-23 02:32
    Well I connected the 2 displays & controllers (Data Out -> Data In) and (CLOCK -> CLOCK) and (ChipSel -> ChipSel). I can see that using my method that I will have to use a larger array than 65 for the buffer variable.

    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?
  • T&E EngineerT&E Engineer Posts: 1,396
    edited 2007-10-24 12:40
    I was able to figure out how to scroll without having to use an array but having problems still with the software when connecting 2 of SPI LED matrix controllers (DataOut to DataIn) & (Clock to Clock) & (ChipSel to ChipSel).
    Here is what works for 1 SPI LED matrix:
    DISPLAY_RGB1:        
      FOR tmpB1 = 0 TO 196 step 8
        tmpB2 = tmpB1
        tmpB3 = 0
        DO WHILE tmpB3 < 65
          READINC Ltr_Space + tmpB2, tmpB4                                 
          tmpB4 = tmpB4 * color
          INC tmpB3
            LOW ChipSel
            PAUSE 1
            SHIFTOUT DataIn, Clock, MSBFIRST, tmpB4
        LOOP
            PAUSE 1
            HIGH ChipSel
          DELAY_MS 100
      NEXT
      RETURN
     
     
     
    Ltr_Space:
      DATA   0,0,0,0,0,0,0,0
      DATA   0,0,0,0,0,0,0,0
      DATA   0,0,0,0,0,0,0,0
      DATA   0,0,0,0,0,0,0,0
      DATA   0,0,0,0,0,0,0,0
      DATA   0,0,0,0,0,0,0,0
      DATA   0,0,0,0,0,0,0,0
      DATA   0,0,0,0,0,0,0,0
    

    Ltr_P:
      DATA   1,1,1,1,1,1,1,1
      DATA   1,1,1,1,1,1,1,1
      DATA   0,0,0,1,1,0,1,1
      DATA   0,0,0,1,1,0,1,1
      DATA   0,0,0,1,1,0,1,1
      DATA   0,0,0,1,1,1,1,1
      DATA   0,0,0,0,1,1,1,0
      DATA   0,0,0,0,0,0,0,0
    

    Ltr_h:
      DATA   1,1,1,1,1,1,1,1
      DATA   1,1,1,1,1,1,1,1
      DATA   0,0,0,0,1,1,0,0
      DATA   0,0,0,0,1,1,0,0
      DATA   0,0,0,0,1,1,0,0
      DATA   1,1,1,1,1,0,0,0
      DATA   1,1,1,1,0,0,0,0
      DATA   0,0,0,0,0,0,0,0
    


    Post Edited (T&E Engineer) : 10/24/2007 12:46:24 PM GMT
  • ZootZoot Posts: 2,227
    edited 2007-10-24 17:43
    Just keep shifting out till you've loaded all data into all the shift registers, then pulse all of them at once to latch. Remember it's first in, first out, so the first byte of data you shift will show up on the LAST shift register, and the last byte you send will be on the FIRST register (the one that has it's Din connected to the SX). Think of pushing tennis balls through a tube ....

    DISPLAY_RGB1:        
      FOR tmpB1 = 0 TO 196 step 8
        tmpB2 = tmpB1
        tmpB3 = 0
    
    ' note that CS is held low, then ALL the bits are shifted out, then it's brought high again
     LOW ChipSel
     PAUSE 1
           
    ' for example, sending bits 0-127 to two registers
        DO WHILE tmpB3 < 128
          READINC Ltr_Space + tmpB2, tmpB4                                 
          tmpB4 = tmpB4 * color
          INC tmpB3
            SHIFTOUT DataIn, Clock, MSBFIRST, tmpB4
    ' remember that bits 0-64 will be in the SECOND register, and bits 64-127 will be in the FIRST register
        
         LOOP
    
    ' latch it all in
            PAUSE 1
            HIGH ChipSel
          DELAY_MS 100
    
      NEXT
    
    
    
      RETURN
    
    



    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
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-24 18:46
    Thanks Zoot. I see what you did (change the 65 to a 128) and move the "Low ChipSel" and "Pause 1" statements outside of the loop. I think I tried this and I got a ghosting effect on both displays. I will try this again tonight.
    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:

      scrollSpd = 100    ' slow
      SCROLL_LF "<- Left   "   ' scroll text
    

    ' Use: SCROLL_LF [noparse][[/noparse] String | Label ]
    ' -- scrolls ASCII message; embedded string or z-string at "Label"
    ' -- strings in DATA statements may contain non-printing chars (bell, cls)
    SUB SCROLL_LF
      tmpW2 = __WPARAM12    ' start of string
    Get_Next_Char:
      READINC tmpW2, tmpB1    ' get character
      IF tmpB1 = 0 THEN Scroll_Lf_Exit  ' exit if at end of string
      ' handle non-printable
      '
      IF tmpB1 < $20 THEN    ' non-printable?
        IF tmpB1 = Bell THEN
          'beepTmr = BellTm    ' beeper on
          GOTO Get_Next_Char   ' get next char
        ELSEIF tmpB1 = FormFeed THEN
          CLS  
          GOTO Get_Next_Char
        ELSE
          tmpB1 = " "
        ENDIF
      ENDIF
      ' convert non-ASCII chars to space
      '
      IF tmpB1 > 127 THEN
        tmpB1 = " "
      ENDIF
      ' read character map into char buffer
      '
      tmpB1 = tmpB1 - $20    ' zero adjust
      tmpW3 = tmpB1 * 5    ' calc character offset
      FOR tmpB2 = 0 TO 4
        READINC ASCII_Set + tmpW3, charBuf(tmpB2) ' read character map
      NEXT
      charBuf(5) = %00000000   ' space pad
      ' push character into display from right
      '
      tmpB5 = 0
      LOW ChipSel
      PAUSE 1
      
     DO WHILE tmpB5 < 65
      
      FOR tmpB2 = 0 TO 5    ' char columns + space
        dispBuf(8) = charBuf(tmpB2)  ' get one colum from char
        FOR tmpB3 = 0 TO 7    ' loop through display
          tmpB4 = tmpB3 + 1
          dispBuf(tmpB3) = dispBuf(tmpB4)  ' shift display left 
                                        
          tmpB5 = tmpB5 * color
          INC tmpB5
           
            SHIFTOUT DataIn, Clock, MSBFIRST, dispBuf(tmpB3)
        
        NEXT
        DELAY_MS scrollSpd
      NEXT
      
      LOOP
            PAUSE 1
            HIGH ChipSel
    
      GOTO Get_Next_Char    ' get another character
    Scroll_Lf_Exit:
      ENDSUB
    

    ' -------------------------------------------------------------------------
    ' Letters, Numbers, and Symbols
    ' -------------------------------------------------------------------------
    ASCII_Set:
      DATA %00000000    ' space (ASCII 32)
      DATA %00000000
      DATA %00000000
      DATA %00000000
      DATA %00000000
      DATA %00000000    ' !
      DATA %00000000
      DATA %01001111
      DATA %00000000
      DATA %00000000
      DATA %00000000    ' "
      DATA %00000111
      DATA %00000000
      DATA %00000111
      DATA %00000000
      DATA %00010100    ' #
      DATA %01111111
      DATA %00010100
      DATA %01111111
      DATA %00010100
      DATA %00100100    ' $
      DATA %00101010
      DATA %01111111
      DATA %00101010
      DATA %00010010
      DATA %00100011    ' %
      DATA %00010011
      DATA %00001000
      DATA %01100100
      DATA %01100010
      DATA %00110110    ' &
      DATA %01001001
      DATA %01010101
      DATA %00100010
      DATA %01010000
      DATA %00000000    ' '
      DATA %00000101
      DATA %00000011
      DATA %00000000
      DATA %00000000
      DATA %00000000    ' (
      DATA %00011100
      DATA %00100010
      DATA %01000001
      DATA %00000000
      DATA %00000000    ' )
      DATA %01000001
      DATA %00100010
      DATA %00011100
      DATA %00000000
      DATA %00010100    ' *
      DATA %00001000
      DATA %00111110
      DATA %00001000
      DATA %00010100
      DATA %00001000    ' +
      DATA %00001000
      DATA %00111110
      DATA %00001000
      DATA %00001000
      DATA %00000000    ' ,
      DATA %01010000
      DATA %00110000
      DATA %00000000
      DATA %00000000
      DATA %00001000    ' -
      DATA %00001000
      DATA %00001000
      DATA %00001000
      DATA %00001000
      DATA %00000000    ' .
      DATA %01100000
      DATA %01100000
      DATA %00000000
      DATA %00000000
      DATA %00100000    ' /
      DATA %00010000
      DATA %00001000
      DATA %00000100
      DATA %00000010
      DATA %00111110    ' 0
      DATA %01010001
      DATA %01001001
      DATA %01000101
      DATA %00111110
      DATA %00000000    ' 1
      DATA %01000010
      DATA %01111111
      DATA %01000000
      DATA %00000000
      DATA %01000010    ' 2
      DATA %01100001
      DATA %01010001
      DATA %01001001
      DATA %01000110
      DATA %00100001    ' 3
      DATA %01000001
      DATA %01000101
      DATA %01001011
      DATA %00110001
      DATA %00011000    ' 4
      DATA %00010100
      DATA %00010010
      DATA %01111111
      DATA %00010000
      DATA %00100111    ' 5
      DATA %01000101
      DATA %01000101
      DATA %01000101
      DATA %00111001
      DATA %00111100    ' 6
      DATA %01001010
      DATA %01001001
      DATA %01001001
      DATA %00110000
      DATA %00000001    ' 7
      DATA %01110001
      DATA %00001001
      DATA %00000101
      DATA %00000011
      DATA %00110110    ' 8
      DATA %01001001
      DATA %01001001
      DATA %01001001
      DATA %00110110
      DATA %00000110    ' 9
      DATA %01001001
      DATA %01001001
      DATA %00101001
      DATA %00011110
      DATA %00000000    ' :
      DATA %00110110
      DATA %00110110
      DATA %00000000
      DATA %00000000
      DATA %00000000    ' ;
      DATA %01010110
      DATA %00110110
      DATA %00000000
      DATA %00000000
      DATA %00000000    ' <
      DATA %00001000
      DATA %00010100
      DATA %00100010
      DATA %01000001
      DATA %00010100    ' =
      DATA %00010100
      DATA %00010100
      DATA %00010100
      DATA %00010100
      DATA %00000000    ' >
      DATA %01000001
      DATA %00100010
      DATA %00010100
      DATA %00001000
      DATA %00000010    ' ?
      DATA %00000001
      DATA %01010001
      DATA %00001001
      DATA %00000110
      DATA %00110010    ' @
      DATA %01001001
      DATA %01111001
      DATA %01000001
      DATA %00111110
      DATA %01111110    ' A
      DATA %00010001
      DATA %00010001
      DATA %00010001
      DATA %01111110
      DATA %01111111    ' B
      DATA %01001001
      DATA %01001001
      DATA %01001001
      DATA %00110110
      DATA  %00111110     ' C
      DATA  %01000001
      DATA  %01000001
      DATA  %01000001
      DATA  %00100010
      DATA %01111111    ' D
      DATA %01000001
      DATA %01000001
      DATA %01000001
      DATA %00111110
      DATA  %01111111     ' E
      DATA  %01001001
      DATA  %01001001
      DATA  %01001001
      DATA  %01000001
      DATA  %01111111     ' F
      DATA  %00001001
      DATA  %00001001
      DATA  %00001001
      DATA  %00000001
      DATA  %00111110     ' G
      DATA  %01000001
      DATA  %01001001
      DATA  %01001001
      DATA  %01111010
      DATA %01111111    ' H
      DATA %00001000
      DATA %00001000
      DATA %00001000
      DATA %01111111
      DATA %00000000    ' I
      DATA %01000001
      DATA %01111111
      DATA %01000001
      DATA %00000000
      DATA %00100000    ' J
      DATA %01000000
      DATA %01000001
      DATA %00111111
      DATA %00000001
      DATA %01111111    ' K
      DATA %00001000
      DATA %00010100
      DATA %00100010
      DATA %01000001
      DATA %01111111    ' L
      DATA %01000000
      DATA %01000000
      DATA %01000000
      DATA %01000000
      DATA %01111111    ' M
      DATA %00000010
      DATA %00001100
      DATA %00000010
      DATA %01111111
      DATA %01111111    ' N
      DATA %00000100
      DATA %00001000
      DATA %00010000
      DATA %01111111
      DATA %00111110    ' O
      DATA %01000001
      DATA %01000001
      DATA %01000001
      DATA %00111110
      DATA %01111111    ' P
      DATA %00001001
      DATA %00001001
      DATA %00001001
      DATA %00000110
      DATA %00111110    ' Q
      DATA %01000001
      DATA %01010001
      DATA %00100001
      DATA %01011110
      DATA %01111111    ' R
      DATA %00001001
      DATA %00011001
      DATA %00101001
      DATA %01000110
      DATA  %00100110     ' S
      DATA  %01001001
      DATA  %01001001
      DATA  %01001001
      DATA  %00110010
      DATA  %00000001     ' T
      DATA  %00000001
      DATA  %01111111
      DATA  %00000001
      DATA  %00000001
      DATA %00111111    ' U
      DATA %01000000
      DATA %01000000
      DATA %01000000
      DATA %00111111
      DATA %00011111    ' V
      DATA %00100000
      DATA %01000000
      DATA %00100000
      DATA %00011111
      DATA %00111111    ' W
      DATA %01000000
      DATA %00111000
      DATA %01000000
      DATA %00111111
      DATA %01100011    ' X
      DATA %00010100
      DATA %00001000
      DATA %00010100
      DATA %01100011
      DATA %00000111    ' Y
      DATA %00001000
      DATA %01110000
      DATA %00001000
      DATA %00000111
      DATA %01100001    ' Z
      DATA %01010001
      DATA %01001001
      DATA %01000101
      DATA %01000011
      DATA %00000000    ' [noparse][[/noparse]
      DATA %01111111
      DATA %01000001
      DATA %01000001
      DATA %00000000
      DATA  %00000010     ' \
      DATA  %00000100
      DATA  %00001000
      DATA  %00010000
      DATA  %00100000
      DATA %00000000    ' ]
      DATA %01000001
      DATA %01000001
      DATA %01111111
      DATA %00000000
      DATA %00000100    ' ^
      DATA %00000010
      DATA %00000001
      DATA %00000010
      DATA %00000100
      DATA %01000000    ' _ (underscore)
      DATA %01000000
      DATA %01000000
      DATA %01000000
      DATA %01000000
      DATA %00000000    ' `
      DATA %00000001
      DATA %00000010
      DATA %00000100
      DATA %00000000
      DATA %00100000    ' a
      DATA %01010100
      DATA %01010100
      DATA %01010100
      DATA %01111000
      DATA %01111111    ' b
      DATA %01001000
      DATA %01000100
      DATA %01000100
      DATA %00111000
      DATA %00111000    ' c
      DATA %01000100
      DATA %01000100
      DATA %01000100
      DATA %00100000
      DATA %00111000    ' d
      DATA %01000100
      DATA %01000100
      DATA %01001000
      DATA %01111111
      DATA %00111000    ' e
      DATA %01010100
      DATA %01010100
      DATA %01010100
      DATA %00011000
      DATA %00001000    ' f
      DATA %01111110
      DATA %00001001
      DATA %00000001
      DATA %00000010
      DATA %00001100    ' g
      DATA %01010010
      DATA %01010010
      DATA %01010010
      DATA %00111110
      DATA %01111111    ' h
      DATA %00001000
      DATA %00000100
      DATA %00000100
      DATA %01111000
      DATA %00000000    ' i
      DATA %01000100
      DATA %01111101
      DATA %01000000
      DATA %00000000
      DATA %00100000    ' j
      DATA %01000000
      DATA %01000100
      DATA %00111101
      DATA %00000000
      DATA %01111111    ' k
      DATA %00010000
      DATA %00101000
      DATA %01000100
      DATA %00000000
      DATA %00000000    ' l
      DATA %01000001
      DATA %01111111
      DATA %01000000
      DATA %00000000
      DATA %01111100    ' m
      DATA %00000100
      DATA %00011000
      DATA %00000100
      DATA %01111000
      DATA %01111100    ' n
      DATA %00001000
      DATA %00000100
      DATA %00000100
      DATA %01111000
      DATA %00111000    ' o
      DATA %01000100
      DATA %01000100
      DATA %01000100
      DATA %00111000
      DATA %01111100    ' p
      DATA %00010100
      DATA %00010100
      DATA %00010100
      DATA %00001000
      DATA %00001000    ' q
      DATA %00010100
      DATA %00010100
      DATA %00011000
      DATA %01111100
      DATA %01111100    ' r
      DATA %00001000
      DATA %00000100
      DATA %00000100
      DATA %00001000
      DATA %01001000    ' s
      DATA %01010100
      DATA %01010100
      DATA %01010100
      DATA %00100000
      DATA %00000100    ' t
      DATA %00111111
      DATA %01000100
      DATA %01000000
      DATA %00100000
      DATA %00111100    ' u
      DATA %01000000
      DATA %01000000
      DATA %00100000
      DATA %01111100
      DATA %00011100    ' v
      DATA %00100000
      DATA %01000000
      DATA %00100000
      DATA %00011100
      DATA %00111100    ' w
      DATA %01000000
      DATA %00110000
      DATA %01000000
      DATA %00111100
      DATA %01000100    ' x
      DATA %00101000
      DATA %00010000
      DATA %00101000
      DATA %01000100
      DATA %00001100    ' y
      DATA %01010000
      DATA %01010000
      DATA %01010000
      DATA %00111100
      DATA %01000100    ' z
      DATA %01100100
      DATA %01010100
      DATA %01001100
      DATA %01000100
      DATA %00000000    ' {
      DATA %00001000
      DATA %00110110
      DATA %01000001
      DATA %00000000
      DATA %00000000    ' |
      DATA %00000000
      DATA %01111111
      DATA %00000000
      DATA %00000000
      DATA %00000000    ' }
      DATA %01000001
      DATA %00110110
      DATA %00001000
      DATA %00000000
      DATA %00000100    ' ~
      DATA %00000010
      DATA %00000100
      DATA %00000010
      DATA %00000000
      DATA %00001000    ' <- (non ASCII)
      DATA %00011100
      DATA %00101010
      DATA %00001000
      DATA %00001000
    


    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!
    ·
  • ZootZoot Posts: 2,227
    edited 2007-10-24 19:48
    Yeah, what you said. You'll have other changes to make to have the code dump in your particular pattern, but here's the big change (aside from redrawing your chars in 8x8 maps smile.gif )


    ' 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:

    messagePntr = address 'point to data address of first character of text string
    ' now dump 8 CHARACTERS
    LOW CS ' get shift registers ready
    FOR char = 7 TO 0
       READ --> from messagePntr+char into tmpByte1 'get the char
       FOR outBytes = 7 TO 0  'now, you need to shift out 8 bytes of pixel map for this character ---
          'each character map has 8 bytes, organized following ascii chart --- does not include offset for 0 or other error checking 
          READ --> from (charMaps+char)*8 into tmpByte2
             'great, now you've got the first row (or column as you prefer) of map data in tmpByte2
             'process tmpByte2 for each pixel if you need RGB info, etc.
            SHIFTOUT tmpByte2
       NEXT 'next row/col for this character
    NEXT 'next char in string
    HIGH CS 'latch the data!!!!
    
    



    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:

    FOR start = 0 TO 7
      end = start+7  'set "tail" of this sliding window
    
    messagePntr = address 'point to data address of first character of text string
    ' now dump 8 CHARACTERS
    LOW CS ' get shift registers ready
    FOR char = end TO start  'on second loop, start will be 1, end will be 8
       READ --> from messagePntr+char into tmpByte1 'get the char
       FOR outBytes = 7 TO 0  'now, you need to shift out 8 bytes of pixel map for this character ---
          'each character map has 8 bytes, organized following ascii chart --- does not include offset for 0 or other error checking 
          READ --> from (charMaps+char)*8 into tmpByte2
             'great, now you've got the first row (or column as you prefer) of map data in tmpByte2
             'process tmpByte2 for each pixel if you need RGB info, etc.
            SHIFTOUT tmpByte2
       NEXT 'next row/col for this character
    NEXT 'next char in string
    HIGH CS 'latch the data!!!!
    
    MS_DELAY 100 'delay between scroll "frames"
    NEXT
    
    
    



    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
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-24 23:04
    Zoot,

    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?
    Zoot said...
    Just keep shifting out till you've loaded all data into all the shift registers, then pulse all of them at once to latch. Remember it's first in, first out, so the first byte of data you shift will show up on the LAST shift register, and the last byte you send will be on the FIRST register (the one that has it's Din connected to the SX). Think of pushing tennis balls through a tube ....

    DISPLAY_RGB1:        
      FOR tmpB1 = 0 TO 196 step 8
        tmpB2 = tmpB1
        tmpB3 = 0
    
    ' note that CS is held low, then ALL the bits are shifted out, then it's brought high again
     LOW ChipSel
     PAUSE 1
           
    ' for example, sending bits 0-127 to two registers
        DO WHILE tmpB3 < 128
          READINC Ltr_Space + tmpB2, tmpB4                                 
          tmpB4 = tmpB4 * color
          INC tmpB3
            SHIFTOUT DataIn, Clock, MSBFIRST, tmpB4
    ' remember that bits 0-64 will be in the SECOND register, and bits 64-127 will be in the FIRST register
        
         LOOP
    
    ' latch it all in
            PAUSE 1
            HIGH ChipSel
          DELAY_MS 100
    
      NEXT
    
    
    
      RETURN
    
    



    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.

  • ZootZoot Posts: 2,227
    edited 2007-10-24 23:07
    Can you post the .sxb program that gave you the "ghost"? I'll try to take a look at it after dinner this evening.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-25 00:22
    Thanks Zoot.
    This is what is running:
    DISPLAY_RGB1:        
      FOR tmpB1 = 0 TO 255 step 8
        tmpB2 = tmpB1
        tmpB3 = 0
        
        LOW ChipSel
        DELAY_MS 1
        DO WHILE tmpB3 < 64
         
          READINC Ltr_Space + tmpB2, tmpB4                                 
          tmpB4 = tmpB4 * color
            SHIFTOUT DataIn, Clock, MSBFIRST, tmpB4
          INC tmpB3
        LOOP
            DELAY_MS 1
            HIGH ChipSel
          DELAY_MS 100
      NEXT
      RETURN
    

    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:
    messagePntr = address 'point to data address of first character of text string
    

    ·How do I find out the data address? Isn't this CharMaps: ? or Ascii_Set:·?

    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.

    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
  • ZootZoot Posts: 2,227
    edited 2007-10-25 01:01
    messagePntr = address 'point to data address of first character of text string
    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
  • ZootZoot Posts: 2,227
    edited 2007-10-25 03:14
    OK, dude, I cut this whole thing way down. I think this will work -- it compiles, but obviously I can't test it.

    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 B), OR you would need a BIT BASED buffer that you can manipulate. At 8 bytes per display square, this isn't too much, but if you don't get the code I wrote that takes a BIT based image map (rather than your very very long BYTE based maps), a bit-based buffer may add to debug headaches. Keep in mind that the RoboBadge is 1/0 for pixels, no colors, very quick, but the same theories would work here -- you'd be holding 16 bytes (128 bits) -- of char data in memory.

    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
  • ZootZoot Posts: 2,227
    edited 2007-10-25 03:19
    P.S. -- one final comment -- my code is NOT very efficient at the assembly level... selah.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-25 10:21
    I tried to run it this morning before work and it did not do anything other than flash some colors on the entire screen fast (flickering almost).

    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.
  • ZootZoot Posts: 2,227
    edited 2007-10-25 12:52
    Well, I forgot the .5 ms delay after the for...shiftout...next and before taking ChipSel HIGH... so try that. Otherwise, there might be logic errors in my code.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-25 13:32
    Yes. I saw that the PAUSE 1 was missing too. I also added a MS_DELAY 100 between the FOR NEXT looping to see it slow down a bit. I noticed that it starts with some RED lines being drawn in up/down and then if I remember right some other colors full flashing like yellow (redgreen). This makes sense because you are executing other messages (Msg2, Msg3) that their characters are not 8x8 (like A, B and C are in Msg1).

    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.

    'Use: SEND_MSG MsgAddr, color (0-6)
    DISPLAY_MSG:
       tmpW2 = __WPARAM12  ' pass address of message to print; tmpW1 is used in other subs
       color = __PARAM3    ' entire message will be one color, but you can play with this I'm sure
    Setup_Led_Driver:
       LOW ChipSel
       DELAY_MS 1 ' delay following spec sheet for driver
       
    Read_Char:
       READINC tmpW2, char ' read char from string...
       IF char = 0 THEN Chars_Done ' end of string? done...
       'now, you've got a char, you need to point READ to
       'to that 8 byte character map and read in each row of bits,
       'convert each bit to byte with color, send it
       'but it's FIRST IN, FIRST OUT to the shift register
    Map_Char:
       tmpW3 = char - 32 'subtract 32 so 0 = space
            'you could do other trickery here to get form feed chars, case sensitivity, etc.
       tmpW3 = tmpW3 * 8 'it's the charactuer "number" * 8 bytes
       'now some trickery is needed to "mask" the bit of the pixel, so you can add color and create a byte...
    Parse_Char:
       FOR tmpB5 = 0 TO 7 ' loop through rows, top to bottom 
           READINC ASCII_Set + tmpW3, tmpB2  'read first row of pixels bits ("bitmap") into tmpB2, tmpW3 will increment on each pass
               FOR tmpB3 = 0 TO 7 ' unless you mirror image your charMaps, you need to send pixels HSB to MSB, hence mask rotates right
                  tmpB4 = %1000_0000 >> tmpB5  'bit mask for this pixel remember it's just a BIT
                  tmpB4 = tmpB2 & tmpB4 'mask with row and save to mask variable space
                  IF tmpB4 <> 0 THEN 'pixel on? -- set to 1 and add color
                      tmpB4 = 1 + color
                  ENDIF
                  'whew, now you've got a byte with color/on/off ready to go to top left shift register
                  'so send it
                  SHIFTOUT DataIn, Clock, MSBFIRST, tmpB4
               NEXT ' next pixel this row, from LEFT TO RIGHT, not right to left
       [b]DELAY_MS 100[/b]
       NEXT 'next row this char
    Next_Char:
       GOTO Read_Char
    Chars_Done:
       ' latch it and pause!!!
       [b]DELAY_MS 1
    [/b]   HIGH ChipSel
    Msg_Done:
       RETURN
    


    How about using JonnyMac's BIT routine too (if needed):

    ·This helped when converting your BS2 DoChar routine for use on the SX/B.

    ' Use: value = BITVAL someVal, position
    ' -- "someVal" can be a byte or word
    FUNC BITVAL
      IF __PARAMCNT = 2 THEN                        ' byte passed?
        tmpW1 = __PARAM1                            ' get byte value
        temp1 = __PARAM2                            ' get bit position 
      ELSE                                          ' word passed
        tmpW1 = __WPARAM12                          ' word was passed
        temp1 = __PARAM3                            ' get bit position
      ENDIF
      temp2 = 0                                     ' assume cleared
      IF temp1 >= 0 THEN                            ' position value legal?
        IF temp1 <= 15 THEN
          tmpW2 = 1 << temp1                        ' create bit mask
          tmpW2 = tmpW2 & tmpW1                     ' clear other bits
          IF tmpW2 > 0 THEN                         ' if not zero
            temp2 = 1                               '   bit was 1
          ENDIF
        ENDIF  
      ENDIF
      RETURN temp2
      ENDFUNC
    
    doChar:       
          
           LOW ChipSel 'get ready for SPI
           PAUSE 1
           FOR rows = 0 TO 7  'loop through rows
              pixels = buf(rows)
              FOR cols = 0 TO 7 'loop cols and make a pixel byte
                  value = BITVAL pixels, cols
                  value = value * Color
                  SHIFTOUT DataIn, Clock, MSBFIRST, value
                  'if bit for this col/row is 1, then color gets you 1-7 if "on"
              'Un-comment to have every LED pixel random
              'RANDOM seed
              'Rand_no = seed // 7 + 1
              'color = Rand_no
              NEXT
           NEXT
           'Un-comment to have every letter random
             'RANDOM temp1     '
             'temp2 = temp1 // 7
             'temp2 = temp2 + 1
             'color = temp2
             RANDOM seed     
             color = seed // 7
             color = color + 1
           'Hold down on keypad for random color cycling
           PAUSE 1
           HIGH ChipSel 'latch it
           RETURN
    
    

    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.
  • ZootZoot Posts: 2,227
    edited 2007-10-25 13:59
    Not sure about errors -- hard to guage without having one of the displays. You do NOT need the DELAY_MS 100 in the for/next loop -- this just slows down dumping data (nothing's been latched at that point, so it doesn't matter).

    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
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-25 14:02
    Right. I will try with just "A" first. However, it will be early this evening before I get home to test this.

    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.
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-25 15:22
    Let me get back to the original issue that using my routine:
    DISPLAY_RGB1:        
      FOR tmpB1 = 0 TO 255 step 8
        tmpB2 = tmpB1
        tmpB3 = 0
        
        LOW ChipSel
        DELAY_MS 1
        [b]DO WHILE tmpB3 < 64    'or use    DO WHILE tmpB3 < 128    for 2 displays...[/b]
         
          READINC Ltr_Space + tmpB2, tmpB4                                 
          tmpB4 = tmpB4 * color
            SHIFTOUT DataIn, Clock, MSBFIRST, tmpB4
          INC tmpB3
        LOOP
            DELAY_MS 1
            HIGH ChipSel
          DELAY_MS 100
      NEXT
      RETURN
    
    

    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.
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-26 10:04
    Zoot,

    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.
  • ZootZoot Posts: 2,227
    edited 2007-10-26 11:33
    I would guess the ghosting is from either improper manipulation of the bitmap buffer, or an error in scanning the bytes of your pixels. That said, I would approach this backwards ---

    - 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
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-26 11:51
    Thank you Zoot. I will go through this posting tonight and over the weekend.

    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.
  • ZootZoot Posts: 2,227
    edited 2007-10-26 12:05
    (e.g. DO WHILE tmpB3 < 65·· or·· DO WHILE tmpB3· <· 129 ).
    Right, but the above would give you 65 bytes (0-64) or 129 bytes (0-128) which would give you a ghost. But that's not what's in your code it doesn't look like.

    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
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-26 12:23
    Yes. I was playing around with different values near 64. If I use:
    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):
    Interface to Default Programming
    The RGB/RG matrix backpacks' default
    program communicates via standard SPI
    protocol. Data In to the device (MOSI) must
    be provided via the DI pin. SPI Clock must be
    provided via the SCK pin. The device will
    return data via the data out connection
    (MISO) via the DO pin. All input is ignored as
    long as the CS pin is logic true (5V) and all
    data is accumulated as long as the CS pin is
    logic false (0V).
    
    [b]The device maintains a single 64 byte
    buffer which represents each position in the
    matrix.[/b] When CS is asserted (low) the device
    begins reading data from the SPI input and
    writing it sequentially to the 64 byte buffer.
    Simultaneously, the device will output the old
    buffer data, sequentially, on the MISO line.
    Hence, to program every LED, a set of 64
    bytes must be sequentially transferred to the
    backpack, while maintaining CS asserted.
    


    What about this too?

    SPI Timings:
    A delay of 0.5ms is recommended between
    the assertion of CS and the start of data
    transfer, as well as after the end of data
    transfer and the negation of CS. [b]The SPI
    clock should not exceed 125kHz.[/b]
    

    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:

    DISPLAY_RGB1:        
      FOR tmpB1 = 0 TO 255 step 8
        tmpB2 = tmpB1
        tmpB3 = 0
        
        LOW ChipSel
        DELAY_MS 1
        [b]DO WHILE tmpB3 < 64    'or use    DO WHILE tmpB3 < 128    for 2 displays...[/b]
         
          READINC Ltr_Space + tmpB2, tmpB4                                 
          tmpB4 = tmpB4 * color
            SHIFTOUT DataIn, Clock, MSBFIRST, tmpB4
          INC tmpB3
        LOOP
            DELAY_MS 1
            HIGH ChipSel
          DELAY_MS 100
      NEXT
      RETURN
    

    ·
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-29 00:02
    Well I figured out the Ghosting problem. It says in the RGB backpack should not exceed 125 KHz.

    SPI Timings:
    A delay of 0.5ms is recommended between
    the assertion of CS and the start of data
    transfer, as well as after the end of data
    transfer and the negation of CS. [b]The SPI
    clock should not exceed 125kHz.[/b]
    


    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?
  • ZootZoot Posts: 2,227
    edited 2007-10-29 01:29
    T&E -- I think you are barking up the wrong tree. Unless you use the SpeedMult parameter with SHIFTIN/SHIFTOUT, the SHIFT functions in SX/B are set at ~83khz (slow enough for Stamps). And to the best of my knowledge, the SHIFT timing is frequency independent (that is, the time between bits is recalcuating based on device frequency so that the time between bits is always ~6us). That said, slowing things down to 128_000 would probably slow down SHIFTIN/SHIFTOUT, but I don't think you were anywhere near 125khz to begin with.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-29 02:01
    Wow. Now I don't know what to believe or understand this problem. All I know is when I moved the DEVICE and FREQ lines from 4 MHZ to 128 KHZ, the ghosting was not seen. However, I did change it also to 1 MHZ and I did see the ghosting again which makes sense why I also saw it at 4 MHZ.

    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?
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-29 02:09
    Zoot,

    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
  • ZootZoot Posts: 2,227
    edited 2007-10-29 02:49
    Somebody said...
    // The Backpack requires 125Khz SPI -> which is the slowest rate at which the Arduino's hardware SPI bus can communicate at.

    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
  • ZootZoot Posts: 2,227
    edited 2007-10-29 03:01
    From the backpack documentation:
    Somebody said...
    The SPI clock should not exceed 125kHz.

    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
  • T&amp;E EngineerT&amp;E Engineer Posts: 1,396
    edited 2007-10-29 10:19
    That's how I originally took that statement too. However, you can ignore the fact that the ghosting goes away with the slower speed (e.g. 128 KHZ which is close to 125 KHZ). It definately is seen at 1 MHz and higher.

    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?
  • ZootZoot Posts: 2,227
    edited 2007-10-29 14:01
    Tell you what -- post your most recent version of the program and I'll take a look tonight. Also, until you have bit- (not byte-) mapped ASCII characters, scrolling and such will be hard to deal with for any message of any length. Think about it -- at 64 bytes per 8x8 character, that would be 1664 bytes *just* to do 26 letters.

    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
Sign In or Register to comment.