Shop OBEX P1 Docs P2 Docs Learn Events
Spin - WHILE? — Parallax Forums

Spin - WHILE?

cavelambcavelamb Posts: 720
edited 2012-02-24 13:00 in Propeller 1
More lessons from a blinkin' LED...

I've been messing with this one on and off for several days.
I'm trying to get the Repeat/While loop working.
I could code around it, but that doesn't teach me how to do it the right way...

Wha-zup?
{{   Blinky6.spin }}
CON
_CLKMODE=XTAL1+PLL2X
_XINFREQ =5_000_000
HI, ON, ONE,P_OUT = 1
LO, OFF, ZERO, P_IN = 0
PO_LED = 07
PI_SWITCH = 06
SlowWait = 5_000_000
FastWait = 1_000_000

VAR BYTE X,Y,Z
 
PUB  MAIN 

dira [PO_LED] := P_OUT              'output pin for LED
outa [PO_LED] := LO
dira [PI_SWITCH] := P_IN            'input pin for button

X:=0

Repeat
   x+=1
   if X==8
      X:=1 
  Z := byte [NUMS[X]]    
  Repeat Z
      BlinkFast

  Repeat
     y :=  ina[PI_Switch]
     While Y > 0               ' page 41, 107 in the manual!!

PUB BlinkFast
    outa[PO_LED] := HI
    waitCNT (FastWait+cnt)
    outa[PO_LED] := LO     
    waitCNT (FastWait+cnt)

