Shop OBEX P1 Docs P2 Docs Learn Events
How do I understand the program flow of a Spin application — Parallax Forums

How do I understand the program flow of a Spin application

garyggaryg Posts: 420
edited 2013-03-29 10:11 in Propeller 1
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.

Comments

  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2013-03-27 15:55
    SPIN works like any other language, and starts from the first instruction at the top and works its way down. When an instruction references a secondary object, it starts at the top of that method call and works its way to the end, then returns back to where it came from. This is true for all method (AKA function) calls, whether it is in a different object, or in the same one. Imagine, all methods are called with a GOSUB command, and at the bottom is a RETURN (as many methods have anyway).

    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.
  • skylightskylight Posts: 1,915
    edited 2013-03-27 16:22
    One thing that took me a while to grip was the indentation of the code, when I'm trying out different things I quickly hit the F10 or F11 button to load the program code onto the propellor then wonder why it hasn't worked when it did before only to find the added line of code wasn't indented far enough and attached itself to code above and not to the part it was intended for.
    That's where the editor feature of showing what's linked together is very handy.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2013-03-27 16:28
    True, forgot about that (that is very important). SPIN is kind of a rarity with its need for absolutely correct formatting. Most other languages ignore practically all white space, and formatting is only for readability (as with PBASIC I do believe).
  • kwinnkwinn Posts: 8,697
    edited 2013-03-27 18:52
    garyg wrote: »
    Hi .......

    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.
    .............

    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.
  • garyggaryg Posts: 420
    edited 2013-03-27 19:22
    I've printed the ADC_INPUT_example files
    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!
  • kwinnkwinn Posts: 8,697
    edited 2013-03-27 20:37
    garyg wrote: »
    I've printed the ADC_INPUT_example files
    So far, it would appear to me that:

    ADC_INPUT_example.spin - is the main program.
    Correct.
    FullDuplexSerial.spin - is sort of like a subroutine of the ADC_INPUT_example program.
    Yes, it performs the serial I/O function to display the results on the computer that the main program requests by the DEBUG statements.
    ADC_INPUT_DRIVER.spin - is sort of like another subroutine of the ADC_INPUT_example program.
    Yes, it controls the ADC chip and performs the functions the main program requests by the ADC statements.
  • garyggaryg Posts: 420
    edited 2013-03-28 12:58
    Next question?
    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.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2013-03-28 13:02
    These are method parameters. They are assigned when the method is called in the parent object (as in ADC.start(Vo_p, Vn_p, Vclk_p, Vcs_p, 8, 8, 12, 1, false)). And those values are a little easier to trace.
  • garyggaryg Posts: 420
    edited 2013-03-28 14:38
    I believe I'm not quite understanding, but getting closer.
    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)
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2013-03-28 14:46
    So remember that this object is being used by the parent object. So the start method never "just runs". You call the method from somewhere else. In this case, it's from the parent object (ADC_DRIVER_example). You could call the method from within this object, but you would have to create a "main" method that supplies parameters and calls the start method.

    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.
  • skylightskylight Posts: 1,915
    edited 2013-03-28 15:24
    Bobb Fwed wrote: »

    Keep the questions coming. There are many people on this forum ready and willing to help.
    And to learn as well, The point you made above about forgetting how hard it is to pick up the concepts at first is true even here on this very helpful forum, As you say you (not personally but the helpers in general) take it for granted and some times the advice given is several layers above the thinking process of those asking and all of a sudden you get the dreaded mind block and it all goes over your head. This is not a criticism as it's hard for those answering to know the level at which the asker is at.

    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.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2013-03-28 15:44
    SPIN was my fifth or sixth language and even so it had some serious hurdles to overcome in my mind. The biggest being tracking information from multiple COGs, but I do remember many days of head scratching trying to figure out things that seemed they should be very simple, and eventually they were simple.
    PASM is another beast entirely.
  • lardomlardom Posts: 1,659
    edited 2013-03-28 16:20
    garyg, That object is hard to understand. The terms in the parameter list are not explained. The only way to get a clearer understanding of what they mean is to study the datasheet on the adc chip itself. On top of that the key part is written in pasm.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2013-03-28 16:36
    The parameters are explained:
    '' 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.
  • lardomlardom Posts: 1,659
    edited 2013-03-28 17:40
    Yeah, I missed it. I'm sorry. One thing I noticed in post #10 is that the object's parameter list has a total of nine parameters. garyg's edit added a sequence of numbers that would, I think, generate an error message.
  • kwinnkwinn Posts: 8,697
    edited 2013-03-28 18:01
    @garyg

    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.
  • ElectrodudeElectrodude Posts: 1,658
    edited 2013-03-28 19:55
    Take for example the following spin code:
    PUB start
    
      blinkLED(0,10,200)
    
    PRI blinkled(pin,times,delay) | i
     
      dira[pin]:=1
      repeat i from 1 to times
        !outa[pin]
        waitcnt(clkfreq*delay/1000+cnt)
    

    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...):
    '$STAMP BS2
    '$PBASIC 2.5
    
    i          VAR word
    
    pin      VAR nib
    times  VAR word
    delay  VAR word
    
    Start:
    pin=0
    times=10
    delay=200
    GOSUB blinkLED
    END
    
    BlinkLED:
      FOR i FROM 1 TO times
        TOGGLE pin
        SLEEP delay
      NEXT
    RETURN
    

    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
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2013-03-28 20:06
    kwinn said
    Fortunately you do not have to understand how the driver works to make use of it.

    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
    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) 
    

    To use this in your code you would write
        adc.start (0,1,2,3,8,8,16,1, False) 
    

    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.
  • garyggaryg Posts: 420
    edited 2013-03-29 10:11
    Thanks
    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.
Sign In or Register to comment.