More PBASIC to Spin questions
Genetix
Posts: 1,774
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.
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
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, 1000None 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.
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.
[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.
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.
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, 1000Does Lookdown return an index starting at one or zero? I've been assuming it starts the index at one.
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).
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 valueAnd 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)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.
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.
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.