Shop OBEX P1 Docs P2 Docs Learn Events
PASM beginner questions — Parallax Forums

PASM beginner questions

g3cwig3cwi Posts: 262
edited 2012-06-17 12:25 in Propeller 1
Hi all

I have been looking at someone's demo programs to blink an LED in PASM. There are a couple of things that I could do with some help on. My verbose comments on the program show them, one is the use of OR instead of MOV in two places (MOV does work there too) and some sort of indirect addressing that I don't grasp yet.

(CODE DELETED)

Any clues will be welcome.

Thanks

Richard

Comments

  • Mark_TMark_T Posts: 1,981
    edited 2012-06-16 02:36
    The OR and ANDN instructions are used when updating the OUTA pseudo-register so that other pins that may (in a more complex program) be in use aren't changed when the blinker pin is set or reset. If you only have one pin set as an output then you can indeed use MOV, but OR and ANDN are used because that's what you need in the general case.

    By indirect addressing perhaps you mean the accessing of HUB RAM with RDLONG? Or perhaps the use of the # in the JMP instruction? I can't really guess.
  • g3cwig3cwi Posts: 262
    edited 2012-06-16 02:58
    Thanks Mark_T.

    It was this code that was (perhaps) indirect addressing:


    add t1, #4 ' point to "on" ticks
    rdlong ontix, t1 ' read on timing

    Not sure how that work.

    Regards

    Richard
  • lostcauzlostcauz Posts: 36
    edited 2012-06-16 03:08
    The cognew loads the blinkpin variable which is a long, hence 4 bytes. Notice the ontiming and offtiming variables are consecutive after the blinkpin variable. When the code adds #4 to t1, which is originally loaded with the blinkpin variable, this loads the next long, which is ontiming. This is read into the variable ontix. Next, again the t1 variable is incremented to point to the next long which is offtiming and copied to offtix.
  • g3cwig3cwi Posts: 262
    edited 2012-06-16 03:11
    ahhh! Got it now. Thanks lostcauz.

    Cheers

    Richard
  • Mark_TMark_T Posts: 1,981
    edited 2012-06-16 05:39
    lostcauz wrote: »
    The cognew loads the blinkpin variable which is a long, hence 4 bytes. Notice the ontiming and offtiming variables are consecutive after the blinkpin variable. When the code adds #4 to t1, which is originally loaded with the blinkpin variable, this loads the next long, which is ontiming. This is read into the variable ontix. Next, again the t1 variable is incremented to point to the next long which is offtiming and copied to offtix.

    I prefer to be clear and not just say "variable" - here we are talking about the address of the variable blinkpin (in hub RAM) being passed to the cog via the PAR register. Sometimes people talk about a variable meaning the address, sometimes the current value, and sometimes as an abstract thing which can be changed (which under the hood always means the address is being used to do the updating and reading).

    In case its not clear to a newcomer the cog runs in its own separate RAM (which is 32-bit wide) which cannot be accessed from outside the cog. Each cog can access the hub ram (which is byte-addressed) via rdbyte/rdword/rdlong/wrbyte/wrword/wrlong instructions.

    The cog RAM itself contains the instructions of the cog as well as the data, and allows self-modifying code as a result. cog RAM addresses increase by 1 for each long, unlike hub RAM which is byte-addressed.

    The PAR register gets passed only 14 bits from the COGNEW instruction, being bits 2 to 15 (enough to address cog RAM on long-word boundaries).
  • JonnyMacJonnyMac Posts: 9,194
    edited 2012-06-16 06:09
    Please be mindful of posting what you think is "helpful" -- there are many erroneous statements in your verbose comments.

    For example: "PAR is pin number passed by COGNEW"

    Nope. PAR holds the hub address of the pin number and is passed to the cog. This gets copied into t1 (which can be modified, PAR is read-only) for use with the rdlong instruction which READS a LONG from an address in the hub.

    I won't bother detailing all the other errors in your comments but will ask that you sift back through so as not to undo your intention of helping other newcomers. You can in fact edit your own posts to correct mistakes or make clarifications (I do this all the time).

    I know that my program comments tend to be brief; as programmers we get paid to write code, not comments, so my opinion is that comments should serve to describe the purpose of the code, not simply replicate the often self-evident purpose of an instruction. For those that may think me insensitive to newcomers, I'm not -- that listing is from one of my N&V columns where all of the code is described in great detail.
  • g3cwig3cwi Posts: 262
    edited 2012-06-16 06:49
    Thanks Jonny

    As a beginner in PASM I can't hope to spot all my errors - that's the nature of being a beginner. However, I have taken your advice and deleted all the code so that other beginners don't miss out on the fun.

    By the way, I'm a teacher, not a programmer. So from one profession to another can I suggest that "self evident" is not something that I would ever assume when teaching.

    Cheers

    Richard
  • g3cwig3cwi Posts: 262
    edited 2012-06-16 11:19
    Moving swiftly on to a two LED test I modified the code as attached. However, several hours down the line and many tests have failed to reveal what is wrong. The idea is simply that two LEDs are flashed at the same time. Not very difficult, I hoped.
    '' Blame no-one but me for this code
    '' Richard G3CWI
    
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    var
      
      long  cog
      long  blinkpin[2]           ' pin used by blinker cog
      long  ontiming           ' pin "on" timing in milliseconds
      long  offtiming          ' pin "off" timing in milliseconds
    
    Pub Main
    
    start (2, 3, 500, 200)
    
    Repeat
    
    pub start(pin0, pin1 , onms, offms)
    
    '' Start blinking pin with specified on and off durations (in milliseconds)
    
      stop   ' stop if already running
    
      blinkpin[0]  := pin0
      blinkpin[1]  := pin1
      
      ontiming  := clkfreq / 1000 * onms
      offtiming := clkfreq / 1000 * offms
    
      result := cog := cognew(@blinker,   @blinkpin[0])    ' start blinker cog
    
    pub stop
    
    '' Stops blinker cog if running
    
      if (cog)
        cogstop(cog~ - 1)  ' stop cog, clear id
    
    
    pub active
    
    '' Returns true if blinker is active
    
      return (cog > 0)
    
    dat
    
                            org     0    'Set start point for PASM
                            
    blinker                 mov     t0, par       ' start of structure 
                            mov     t1, par       ' addr in PAR => t1
                            rdlong  t2, t1        ' read blink pin0
                            mov     t3, #1
                            shl     t3, t2
    
                            add     t1, #4       ' go to next address
                  
                            rdlong  t4, t1       ' read blink pin1
                            mov     t5, #1
                            shl     t5, t4
                            
                            or      t5, t3
                            rdlong  pinmask, t5
    
                            add     t0, #8        ' point to "on" ticks
                            rdlong  ontix, t0     ' read on timing
                            
                            add     t0, #4         ' point to "off" ticks
                            rdlong  offtix, t0     ' read off timing
                            
                            mov     dira, t3  ' make pin an output
                            or      outa, t3  ' start on
                            
                            mov     timer, ontix   ' start with on time
                            add     timer, cnt     ' sync with system counter
                            
    bloop                   waitcnt timer, offtix    ' let on time expire, load off time
    
                            andn    outa, pinmask   ' pin off
                            
                            waitcnt timer, ontix     ' let off time expire, load on time
                            or      outa, pinmask   ' pin on
                            
                            jmp     #bloop           'jump back to bloop label to rerun loop
                              
    ' --------------------------------------------------------------------------------------------------
    ''Reserve longs for variables
    
    pinmask                 res     1
    ontix                   res     1    ''on timing in system ticks
    offtix                  res     1    ''off timing in system ticks
    timer                   res     1    ''used to set timing
    
    t0                      res     1    ''temporary variable 
    t1                      res     1    ''temporary variable
    t2                      res     1    ''temporary variable  
    t3                      res     1    ''temporary variable
    t4                      res     1    ''temporary variable  
    t5                      res     1    ''temporary variable
    
                            fit     496                                    
    

    No doubt some silly mistake(s).

    Cheers

    Richard
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-06-16 11:25
    For a start, rdlong pinmask,t5 should be mov pinmask,t5. 'Haven't looked beyond that one...

    -Phil
  • g3cwig3cwi Posts: 262
    edited 2012-06-16 11:30
    Thanks Phil

    That does not work so there is something else up.

    Cheers

    Richard
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-06-16 11:35
    "Does not work," isn't much of a description. What are the symptoms?

    -Phil
  • g3cwig3cwi Posts: 262
    edited 2012-06-16 11:39
    Phil with your suggested change, P2 LED lights and flashes but no others.

    Edit - changing the value passed to pin0 gives the expected results. Changing the value passed to pin1 does nothing.

    Cheers

    Richard
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-06-16 11:41
    That's because you preloaded dira with t3 instead of pinmask.

    -Phil
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-06-17 06:14
    Your code should set pins P0 to P8. If you are not seeing this then either your LEDs are wired wrong on P0 and P1, or the rest of your code is causing this to fail. Please post all your code.

    I noticed the cog variable is not used consistently between the start and stop routine. In the start routine you are setting it to the return value from cognew, which is 0 to 7 if it succeeds and -1 if it fails. The stop routine assumes the value is 1 through 8 if the cog is active, and 0 if it is not.
  • g3cwig3cwi Posts: 262
    edited 2012-06-17 06:25
    Hi Dave

    I have realised that it is a Prop BoE thing. I had not realised that some LEDS are active low and some are active high. It was only after writing here that I started to wonder if the problem was hardware related. I was convinced my software was at fault. Now I'm back on track - thanks.

    Re the start and stop problem - thanks for that. I did not write the core code so someone else is responsible for that problem!

    Cheers

    Richard
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-06-17 10:20
    Again, Richard, only one LED is flashing because dira has only one bit set.

    -Phil
  • g3cwig3cwi Posts: 262
    edited 2012-06-17 10:55
    Thanks Phil

    All is working now.

    Regards

    Richard
  • JonnyMacJonnyMac Posts: 9,194
    edited 2012-06-17 11:22
    So from one profession to another can I suggest that "self evident" is not something that I would ever assume when teaching.

    I tend to make the dangerous assumption that those interested in programming have a willingness to crack open the manual! ;) A failing on my part, I'm sure. But just as my automobile doesn't have instructions printed on the steering wheel as to what it does, my listings don't tend to explain what an instruction does, rather its intent for the program which I think is more valuable for those using my listings.

    IMHO, more verbose is not always simpler. Here's how you can have two pins doing the same thing -- and only one additional cog variable is used (mask for the second pin). Note, too, that as the pins and timing variables are not needed after the .start method, those can be disposed of, too.
    '' =================================================================================================
    ''
    ''   File....... blinker2.spin
    ''   Purpose.... PASM LED blinker
    ''   Author.....             
    ''   E-mail..... 
    ''   Started.... 
    ''   Updated.... 
    ''
    '' =================================================================================================
    
    
    var
    
      long  cog
    
    
    pub start(pin0, pin1, onms, offms) | ok
    
    '' Start blinking two pins with specified on and off durations (in milliseconds)
    
      stop                                                          ' stop if already running
    
      onms *= clkfreq / 1000                                        ' convert to system ticks
      offms *= clkfreq / 1000 
    
      ok := cog := cognew(@blinker, @pin0) + 1                      ' start blinker cog
      waitcnt(clkfreq >> 10 + cnt)                                  ' let cog start   
    
      return ok
       
    
    pub stop
    
    '' Stops blinker cog if running
    
      if (cog)
        cogstop(cog - 1)                                            ' stop cog, clear id
        cog := 0
    
    
    pub active
    
    '' Returns true if blinker is active
    
      return (cog > 0)
      
    
    con
    
    dat
    
                            org     0
    
    blinker                 mov     t1, par                         ' copy hub address of parameters
                            rdlong  t2, t1                          ' read blink pin0
                            mov     pinmask0, #1                    ' create mask from pin #
                            shl     pinmask0, t2
                            mov     dira, pinmask0                  ' set to output
    
                            add     t1, #4                          ' point to pin1
                            rdlong  t2, t1                          ' read blink pin1
                            mov     pinmask0, #1                    ' create mask from pin #
                            shl     pinmask0, t2
                            or      dira, pinmask1                  ' include pin1 in outputs
    
                            add     t1, #4                          ' point to "on" ticks
                            rdlong  ontix, t1                       ' read on timing
    
                            add     t1, #4                          ' point to "off" ticks
                            rdlong  offtix, t1                      ' read off timing
    
                            or      outa, pinmask0                  ' start with pins on
                            or      outa, pinmask1
    
                            mov     timer, ontix                    ' start with "on" time
                            add     timer, cnt                      ' sync with system counter
    
    bloop                   waitcnt timer, offtix                   ' let on timer expire, load off time
                            andn    outa, pinmask0                  ' pins off
                            andn    outa, pinmask1
                            waitcnt timer, ontix                    ' let off timer expire, load on time
                            or      outa, pinmask0                  ' pins on
                            or      outa, pinmask1          
                            jmp     #bloop                          ' loop forever
                              
    ' --------------------------------------------------------------------------------------------------
    
    pinmask0                res     1                               ' mask for blinker pin0
    pinmask1                res     1                               ' mask for blinker pin1
    ontix                   res     1                               ' on timing in system ticks
    offtix                  res     1                               ' off timing in system ticks
    timer                   res     1
    
    t1                      res     1
    t2                      res     1
    
                            fit     496                                    
    
                            
    dat
    
    {{
    
      Terms of Use: MIT License
    
      Permission is hereby granted, free of charge, to any person obtaining a copy of this
      software and associated documentation files (the "Software"), to deal in the Software
      without restriction, including without limitation the rights to use, copy, modify,
      merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
      permit persons to whom the Software is furnished to do so, subject to the following
      conditions:
    
      The above copyright notice and this permission notice shall be included in all copies
      or substantial portions of the Software.
    
      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
      INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
      PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
      CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
      OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    }}
    
  • potatoheadpotatohead Posts: 10,261
    edited 2012-06-17 12:25
    The right answer here is discoverable.

    Commenting the intent makes the program very discoverable, and that's really the goal as anyone can run tests, look up the instruction definitions, etc...

    "ADD" is pretty self evident. What is being added and why isn't.
Sign In or Register to comment.