Shop OBEX P1 Docs P2 Docs Learn Events
More PBASIC to Spin questions — Parallax Forums

More PBASIC to Spin questions

GenetixGenetix Posts: 1,754
edited 2014-07-10 19:27 in Propeller 1
WAM 3.0: Chapter 6, Activity #4 (p. 189) - Dial Display

LOOKDOWN time, <= [40, 150, 275, 400, 550, 800], index

Apparently PBASIC allows comparison operations in LOOKDOWN while Spin doesn't so how would I do this?



Also, I would like to imitate FREQOUT (Chapter 8) using 2 frequencies.
I am thinking of having Counter A and B use the same APIN at the same time but the Propeller manual doesn't mention what will happen.

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-07-09 00:42
    I don't know if this can be done with a lookdown command in Spin. I usually forget to use use the lookdown command.

    Here are three different ways to work around this. I have a hard time believing there isn't a better way.
    CON ' timing constants
    
      _clkmode = xtal1 + pll16x 
      _xinfreq = 5_000_000
    
    
      DEBUG_BAUD = 115_200
    
    
      MAX_TEST_INDEX = 8
      TEST_DATA = MAX_TEST_INDEX + 1
        
    OBJ 
    
    
      Pst : "Parallax Serial Terminal"
     
    PUB Setup
    
    
      Pst.Start(DEBUG_BAUD)
    
    
      repeat
        Pst.str(string(13, "Press any key to start."))
        waitcnt(clkfreq / 2 + cnt)
        result := Pst.RxCount
      until result
    
    
      Main
      
    PUB Main 
    
    
      repeat result from 0 to MAX_TEST_INDEX
        Pst.str(string(13, "time = "))
        Pst.dec(testData[result])
        Pst.str(string(", index from case = "))
        Pst.dec(FindIndexCase(testData[result]))
        Pst.str(string(", if = "))
        Pst.dec(FindIndexIf(testData[result]))
        Pst.str(string(", dat = "))
        Pst.dec(FindIndexDat(testData[result]))
        
      Pst.str(string(13, "Program over."))
      repeat
        
    PUB FindIndexCase(time) : index
    
    
      case time
        0..40:
          index := 1
        41..150:
          index := 2
        151..275:
          index := 3
        276..400:
          index := 4
        401..550:
          index := 5
        551..800:
          index := 6
        other:
          index := 7' or whichever number you want
    
    
    PUB FindIndexIf(time) : index
    
    
      if time =< 40
        index := 1
      elseif time =< 150
        index := 2
      elseif time =< 275
        index := 3
      elseif time =< 400
        index := 4
      elseif time =< 550
        index := 5
      elseif time =< 800
        index := 6
      else
        index := 7' or whichever number you want
    
    
    PUB FindIndexDat(time) : index
    
    
      repeat until index == 6 or time =< lookDownTable[index++]
    
    
    DAT
      lookDownTable         long 40, 150, 275, 400, 550, 800
    
    
      testData              long 1, 39, 40, 41, 153, 350, 444, 600, 1000
    

    None of the methods are as simple as the PBASIC technique.

    Maybe someone will have a better solution.

    This is the output from the above code.
    Press any key to start.Press any key to start.
    time = 1, index from case = 1, if = 1, dat = 1
    time = 39, index from case = 1, if = 1, dat = 1
    time = 40, index from case = 1, if = 1, dat = 1
    time = 41, index from case = 2, if = 2, dat = 2
    time = 153, index from case = 3, if = 3, dat = 3
    time = 350, index from case = 4, if = 4, dat = 4
    time = 444, index from case = 5, if = 5, dat = 5
    time = 600, index from case = 6, if = 6, dat = 6
    time = 1000, index from case = 7, if = 7, dat = 7
    Program over.
    

    I'm not sure if time is over 800 if the index is supposed to be zero or seven. I assumed seven. The code would need to changed if the index were supposed be zero when time is over 800.

    As with most computer languages, there is often more than one way to accomplish a task in Spin.

    There's some good information about counters in the PEK (Propeller Education Kit) available through the "Help" menu of the Propeller Tool. I don't know the answer to your counter question myself.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-07-09 09:37
    You could do that particular case with something like this...
    [SIZE=1][FONT=courier new]PUB lookLessEq(inputValue,value0,value1,value2,value3,value4,value5) | idx
       repeat result from 0 to 5
         if inputValue =< value0[idx]
           quit   ' exit repeat early
         result := 6  ' if not satisfied in list
    [/FONT][/SIZE]
    
    It could also be done with a pointer to the list in DAT, along with how many items are in the list, and even a parameter to indicate what comparison operation to perform.


    Freqout on the Stamp is constructed using duty mode. The sine values for the two frequencies at each point in time are computed and summed, and that sets the instantaneous duty cycle. On the Prop, for anything but very low frequencies you would have to use PASM to do the sines and transfer them to a counter operating in duty mode. I don't think simple overlapping of two NCO mode ctra and ctrb would give you satisfactory results. The overlap is wired-or. On the other hand, if you direct the NCO mode output to two different pins, resistors can be used to analog sum NCO outputs.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-07-09 09:53
    LOOKDOWN is simply a series of tests that work through a list until the first good match is found.
    LOOKUP is the same, but it would start at the opposite end of the list and work in the opposite direction.

    So I suppose in SPIN, you would have an array of values, and just keep walking the array until you find the right fit. This would usually be paired with another address to jump to or another value to plug in somewhere.

    Tracy Allen provided the SPIN code above, but this is also very easy to do in PASM. As I mentioned before, if you can get to the generic concept, you can easily manage to get the same results in any language.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-07-09 10:11
    I like Tracy's idea of using a pointer.

    Here's my version using a pointer. It's just a small variation on the "Dat" method.
    PUB Main 
    
      repeat result from 0 to MAX_TEST_INDEX
        Pst.str(string(13, "time = "))
        Pst.dec(testData[result])
        Pst.str(string(", index from ptr = "))
        Pst.dec(FindIndexPtr(testData[result], @lookDownTable, 6))
        
      Pst.str(string(13, "Program over."))
      repeat
    
    
    PUB FindIndexPtr(time, tablePtr, tableSize) : index
    
    
      repeat until index == tableSize or time =< long[tablePtr][index++]
    
    
    DAT
      lookDownTable         long 40, 150, 275, 400, 550, 800
    
    
      testData              long 1, 39, 40, 41, 153, 350, 444, 600, 1000
    

    Does Lookdown return an index starting at one or zero? I've been assuming it starts the index at one.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-07-09 10:58
    On the Stamp, the result index is zero-based. And if the target condition is not found in the list, the result variable keeps whatever value it had going in. So more work to duplicate that behavior in a Spin method. Stamp variables are few, and all global.
  • GenetixGenetix Posts: 1,754
    edited 2014-07-09 15:55
    Thanks guys for the solutions. Considering how much more powerful the Propeller is than the Stamp I am still amazed at how powerful many of the Stamp commands are.

    I forgot the Stamp outputs a PWM signal that gets filtered into a sine wave when you use FREQOUT.



    I came into 3 more issues.

    The DCD command - Returns the value of the highest set bit (Chapter 8 - Activity #4-5, used to determine the octave change)
    Given the way the Propeller counters work I would either need the add the PEK routine for determined the FRQx constant or have a large table with all the values.

    I don't see a PST (Parallax Serial Terminal) equivalent for DEBUG DEC#.

    I am not sure about this one, also from Ch. 8, #4-5.
    The Notes are stored in DATA statements and letters (in quotes and separated by commas).
    The note is read into a variable and then printed (DEBUG variable_name).
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-07-09 19:11
    I would suggest you be a little careful with your translations -- if you get too literal you'll just end up hand-cuffing the Propeller with the limited features of the BASIC Stamp (this is why I have never used the BS2 object, and I strongly suggest that it be avoided). The great fun in coding is adding features that we like elsewhere.

    I use an updated version of FullDuplexSerial that has a method called rjdec (right-justified decimal). I do a lot of formatted display so this is useful. Note, too, that you can select the leading pad character.
    pub rjdec(val, width, pchar) | tmpval, pad
    
    '' Print right-justified decimal value
    '' -- val is value to print
    '' -- width is width of (padded) field for value
    '' -- pchar is [leading] pad character (usually "0" or " ")
    
    '  Original code by Dave Hein
    '  Added (with modifications) to FDS by Jon McPhalen
    
      if (val => 0)                                                 ' if positive
        tmpval := val                                               '  copy value
        pad := width - 1                                            '  make room for 1 digit
      else
        if (val == NEGX)                                            '  if max negative
          tmpval := POSX                                            '    use max positive for width
        else                                                        '  else
          tmpval := -val                                            '    make positive
        pad := width - 2                                            '  make room for sign and 1 digit
    
      repeat while (tmpval => 10)                                   ' adjust pad for value width > 1
        pad--
        tmpval /= 10
    
      repeat pad                                                    ' print pad
        tx(pchar)
    
      dec(val)                                                      ' print value
    
  • kuronekokuroneko Posts: 3,623
    edited 2014-07-09 19:30
    JonnyMac wrote: »
    Here's a bit of code that handles DCD the way the Propeller should: it returns the position of the highest set bit (31..0), or -1 if no bits are set.
    pub dcd(value) | pos
    
    '' Returns value of highest bit set
    '' -- 0..31
    '' -- returns 0 if no bits set
    
      pos := -1                                                     ' no bits set
    
      if (value <> 0)                                               ' if bits
        pos := 31                                                   ' start with msb
        repeat 31
          if (value & (1 << 31))                                    ' if msb = 1
            quit                                                    '  we found it
          else
            value <<= 1                                             ' check next bit
            --pos                                                   ' update position
    
      return pos
    
    Shouldn't you be using the >| operator for this? Besides this methods seems to return -1 when no bit is set (comment still says 0).
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-07-09 19:41
    I'm going to delete that post and crack the manual open -- I don't tend to use the special operator so I just probably re-familiarize myself with them.

    And look what I found in my own template!
    pub bit_pos(value, mode)
    
    '' Returns position of 1st "1" bit
    '' -- mode 0 (LSBFIRST) to scan from lsb, mode 1 (MSBFIRST) to scan from msb 
    '' -- -1 = no bits set
    
      if (value == 0)                                               ' if no bits                                   
        return -1                                                   '  return -1
    
      else
        if (mode == LSBFIRST)                                       ' check from LSB
          value ><= 32                                              '  flip for >|
          return (32 - >|value)
        else
          return (>|value - 1)
    
  • GenetixGenetix Posts: 1,754
    edited 2014-07-10 00:16
    Jon, I have not used any of the Stamp objects because I want to learn how the Propeller works and how to use Spin. Some commands translate easily but for a few there is not equivalent. I know of no PBASIC to Spin chart so I am creating one myself.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-07-10 11:23
    Well done! Not that it matters, but I think that's an excellent attitude and you'll be a better programmer for it. In the end, it's all bits whizzing around on the inside of the chip, anyway; the presentation on the outside world (HLL) is for humans.

    I trust you're enjoying the Propeller and will even more as you get comfortable with it.

    Once you're very comfortable with Spin, you'll be able to translate projects for a variety of devices.
  • GenetixGenetix Posts: 1,754
    edited 2014-07-10 15:23
    Moving from the BS2 to the Propeller, I love Spin but I've also realized how powerful PBASIC is. Chip is the man!!! To unlock the real power of the Propeller though I need to use Assembly and I plan on doing that next. The only frustrating thing is that there are few books on the Propeller and the Manual is often vague. I want to later convert other BS2 code to Spin for the other Stamps-in-Class texts.


    Geeze, I feel stupid. I just looked at the DCD command in the BASIC Stamp manual and realized how simple it is. It takes in a Nibble (0-15) and outputs 2^N. That is same as Shifting 1 by N places. 1 line of code (assuming the number is in the valid range).
    Result = DCD input_value ---> Result := 1 << input_value

    Funny considering shifts have always been baffling to me.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-07-10 19:27
    Shifting is good -- always very useful.

    Tip 1: Shifting left is a faster way to multiply by a power of 2 (2, 4, 8, 16....)
    Tip 2: Shifting right is a faster way to divide by a power of 2
    Tip 3: You can use shifting to divide negative numbers in Spin using the ~> operator ( instead of >> )

    There are assembly versions of these operators << is shl, >> is shr, ~> is sar.

    The Propeller also does rotating which can be very powerful.
Sign In or Register to comment.