DAT NUMS Byte 1,2,3,4,5,6,7

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-02-23 22:09
    An end-of-loop while has to be on the same indent level as the repeat that it applies to.

    -Phil
  • AribaAriba Posts: 2,690
    edited 2012-02-23 22:09
    While must be indented the same as the repeat above

    Andy
  • 4x5n4x5n Posts: 745
    edited 2012-02-23 22:09
    Shouldn't the syntax be:

    repeat while Y>0

    ?
  • Cluso99Cluso99 Posts: 18,069
    edited 2012-02-23 22:54
    I also note that your
    Z := byte...
    is not on the same indent level.

    Indentation is vital in spin. Get it wrong and you will get all sorts of problems.

    I suggest you turn on the indentation markers in PropTool to check you have what you expect.

    4x5n:
    When the while is at the end of the repeat loop, the loop is executed once before the while test. If the while test is at the beginning of the repeat loop, if the alue does not satisfy the while test, then the loop will not be executed. Each have their own valid use in coding.
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-02-23 23:37
    Hmmm ... using constants is a good idea, but I think you should find the right amount of constants. It should add value to the code when using a constant. Possible added values are:
    it makes the code more readable
    it makes the code configrable
    it removes runtime calculations

    If you use constants for timing you should think about making these constanst depend on _CLKFREQ. Then it's easier to modify the code for a board that uses a different chrystal or that uses RCFast/Slow.

    By the way .. it's very usual that constants are written in UPPERCASE. This way you easily know whether you're looking at a constant or a variable.

    So, what I would not do is replace the operators ~ and ~~ by constants. Why? Because ~ and ~~ are well known by each SPIN-programmer and there is no need to lookup the value of P_IN or P_OUT in the constant block.

    From brain-debugging I would say that your code does not work. The problems are
    Z := byte [NUMS[X]]
    and
    X:=0
    Repeat
    x+=1

    byte[] needs an address which points to some data in memory. But you feed it with NUMS[X] which goes from 2 to 7. So, actually your blink funktion will blink depending on the content of HUB-RAM addresses 2 - 7 which is not really in your hand ;oP
    What you could write is byte[ @NUMS[X] ] or byte[ @NUMS + X ] or simply NUMS[X].
    An array starts with index 0, but your code sets X to 1 minimum. So, here are my corrections:
    {{   Blinky6.spin }}
    CON
    _CLKMODE=XTAL1+PLL2X
    _XINFREQ =5_000_000
    
    PO_LED = 07
    PI_SWITCH = 06
    
    WAIT_1s = _CLKFREQ
    WAIT_200ms = _CLKFREQ / 5
    
    VAR BYTE X,Y,Z
     
    PUB  MAIN 
    
    dira [PO_LED] ~~
    outa [PO_LED] := LO
    dira [PI_SWITCH] ~
    
    X:=0
    
    Repeat
      if X==8
         X~ 
      Z := NUMS[X++]    
      BlinkFast( Z )
    
      WaitButton
    
    PUB BlinkFast( blinks )
      Repeat blinks
        outa[PO_LED]~~
        waitCNT (WAIT_200ms + cnt)
        outa[PO_LED]~
        waitCNT (WAIT_200ms + cnt)
    
    PUB WaitButton
      Repeat
         y :=  ina[PI_Switch]
      While Y
    
    DAT NUMS Byte 1,2,3,4,5,6,7
    
  • cavelambcavelamb Posts: 720
    edited 2012-02-23 23:44
    Thanks for the quick response guys!

    OK, indentation thingie turned on and yeah, that's probably a good idea.
    It would be better if indented blocks could be block-moved, but ...

    For some reason the code is just not seeing the button.
    If works (right even!) in the other little programs, so I know the hardware is ok.
    But since I'm not getting the pause there, I wasn't at all sure the Repeat/While was ok.

    The button has a 10k pull-up on port 6, hence SW_ON and SW_OFF logic.

    The LED has a 33 to +3.3 on port 7.

    Simplifying the code, It _should_
    Fetch the 4th number in NUMS,
    Then Repeat Z should blink the light that many times.
    Then wait for a Button to be pressed.

    But it just blinks it's fool head off... (bad habits are hard to break)


    {{   Blinky62.spin }}
    
    CON
    _CLKMODE=XTAL1+PLL2X
    _XINFREQ =5_000_000
    
    LO, OFF, ZERO, P_IN, LED_ON, SW_ON = 0
    HI, ON, ONE, P_OUT, LED_OFF, SW_OFF = 1
    
    PO_LED = 07
    PI_SW1 = 06
    
    SlowWait = 5_000_000
    FastWait = 2_000_000
    
    VAR BYTE X,Y,Z
    PUB  MAIN 
      dira [PO_LED] := P_OUT              'output pin for LED
      outa [PO_LED] := LED_OFF
      dira [PI_SW1] := P_IN                 'input pin for button
      X:=0
    
    Repeat
       X:=4
       Z := byte [NUMS[X]]    
       Repeat Z
          BlinkFast
             
       repeat  While Y == SW_OFF      ' wait until switch pressed     
          Y :=  ina[PI_SW1]
    
    PUB BlinkFast
        outa[PO_LED] := LED_ON
        waitCNT (FastWait+cnt)
        outa[PO_LED] := LED_OFF     
        waitCNT (FastWait+cnt)
    
    DAT NUMS Byte 1,2,3,4,5,6,7
    
  • cavelambcavelamb Posts: 720
    edited 2012-02-24 00:06
    Interesting....

    Setting pin direction to INPUT for the switch...

    but
    dira [PI_SWITCH] :=P_IN doesn't

    HI, ON, ONE,P_OUT, LED_ON = 1
    LO, OFF, ZERO, P_IN, LED_OFF = 0
    
    dira [PI_SWITCH] :=LO  ' works 
    dira [PI_SWITCH] :=P_IN ' doesn't
    

    Underscore not allowed there?
    Or limit for definitions on one line?
  • kuronekokuroneko Posts: 3,623
    edited 2012-02-24 00:21
    LO, OFF, ZERO, P_IN, LED_OFF = 0
    
    In this case LO will be 0 then every following constant is one higher (P_IN being 3) followed by LED_OFF = 0. So you're setting the pin to an output when P_IN is used.

    If you use the PropTool you can place the cursor on a constant (after successful compilation). The status line will show you its value.
  • cavelambcavelamb Posts: 720
    edited 2012-02-24 00:25
    Vielen Dank! Magl

    I'm a sloppy old Assembly programmer from the dark ages and haven't done any programming in years.
    My style (or lack there of) may be painful for a while.
    But I'll work on it.
    ~ and ~~ still look totally mysterious to me. Which is ~ and which is ~~ ??
    To my eye it's unreadable... But maybe it will come... I just need to stay at it.

    Your suggestion actually worked - after a couple of things.

    _CLKFREQ came up undefined - so I changed it to _XINFREQ
    and you left one of my Constants in place - which was then also undefined. :innocent:
    So I changed that to ~ and it worked - perfectly.

    So...
    byte[ @NUMS[X] ] or byte[ @NUMS + X ] or simply NUMS[X] to access my local data
    and
    Z := byte [NUMS[X]] will read from hub memory.

    (and get comfortable with ~ and ~~)
  • cavelambcavelamb Posts: 720
    edited 2012-02-24 00:31
    kuroneko wrote: »
    LO, OFF, ZERO, P_IN, LED_OFF = 0
    
    In this case LO will be 0 then every following constant is one higher (P_IN being 3) followed by LED_OFF = 0. So you're setting the pin to an output when P_IN is used.

    If you use the PropTool you can place the cursor on a constant (after successful compilation). The status line will show you its value.

    Now THAT is mighty useful to know...


    Arigato kuroneko-san
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-02-24 02:54
    Don't understand what you mean with this:
    "So...
    byte[ @NUMS[X] ] or byte[ @NUMS + X ] or simply NUMS[X] to access my local data
    and
    Z := byte [NUMS[X]] will read from hub memory."

    SPIN only has access to HUB memory. Only PASM code has access to COG RAM.

    The point is, when doing Z := byte [NUMS[X]] the value that ends up in Z is not taken from your array. What does the propeller do in this case:
    1. it has a look into X and finds a 1 for the first iteration
    2. it has a look into NUM[ X ] which is actually NUM[ 1 ] and finds 2 - remember indexes start from 0
    3. it then can resolve byte[] ... but it's doing it with byte[ 2 ]. This means it's reading byte 2 of the whole HUB-RAM which is not where your array is stored! And that's why you got some crazy blinking.
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-02-24 03:03
    That's what the PropellerManual says about _CLKFREQ:
    _CLKFREQ specifies the System Clock frequency for start-up. It is a pre-defined constant symbol whose value is determined by the top object file of an application. _CLKFREQ is either set directly by the application itself, or is set indirectly as the result of the _CLKMODE and _XINFREQ settings.

    So, I currently don't understand why it should not be available.

    But for sure it is better to use _CLKFREQ instead of _XINFREQ if you want to create constants for certain waittimes, because _CLKFREQ is really the number of clocks per second. When using _XINFREQ you also need to consider the clock-mode (especially the PLL settings).
  • pgbpsupgbpsu Posts: 460
    edited 2012-02-24 06:43
    cavelamb wrote: »
    It would be better if indented blocks could be block-moved, but ...

    If you are using the Prop Tool, you can move (and indent) blocks of code. See the " Code Block Indenting" section of the prop manual. Pg 71 in my printed v1.0 manual.
  • 4x5n4x5n Posts: 745
    edited 2012-02-24 07:54
    Cluso99 wrote: »
    I also note that your
    Z := byte...
    is not on the same indent level.

    Indentation is vital in spin. Get it wrong and you will get all sorts of problems.

    I suggest you turn on the indentation markers in PropTool to check you have what you expect.

    4x5n:
    When the while is at the end of the repeat loop, the loop is executed once before the while test. If the while test is at the beginning of the repeat loop, if the alue does not satisfy the while test, then the loop will not be executed. Each have their own valid use in coding.

    I've always thought that the "while" went on the repeat line and only ever used it that way. Being able to put it at the end of the block could have saved me some trouble. :-)
  • cavelambcavelamb Posts: 720
    edited 2012-02-24 09:18
    MagIO2 wrote: »
    Don't understand what you mean with this:
    "So...
    byte[ @NUMS[X] ] or byte[ @NUMS + X ] or simply NUMS[X] to access my local data
    and
    Z := byte [NUMS[X]] will read from hub memory."

    SPIN only has access to HUB memory. Only PASM code has access to COG RAM.

    The point is, when doing Z := byte [NUMS[X]] the value that ends up in Z is not taken from your array. What does the propeller do in this case:
    1. it has a look into X and finds a 1 for the first iteration
    2. it has a look into NUM[ X ] which is actually NUM[ 1 ] and finds 2 - remember indexes start from 0
    3. it then can resolve byte[] ... but it's doing it with byte[ 2 ]. This means it's reading byte 2 of the whole HUB-RAM which is not where your array is stored! And that's why you got some crazy blinking.


    Thank you for expanding on that.
    I'm trying to understand the difference between the forms, and obviously got it wrong.
    It was late over here and I was getting punchy.

    I remember that the program and all data is stored in the hub.
    The cog gets the Spin interpreter.
    And, yes, I do understand your point about the 0th index.

    The real problem though was how to access MY data.

    In playing around with it, I had moved the index to 1 just to see if I could return a reasonable number.
    I was getting a couple of hundred blinks where I was expecting only 1 or 2.



    Were you were saying that my mistake was in forming the expression...

    Z := byte[NUMS[x]] instead of using Z := NUMS[X] ?
  • cavelambcavelamb Posts: 720
    edited 2012-02-24 09:23
    MagIO2 wrote: »
    That's what the PropellerManual says about _CLKFREQ:
    _CLKFREQ specifies the System Clock frequency for start-up. It is a pre-defined constant symbol whose value is determined by the top object file of an application. _CLKFREQ is either set directly by the application itself, or is set indirectly as the result of the _CLKMODE and _XINFREQ settings.

    So, I currently don't understand why it should not be available.

    But for sure it is better to use _CLKFREQ instead of _XINFREQ if you want to create constants for certain waittimes, because _CLKFREQ is really the number of clocks per second. When using _XINFREQ you also need to consider the clock-mode (especially the PLL settings).


    I just tried it again.
    _CLKFREQ is shown in BOLD, so Spin Tool is recognizing the term.

    but using it as below generates an Undefined Symbol error.

    Back to the manual...
    CON
    _CLKMODE=XTAL1+PLL2X
    _XINFREQ =5_000_000
    
    WAIT_1s = _CLKFREQ
    WAIT_500 = _XINFREQ / 2
    
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-02-24 12:32
    Hmmm ... I looked into my code and found that I never tried it myself .. I just believed the manual.

    But it works if you define _CLKFREQ yourself:
     _CLKMODE = XTAL1 + PLL2X
     _CLKFREQ = 10_000_000
    

    And after that you can use _CLKFREQ for calculating your waitcnt-values.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-02-24 13:00
    This is one of those strange things. I also assumed _CLKFREQ would be automatically set by _CLKMODE and _XINFREQ (as we now know doesn't work).

    There is a way of setting wait times as constants using some trick. JonnyMac has written about it in his SpinZone articles and it's also used in the Prop Library's "Clock.spin" object.
Sign In or Register to comment.