Shop OBEX P1 Docs P2 Docs Learn Events
Need to speed up this. — Parallax Forums

Need to speed up this.

BTXBTX Posts: 674
edited 2011-07-15 07:02 in Propeller 1
Hi everybody.
I've this (below code) working fine, but I should speed up this.
Could some of the genius of this forum, give me a hand ?
The problem is that the code is too slow, look at it, the repeat parts, there are a lot of repeats, but I can't found another way to do it, the code is for a led sign, and the part is giving me the nightmare, is the HScroll code.
I've the data to "show" in a array named "bufffer", then I pass that data to a PcartelR array, frame by frame, and I show each frame copying the PcartelR array, to a cartelR array. What I get is, so less frame/sec.

I would like to listen some help from you,...ideas or solutions ?
PUB HScroll | i, j, u, v, x, m, n
    repeat i from 0 to 79
       cartelR[i] := 255

    x:=0
    m:=0
    n:=0
  repeat u from 0 to 896 step 8                         ' I have a string with some characters. (about 120 chars of 8 bytes each)
    repeat n from 0 to 7                                ' My matrix display is 8 lines by 8 columns
      repeat i from 0 to 7
        m:=u
        repeat j from 0 to 72 step 8
           repeat v from 0 to 7
              PcartelG[i+j] := CHANGE(PcartelG[i+j], v, VIEW(buffer[x+m], n))   ' buffer contains the usefull data (the text to show), line1, lin2, .. line8 (first digit)// line1, lin2, .. line8 (2nd digit), etc
              n++
              if n==8
                 n:=0
                 m:=m+8
           PcartelG[i+j] :=   PcartelG[i+j] >< 8        ' PcartelR is a provisory array
        x++
        if x==8
           x:=0
      bytemove(@cartelG, @PcartelG, 80)   ' "cartelR" is the visible array in the display, I've an asm rutine that catch the address of cartelR and pass it to the shift registers at very good speed.
'      waitcnt(clkfreq/1000 + cnt)        ' in this line of code, my display show 10 caracters at very low speed scroll, due the above code is too slow.
                                          ' Although the waitcnt is unused.
                                                        
{{Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  and associated documentation files (the "Software"), to deal in the Software without restriction,
  including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
  subject to the following conditions: 
   
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 
   
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}}

PUB VIEW (VALUE, BIT)
{{ BitManipulator.spin, v1.1
   Copyright (c) 2009 Austin Bowen
   *See end of file for terms of use*
   Use to view and manipulate bits, see subroutines for details. To include object:

    OBJ
      BIT : "BitManipulator"
}}
  RETURN VALUE >> BIT >< 1      'Return the bit

