Porting Spin Program from Propeller 1 to Propeller 2
jcfjr
Posts: 74
in Propeller 2
I have a 1000 line Spin/PASM program running on a Propeller 1. Will the same program load and run unaltered on a Propeller 2?
Comments
No
I've been porting a bunch of code from Propeller 1 to Propeller 2. It's been harder than I thought it would be but it keeps getting better as I learn more and as useful objects are created for the Propeller 2.
I was a bit surprised last week when I worked on a Propeller 1 project and I found myself missing some of the new Propeller 2 features.
Make sure to ask questions if you get stuck. People on the forum have been very helpful with my efforts.
There's probably a better P2 list somewhere but here are a few links I keep handy.
Make sure to set any Google Doc to "View" so you don't accidently make unwanted edits. (It only took me two unwanted edits to learn this lesson.)
Main P2 Document
Evaluation Board B
Spin2
Evaluation Board C Product Page
Github Example Programs
Parallax Propeller 2 (PASM) Instructions
I also find JonnyMac's cheat sheet of P1 and P2 operator differences very useful.
I don't understand why all the changes from Spin1 to Spin2 were made but I trust Chip had good reasons to make the changes he did.
One thing which surprised me recently was to learn longs now longer need start on a multiple of 4 in RAM. I initially thought I had an error in my code when I printed out RAM addresses for various variables and some long addresses were odd numbers.
If your code is mostly Spin1 (with little or no PASM) then FlexSpin may be able to compile it for the P2 -- FlexSpin can handle both Spin1 files (with a .spin extension) and Spin2 files (with a .spin2 extension). However, it doesn't do any translation of the PASM parts of the Spin files, so that you'll have to do by hand. There's a limited subset of PASM that works on both P1 and P2, but for the most part the assembly languages are quite different.
I was porting a P1 object to the P2 yesterday. Things to remember:
Thank you for all the input. The main program is all SPIN, but I run three objects in different cogs that are from OBEX and written in PASM1. I know nothing about assembly programming, and every time I think I will try to learn, I give up in a couple days. Do you know of any good starter manuals for PASM? Now that the old OBEX site has moved to GitHub, I can't find anything. Where can I find objects written for the P2? Are there any conversion programs for PASM1 to PASM2? I have a P2 arriving tomorrow, but unless I can find more resources, I doubt I will be able to move up to it.
What objects are you running that use PASM1? Maybe there are suitable P2 replacements.
I use the following objects that all have PASM in them.
fMath : "F32_1_6" 'Fast floating point math cog
PST : "Parallax Serial Terminal" 'used for comments to debug cog
LcdSerial : "FullDuplexSerialPlus" 'Communicate with display cog
MCP3202 : "MCP3202" 'ADC for measuring fwd/ref voltage cog
Encoder : "MultiQuadEncoder" 'Reading encoders input cog
I cannot even find these on line now.
Can you post a test program and those objects so that we can assist?
Notes:
-- I think OzPropDev ported a P1 FP library to the P2
-- My version of FDS has features that you could use for debugging, or you could use the P2 DEBUG statement (if running Windows)
-- the LCD may be able to use my FDS as well; it has richer formatting features
-- The P2 has analog input that will work for 3.3 and lower
-- the P2 has a smart pin mode for quadrature encoders -- I have an object.
I just spent probably six months porting my program/design from a Basic stamp to the P1. I essentially ended up rewriting all my code by the time it was running. The time was worth it, I learned a lot about Spin, and my antenna tuner runs 6 times faster. It appears that I may be getting myself into another total rewrite. My main program is all Spin1, so I am hoping that converting it is not that big of a challenge. But PASM has always scared me and I have never really learned it. So if I need to rewrite these PASM objects, I need to learn PASM1, as well as PASM2. Or find Objects that already have been ported to P2. I am just evaluating if I want to undertake this project, and if I am even capable.
-- Where can I find OzPropDev FP library?
--Yes, I could use either to replace PST
--Communications with display(4D Systems Touchscreen) is simply sending/receiving commands through serial port
WriteObjValue($0F,$03,Frequency2) 'Write frequency to display
PUB WriteObjValue(ObjectId,ObjectIndex,Value) 'Sets the value of a displayed GUI object
SendByte(CmdWriteValue) 'Byte 1 is command byte 'CmdReadValue'
SendByte(ObjectID) 'Byte 2 is ObjectID
SendByte(ObjectIndex) 'Byte 3 is Object Index
Sendbyte(Value>>8) 'Byte 4 is value upper byte
SendByte(Value & $FF) 'Byte 5 is value lower byte
SendChksum 'Byte 6 is calculated checksum, of previous bytes
waitcnt(50000 + cnt)
return RtnBlnAck 'Look for ACK NAK response, and return as boolean..
'False=NAK, True = ACK
--Unfortunately, all my hardware is designed around 5v, so will still need to use the 3202
I don't have a test program for the MCP3202 ADC, but it is probably pretty generic. I use the P1 to repeat a loop that reads two channels, and then averages 50 readings per channel. Quicker than using 3202 to calculate an average!
--I have attached two of the objects that have PASM in them, as well as the demo objects .
I am using the multquadencoder Object to monitor three quad encoders. This Object basically monitors encoder which simply presents a number. I use the number to determine if it has changed +/-, and if so, turn a stepper motor in correct direction.
If you think I can get around converting the PASM by using some new features offered in the P2, I would appreciate your input.
Do you know of any good tutorials on learning PASM programming?
Will my old Prop Plug I used on the P1 work with the P2. Mine is not latest Rev E.
Have a look at this simple demo for the encoder and motor. In this case I am only doing one, just so you can clearly see how things work. The P2 encoder object uses a smart pin mode, hence no cog is required. You can have as many of these as you like (objects can be arrayed, though I don't do that often). You'll also see that the pulsout() method is much cleaner in the P2 than the P1.
Suggestion: Be mindful of your formatting; messy formatting can lead to confusion and hide bugs. I'll have look at your 3202 code, though I have my own P1 object that I can translate for you.
I am working with Chip Gracey on his version which uses inline assembly (big speed, no cog). You'll have to search for Brian's port -- I don't know where it is, just that it exists.
P1 v P2 pasm differences really depends on what hardware you’re directly referencing.
As always, plenty of help on these forums.
I found it thanks to the clues left by JonnyMac.
Here's the link.
I need the object for my project so I thought I'd save you from performing the same search I just completed.
Okay, I translated my MCP3202 code to the P2 using inline PASM2 instead of a cog. After you have it setup you can use the startx() method and built-in mux constants to read the channels. Since you're running it at 5v, do put a 4.7K series resistor in the MISO line.
Warning: I couldn't find an MCP3202 to test with, so this code is not tested.
Updated 16 MAR 2021 -- small clean-up.
Thank you JonnyMac. I just got my P2 today, but discovered I needed the new Prop Rev E to work with the P2. I have ordered, and when I get it, I will try your code with a 3202.
Is Spin2 as fast as PASM1? Is there an advantage to using PASM2? Is there a speed advantage to inline PASM2 vs running the object on a separate cog?
I also looked at OzPropDev FP library, and noticed that it did not have the code to calculate powers, something I need in my program.
I understand that the P2 can run Basic mixed in with the Spin. I remember reading a thread that stated it would be easier to use Basic than a floating point object, but I need to find that thread again. Maybe I can use Basic for my floating point.
Thanks for the info, a lot to absorb!
Where can I find documentation that I can understand the differences? I have the P1 documentation for PASM1, but only can find the list of PASM2 that doesn't really go into enough info for me to understand.
Thank you Duane!
I just noticed this myself. I just need integer powers of ten to convert scientific notation to a float so I whipped this up.
Of course this doesn't help if you need fractional exponents. If this isn't enough make sure you let us know. Someone (maybe even myself) might take a crack at writing a proper power method.
By the way, I haven't tested the above code yet. It seems too simple to fail but I thought I'd warn you.
Duane thanks, but unfortunately the power is usually a fraction(x) between .3 and .5, so something like fmath.Pow(10.0,x).
I spent a few hours yesterday trying to convert F32 to PASM2. I can't get it to fit in the new smaller cog. I'm not sure I'm ready to dive into the execution from hub but I might try converting the PASM sections to inline PASM using Spin2.
If anyone else if working on a floating point object, I hope they let us know. I'd hate to spend time making an inferior object to one already in the works.
Here is the float code from Catalina:
https://forums.parallax.com/discussion/comment/1497474/#Comment_1497474
But I think a float object should not use its own cog on P2, we have inline assembly and cogexec for such blocking PASM code. Unfortunatly many just port objects from P1 one to one without thinking about the new possibilities. On P1 it was necessary to start a new cog for PASM routines, that's not the case for P2.
Andy
I'm giving this a try. I hope you and others make suggestions of how it could be done better. Thanks for the link to the Catalina code.
I tried writing a method to convert an integer to a floating point number using my attempt to translate code from F32. I failed.
I tried again using the Catalina code as a starting point and IT WORKED!
Thanks again for the link Andy.
@jcfjr I think there's a good chance we'll have a full featured floating point object in the near future.
Edit: Right after posting this reply, I saw this post from @ersmith. I haven't looked at the code yet but it's good to know there's someone else working on this. I've very excited about the 64-bit feature.
Duane,
I got my P2, but it was damaged, so still waiting. I noticed that @ersmith code does have Powers function. The code is only the PASM, w/o a Spin2 shell. At first glance, not sure how to call these functions from main program.
How could I keep track of progress of any floating point objects for the P2? It seems that everything mentioned in this thread are not on GitHub, or at least I cant find them.
That's not my code, my code doesn't have Pow() yet but does have Spin2 wrappers for everything.
You could follow the thread Floating point routines 64 and 32 bit for p2. The first post has 3 different floating point objects. They're still works in progress, but I'll update the thread from time to time, and when they're complete I'll post them on GitHub.
If you need floating point in the meantime, the C compilers for the P2 (FlexProp, Catalina, riscvp2 at least) have pretty complete floating point support. So does the BASIC compiler built in to FlexProp. In fact BASIC has a built in power operator, so the program:
prints 2.8284, i.e. the square root of 8.
Jon,
Finally got my P2 Edge card and am ready to test it with a 3202 and the code you supplied earlier in this thread.
I am struggling with understanding where the pin assignments are coming from
How have you associated
SF_CS = 61 { O } '3202 pin numbers
SF_SCK = 60 { O }
SF_SDO = 59 { O }
SF_SDI = 58 { I }
into the start object
pinh(cs) ' initialize pins
pinl(sck)
pinl(mosi)
pinclear(miso)
I see the longmove that moves cspin (start input parameter) into cs, I think.
But how does pinl(sck) know that sck is pin 60?
These pins:
... are used by the Propeller for programming/debugging and the serial flash. Your MCP3202 can share three of the four pins used by the flash; you'll need a separate chip select. In your app, then, you might do this:
Note that my pin naming convention is subsystem __ p2function; that is to say the the pin names in my code reflect what's happening on the Propeller side.
To instantiate the object you would do:
The longmove (which should be 4 longs, not 5) copies the pin numbers passed through the start() method to the object global variables. From there, we can use them at any place in the object.
I did a small clean-up of the file; see original post with code for update of the object.
Jon,
I am familiar with starting an object in another cog in the P1
OBJ
MCP3202 : "MCP3202"
MCP3202.start(dataio, clk, cs, %0011)
But I am not familiar with inline PASM, so do I still have to define your code as the Object i.e. ADC, and write shell object that starts readings
OBJ
ADC : " jm_at24c32"
Pub Main
adc.start(ADC_CS, ADC_SCK, ADC_SDO, ADC_SDI)
a = adc.read(0,0)
b = adc.read(1,0)
I also don't understand how the input parameters in start( cspin, sckpin, misopin, etc. get stripped of the pin and become pinh(cs) and pinl(sck) and pinclear(miso)
Regards,
Jim
Gotcha -- I misunderstood your question.
The start() method gets the pins for the device from the parent and stores them as object global variables. It also sets up the pins. The problem is that we cannot use object global variables directly in the inline pasm code. Have a look at the shiftout() method.
Notice the local variables clk, do, di, tix. The longmove() in this method copies four of the object globals to these locals. The parameters (value, bits) and locals (clk, do, di, tix) and code are copied into the low addresses of the interpreter cog ram and executed. When finished, the parameters and local variables are updated -- though we don't need that here.
We do with shiftin(), however, as it has a return value. With this method, the result variable is passed to the cog and the modified vision comes back which gets returned to the caller.
Jon,
Thanks for the explanation, I think I understand how the pins get assigned. But I still don't understand how to run your code on a P2 within the one cog. Do I make your code an Object like for P1 i.e.
OBJ
ADC : " jm_at24c32"
Pub Main
adc.start(ADC_CS, ADC_SCK, ADC_SDO, ADC_SDI)
a = adc.read(0,0)
b = adc.read(1,0)
But this would start your code on another cog I think.