How do I understand the program flow of a Spin application
garyg
Posts: 420
Hi
I've been doing the Spin programming Tutorial available in the help menue of the Propeller Tool V1.3.2
I've completed 7 lessons.
Now I'm attempting to understand exactly how the programs flow together.
When looking at different programs, I cannot follow program references and variables in spin.
I can follow programs written in PBasic from start to finish.
When I attempt to follow any Spin programs, I cannot see how the various Spin Objects are exactly tied together.
I've even attempted to look at all of the Object files pertaining to an application, but cannot exactly see the link.
Sorry if I'm being vague here, I'm just at the start of trying to understanding Spin.
ANY comments or suggestions would be appreciated.
I've been doing the Spin programming Tutorial available in the help menue of the Propeller Tool V1.3.2
I've completed 7 lessons.
Now I'm attempting to understand exactly how the programs flow together.
When looking at different programs, I cannot follow program references and variables in spin.
I can follow programs written in PBasic from start to finish.
When I attempt to follow any Spin programs, I cannot see how the various Spin Objects are exactly tied together.
I've even attempted to look at all of the Object files pertaining to an application, but cannot exactly see the link.
Sorry if I'm being vague here, I'm just at the start of trying to understanding Spin.
ANY comments or suggestions would be appreciated.
Comments
Really, the only funky stuff starts happening when you see a "cognew" in the software. This is where a second set of instructions can start being executed simultaneously with the first set.
You are being vague. A specific example that confuses you would be helpful so we can break it down for you.
That's where the editor feature of showing what's linked together is very handy.
The code in your spin main program and its PUBlic and PRIvate blocks are how the objects are tied together. The objects themselves are not really much different from a subroutine in any other language except for being run on a separate cpu (cog) if necessary, and of course that the cog could be running a PASM program or the spin interpreter.
Think of the objects as a black box of hardware or software that performs a specific function and requires a specific format for it's commands and data.
So far, it would appear to me that:
ADC_INPUT_example.spin - is the main program.
FullDuplexSerial.spin - is sort of like a subroutine of the ADC_INPUT_example program.
ADC_INPUT_DRIVER.spin - is sort of like another subroutine of the ADC_INPUT_example program.
I'll attempt to follow this program as printed to see if I can follow it.
I'm sure I'll have many questions.
Thanks to all of you for your help so far!
Yes, it performs the serial I/O function to display the results on the computer that the main program requests by the DEBUG statements.
Yes, it controls the ADC chip and performs the functions the main program requests by the ADC statements.
At the beginning of the ADC_INPUT_example.spin
There is this line:
PUB start (DTPin, INPin, CLKPin, RSPin, CHCount, ActChannels, BitCount, SingDiff, FastMode)
Where or How are these things defined?
For example, DTPin - I don't see what this is.
I've looked for it in all 3 programs and cannot see references to anything, or a redifinition of something like LONG ck_pin.
I feel like I'm somewhat understanding but I get lost on this very first part of the code.
Any comments, suggestions, or references would be appreciated.
I'll use my previous line:
PUB start (DTPin, INPin, CLKPin, RSPin, CHCount, ActChannels, BitCount, SingDiff, FastMode)
In order to use an object like this would I need to edit the line to something like this?
PUB start (DTPin, INPin, CLKPin, RSPin, CHCount, ActChannels, BitCount, SingDiff, 0,1,2,3,8,8,16,1, False)
It's all a bit to wrap your head around these things when they are new. In time it will all be second nature. Many of us that have been programming for years take so much of this for granted, we forgot how hard it was to learn our first couple languages. Especially when we are trying to teach ourselves. But in my opinion, that is the better way to learn. You make many more mistakes which solidifies concepts others don't catch if they are just "told" how to program.
Keep the questions coming. There are many people on this forum ready and willing to help.
When I started there were symbols being used in the code that just didn't make sense to me at all.
I really didn't understand the structure of spin I had rough ideas about what this and that did and still do but I fell across the PE Kit Lab documents and read them and things started to fall in place, like what does ++ or ~ mean and how a method calls upon another to get a result and all of a sudden I could delve into code and start to make some sense of it. I found the main propeller manual wasn't as helpful as the PE Kit Labs which explains line for line what's going on.
I've still got a long long way to go, but encouragingly I have managed to adapt and play around with other peoples code and get results.
A few months ago I was looking at giving up with spin and going back to PBasic but I'd say persevere and all of a sudden things will start to click.
Do read the PE kit docs as they have helped me a great deal.
One thing don't get too carried away at first, take your time to learn a certain thing first and understand it before moving on, there will be things you read and later forget, we are all human, but things will start to stick in your mind and you will do things a certain way automatically.
Any way good luck and hope you find it as enjoyable as i am at the moment.
PASM is another beast entirely.
'' DTPin: outgoing (from µController) serial data pin (0-31); ignored if 1-channel ADC
'' INPin: incoming (to µController) serial data pin (0-31)
'' ClkPin: serial clock pin (0-31)
'' RSPin: reset, CS pin (0-31)
'' ChCount: Number of channels on ADC (8 = 3208/3008; 4 = 3204/3004; 2 = 3202/3002; 1 = 3201/3001)
'' ActChannels: number of channels to scan (1-8)
'' BitCount: number of bits the ADC outputs (2-16)
'' SingDiff: ADC single or differential mode (1 = single, 0 = differential)
'' FastMode: Set driver to faster communication. Fast mode may excede specifications of ADC. (True/False)
Either way, it is not an easy object to understand.
As the latter posts have pointed out this is one of the more complicated drivers to use and understand since it supports 8 ADC chips. Fortunately you do not have to understand how the driver works to make use of it. All you really need to understand is the function of each of the parameters that the object needs and Bobb Fwed has posted that. If you want to understand how objects receive and use the parameters that are passed to them you may want to start with a simpler object. Even the full duplex serial object would be simpler than this driver and it is far from the simplest one.
In this example, blinkLED, a function which takes input values for which pin to use, how many times to blink, and how long to wait between blinks, is run and told to blink pin 0 10 times with a 200ms delay between toggles.
Something roughly equivalent to the above but in PBASIC would be (this might be wrong, I haven't used PBASIC in ages...):
The advantage of blinkLED(pin,times,delay) over pin=0:times=10:delay=200:GOSUB blinkLED is that the variables pin, times, and delay aren't wasting memory when not in use. They only exist when blinkLED is called and are created when the parameters are specified and deleted when blinkLED returns control to start. Yes, there are ways around the memory waste in PBASIC, but it's a headache when you have lots of variables. This functionname(parameter 1, parameter 2, ...) notation is very common, and is used in almost all non-BASIC languages that I know of. Another advantage of this is that you don't have to worry about having a million different for loop iterator variables (like the i in my example) and making sure that you don't have for loops calling subroutines that try using the same variable for their own for loops - every function can have its own i variable. In my spin example, the "...,delay) | i" is where i is defined.
Hope I helped,
electrodude
I think that is one of the key points that took me a while to understand and what makes the Prop chip so brilliant.
Let's say you write a little subroutine that takes a string of letters and turns them into capitals. You can publish that and others will find it very useful.
Let's now say you want to publish ten of those routines, all of which do similar things. This isn't a 'program' as such as it won't run, but it is a useful collection of routines. We could call that an 'object'. It is a convenient way to group subroutines together, and it is the way things are published on the Propeller Object Exchange http://obex.parallax.com/
The key is you don't really need to understand how all those routines work in order to use them.
Ok, let's say our ten subroutines all have a common variable that they want to use. It might be something like the size of the screen, or which pin we are using to flash a led. So the first thing one usually does with an object is pass it a list of variables. In your example in post #10, there are nine variables. You don't have to worry about what the object does with those variables - that is up to the boffin who wrote the code, but in general terms, these variables are stored somewhere, probably in a global variable list and then all of the subroutines in the object can use them.
This saves passing lots of variables each time you call a subroutine. The object keeps those variables internally.
Most of these 'start' subroutines have 'start' in the name or something similar. (subroutine, method, function = same thing really).
One thing that took me ages to work out is how to quickly find out what an object can do. So if you load up an object (which is just a text file really), into the propeller tool program, and look along the top of the screen there are some radio buttons you can click to 'condense' the code. In the most condensed version, only the first line of each subroutine shows. So for a string handling object, you can get a quick overview that this object has a 'start' routine, and one to convert to capitals, and to trim spaces, and take the leftmost characters etc.
Here's another thing. The subroutines you can use start with PUB because they are PUBLIC. There are internal routines that the object might use that are called PRI, and you don't need to worry about those. So you can simplify what an object does even further by condensing the code, and then looking at the PUB routines. Sometimes an object only comes to a few lines of code. Much easier to understand then.
Re using objects, generally you would not need to edit the code. In old-school speak, the rule was 'you touch it, you own it'. Including tech support questions *grin*.
So using Spin is a bit like Lego. Grab the objects you need, include them in your program and all you have to do is write the glue code. Extreme example - I once needed a movie player. I found an object that could access data from an SD card. I found another object that did the display. My actual code was less than ten lines long. And I still have no idea how most of the code in those objects worked.
Re your example
To use this in your code you would write
You need to add a line of code in the OBJ section of your code to tell it to link the name "adc" with the actual file name of the object. Usually your name is shorter so it is easier to type. Every subroutine in that object can now be used by typing adc. and then the subroutine name.
I think I'm actually learning something.
Post#2,Post#3 and Post#5 comments reinforced lessons learned from the Spin Tutorial.
By the time I got to Post#10, I felt like I was starting to understand somewhat that the Parameters for
an object needed to be edited in some manner in order to be called by a main program that I may write.
I will read the PE Kit Lab documents
I had noticed the Parameters explained in the notation of the program as in post #15,
I figured that, In my main program, that I would need to actually edit the parameters to fit the particular ADC that
I would be using.
In Post #19, the adc.start (0,1,2,3,8,8,16,1, False) is actually what I was attempting to understand.
I've printed and highlighted sections of this thread.
I'll study a number of examples and attempt to find some simple Objects on the OBEX that I can tye together.
Thanks to all.
I'm sure I will have more questions in the near future.