PUB CHANGE (VALUE, BIT, STATE)
{{ BitManipulator.spin, v1.1
   Copyright (c) 2009 Austin Bowen
   *See end of file for terms of use*
   Use to view and manipulate bits, see subroutines for details. To include object:

    OBJ
      BIT : "BitManipulator"
}}
  IF (STATE <> -1)                                      'If state non-invert
    IF (VIEW(VALUE, BIT) <> STATE)
      IF STATE                                          'Return with stated bit 1
        RETURN VALUE + |< BIT
      ELSE                                              'Return with stated bit 0
        RETURN VALUE - |< BIT
  ELSE
    IF VIEW(VALUE, BIT)                                 'Invert bit
      RETURN VALUE - |< BIT                             'Return with stated bit 0 if 1
    ELSE
      RETURN VALUE + |< BIT                             'Return with stated bit 1 if 0
  RETURN VALUE                                          'Return value without editing if already state

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-07-10 17:47
    Alberto,

    This sure looks like a good candidate to convert to PASM.

    It looks like you're scrolling text horizontally on a LED screen. Is that right?

    There might be (probably is) a fast way to do it in Spin too.

    I built a 10 x 12 LED array.

    I sped things up by building arrays of bytes in EEPROM that I could move into the display buffer more quickly. There was a byte for each "pixel" of the array. This uses more memory but I wanted to be able to have multiple brightness levels within one character or pattern. The initial font consisted of bits but then I converted the bits to bytes. I think this makes the data easier to manipulate. The conversion only has to be done once, not every time the program is started since it is saved in EEPROM. This is the code I use to move the appropriate sections from EEPROM based on the characters located at "localPtr".
    PUB LoadText(localPtr, localSize) | localIndex, showFlag, localCharacter, eeStart
     
      repeat localSize
        showFlag := 0
        localCharacter := byte[localPtr++]
     
        if localCharacter => _LowestAsciiUsed and localCharacter =< _HighestAsciiUsed 
        ' make sure character is within font range.
          showFlag := 1 ' I just realized I don't need showFlag.  
                          '  It's left over from an earlier version.
        else 
          localCharacter := 32
           ' If I don't have a font for the character us a space.
          showFlag := 1
        if showFlag == 1
     
          eeStart := _EepromFontAddress + (121 * (localCharacter - _LowestAsciiUsed))
          Eeprom.ToRam(@fontSpace, @fontSpace + 120, eeStart)
          if localCharacter == 32
            ScrollHorizontal(_DefaultSpaceBetweenLetters, _DefaultNSpacing - _DefaultSpaceBetweenLetters, @fontSpace)
     
     
          else
            ScrollHorizontal(_DefaultSpaceBetweenLetters, fontSpace[120], @fontSpace)
     
    

    I'd move the next character to be displayed into the 120 bytes immediately after the 120 byte display buffer and then use this code to scroll it horizontally.
    PUB ScrollHorizontal(localSpace, localSize, localPtr) | localIndex[2]
      localSize += localSpace
      localSize <#= _LineLength
      repeat localIndex[0] from 0 to localSize - 1
        repeat localIndex[1] from 0 to 9
          bytemove(@displayBuffer + (localIndex[1] * _LineLength), @displayBuffer + (localIndex[1] * _LineLength) + 1, _LineLength - 1)
          byte[@displayBuffer + (localIndex[1] * _LineLength) + _LineLength - 1] := byte[localPtr + (localIndex[1] * _LineLength) + (localIndex[0])]  
        waitcnt(delay + cnt)
     
    

    I use a "delay" of 5,000,000 clock cycles (@80MHz) to keep the text from zipping past too fast.

    I really like the way it turned out. I keep meaning to make a video of it scrolling the text.

    Do you have room in EEPROM to prebuild your characters?

    I think it's one of those times you can gain speed at the cost of memory.

    Duane

    Edit: I've very willing to share the entire program if you'd like to see it.
  • BTXBTX Posts: 674
    edited 2011-07-10 18:51
    Hi Duane.
    At first thx you to answer me !!
    Yeah, I'm doing a led display, and I'm looking for a simple method to scroll a 200 characters text into the display horizontally, vertical, and more effects.
    I thought before about your proposal, but my display is 80x8 pixels and tri-color (maybe too much wasted memory in this size, with that method).
    Like I'm not very good programming, I asked for a better solution, that sure I don't know, and in this forum are a lot of people with very advanced skills to do this task more easily (I'm sure of that).
    Anyway later I will see more closely your code, and here I post mine full actual code too. (sorry it is not well documented yet). I would like to see yours too.
  • kuronekokuroneko Posts: 3,623
    edited 2011-07-10 18:54
    Inside the loop you use lots of i+j indices. They get re-calculated every time so put them into a temporary and use this instead. Also, the bit manipulation is rather verbose (for want of a better word). Here is a modified CHANGE method which is about twice as fast.
    PRI CHANGE(value, pos, bit)
    
     dirb := value
     dirb[pos] := bit
     return dirb
    
    which should be called like this:
    tmp := i+j
    PcartelG[tmp] := CHANGE(PcartelG[tmp], v, buffer[x+m] >> n)
    
    There are most likely other ways of speeding it up (before going to PASM) simply by re-arranging your input data. This is only my first cup of coffee today so have a look if the stuff above makes a big enough difference.
  • BTXBTX Posts: 674
    edited 2011-07-10 19:03
    THANK you so much kuroneko !!!!!
    That kind of things is what I was looking for, not only for this display, instead, it gives me more knowledge in programming technics.
    Now is 23:00 here, today I also worked all day, my eyes are down, tomorow morning I will try your solution before go work, and I will advice you.
    Thanks again.
  • kuronekokuroneko Posts: 3,623
    edited 2011-07-10 19:59
    Another thing, you apply lots of modifications to the PcartelR array (><, ! etc). Don't do that in SPIN but in the PASM driver insteadA. Also, make sure your cartelG array stays long aligned as you use it as par parameterB. This is the case ATM but you know how easily things get messed up with byte VARs getting relocated to come after long and word.

    A From a quick glance you undo the SPIN rev with a PASM rev so you might as well get rid of it entirely.
    B You can always use the rdlong addr, par approach instead of mov addr, par if you don't want to care about alignment.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-07-10 20:21
    kuroneko wrote: »
    Another thing, you apply lots of modifications to the PcartelR array (><, ! etc). Don't do that in SPIN but in the PASM driver instead. Also, make sure your cartelG array stays long aligned as you use it as par parameterA. This is the case ATM but you know how easily things get messed up with byte VARs getting relocated to come after long and word.

    A You can always use the rdlong addr, par approach instead of mov addr, par.

    Another way to keep bytes long aligned is to put them in the DAT section (if they don't have to be in the VAR section) and use ORG immediately before your variable.

    (I'm sure Kuroneko knows this (is there anything about the Prop he doesn't?) but maybe someone else reading this thread doesn't know about this trick.)

    Duane
  • BTXBTX Posts: 674
    edited 2011-07-11 04:52
    Hi guys !!
    @kuroneko.
    Your first try get me more speed that before, but still it is too slow.
    In fact I don't need the modifications in PcartelR array(><, ! etc). there, it is only for add a "nice" effect in the text, but the important part, and slow code, is running before that.

    @kuroneko and @Duane
    I don't understand what are you talking about with "long aligned", the asm part of the code is enough fast for me, or more fast that i could need it. Do you mean scroll the arrays by using longs ? how? I'm scrolling bits.
    Did you all read the full code ?.
  • kuronekokuroneko Posts: 3,623
    edited 2011-07-11 06:12
    BTX wrote: »
    @kuroneko and @Duane
    I don't understand what are you talking about with "long aligned", ...
    Imagine you have the following VAR layout:
    VAR
      byte  array[80]
      long  mode
      word  status
    
    Variables get re-ordered (long followed by word and byte). In the above example @array{0} would end up as 4n+2 which doesn't survive being passed to PASM (par is 4n only). An easy solution would be to use long array[80/4].
  • BTXBTX Posts: 674
    edited 2011-07-11 17:05
    kuroneko.
    I think I understand what you mean, but I can't catch the idea in my case.... :(
  • kuronekokuroneko Posts: 3,623
    edited 2011-07-11 17:21
    BTX wrote: »
    I think I understand what you mean, but I can't catch the idea in my case.... :(
    It's not an issue right now, just saying. Anyway, what's the intended framerate for the loop (as now is the point to look for other ways of speeding things up).
  • Mark_TMark_T Posts: 1,981
    edited 2011-07-11 17:33
    The single most important gain you are going to get is to lose CHANGE and VIEW and directly manipulate the data byte-wide in-line, not bit-by-bit-via-function-calls. If you need to speed up code the first thing you need is an idea of where the program spends time, and this is usually in inner-loops - optimize first the contents of the innermost loops.

    I think your inner loop with v as the variable is doing some shifting, spin has shift operators... You may be able to use longs to shift 32 bits at a time
  • BTXBTX Posts: 674
    edited 2011-07-12 05:34
    @kuroneko.
    My expected framerate is about six times faster as i have now with that code. Although I think to pass that code to pasm, it's a nightmare to do that. :(
    @Mark_T
    Look that, we can name it "my variable" is a string (120 chars in the sample) that I need to shift in portions of 10 chars... I think in use longs, but is not clear for me how, because the "fonts" are bytes... :(
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-07-12 12:46
    six times faster as now but how many frames per second is that?
  • BTXBTX Posts: 674
    edited 2011-07-12 13:27
    Hi StefanL38
    My display is 10 chars wide of 8 pix each, by 8 lines, and I'm multiplexing it at arround 500-550Hz, then, I want to scroll horizontally the text at about 10 chars/seccond.
    As I load an array with the data to show in an "instant" in the display, I should load that array at about 10 times/sec, well, as my array is 80 byte large, I should get about 800 bytes/sec of proccesing speed.
    If I'm not wrong, the frame rate doesn't matter in this case, since I can refresh my display at 500Hz, and what only I want, is to scroll the text at a lower speed. My ScrollH rutine is so slow for that.
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-07-13 01:53
    OK so I'm throwing in my ideas:

    if I understand right you want to move the characters pixelwise.
    There is a character-definition and each character has 8x8 pixels.
    Now if the character should move pixelwise the bit-columms have to move just one pixel.

    I think such operations are predestinated for bitwise bitshifting. You have some kind of representation in the RAM for each pixel.
    Now all bits have to be shifted to the right or to the left and if a character reaches a border the character will vanish bitcolumm-wise
    and on the other side a new character appears bit-colum-wise.

    The bitshifting itself is quite easy. If you can do it with one long (=32 bit) next step is to do it with 10 * 8 * 8 / 32 = 20 longs
    and repeat that for all eight bit-rows.

    A vanishing character is easy.
    I think therefore you use a shiftoperator where the MSB or the LSB just drops (instead of beeing shifted in on the other end)
    shifting in a new character can be done through
    copying basic definition of the character,
    zeroing all bit-columms that are not needed for the next operation (through and AND-operation with only the relevant bit set to 1)
    shifting the remaining bit-columm to the LSB or MSB-position (depending on the direction) and OR-ing these values with the current buffer that represents the actual on/off of the LEDs to show the characters.

    If you haven't done anything with bitshifting yet. This is the right moment to do so
    keep the questions coming
    best regards

    Stefan
  • BTXBTX Posts: 674
    edited 2011-07-13 09:17
    Hi Stefan.
    I was thinking in that at first, but I can't found an easy way to shift it correctly.
    It's not clear for me what you explain, if I've a line like this: (please suppose a byte intead long to write less here)
    "a":=00001111 and the next char begins with "b":=11000000 so my line is:"c":= 0000111111000000, when I shift the first byte I've 00011110 and my2nd byte as 10000000, How to get "c" shifted by one, after both shifts ??
  • kuronekokuroneko Posts: 3,623
    edited 2011-07-14 18:40
    Some Q&D version of a 80(96)x8 bit scroller using a modified FDS as a display. The (speed) limiting factor is the display routine. Just widen your PST display so that it can show 96 characters.
  • BTXBTX Posts: 674
    edited 2011-07-15 07:02
    Hey Marko thx so much !!!!! I'll try this ....
    Have a nice weekend for everybody !!
Sign In or Register to comment.