Shop Learn P1 Docs P2 Docs
PASM Waitneq, waitpeq, and spin parm passing for button pressed. — Parallax Forums

PASM Waitneq, waitpeq, and spin parm passing for button pressed.

Jeffrey KaneJeffrey Kane Posts: 48
edited 2022-05-14 07:32 in PASM/Spin (P1)

Hello,

I could use some help here

this is my code snippet and vars

'vars:
datamask_dira         long  %00000000_00000011_11011100_00000000
datamask_PUPD      long  %00000000_00000000_11010000_00000000
pin_status                 long 0 
waiteq_test               long  %00000000_00000000_00100000_00000000 
Pin13_Dsel1     long |< 13  ' pin 13 
one                long    1  

'setup:
mov dira, datamask_dira       ' %00000000_00000011_11011100_00000000    
mov outa, datamask_PUPD   ' %00000000_00000000_11010000_00000000  

'code:
:button test waiteq_test,INA   wc          'test pin 13 if high or low
               rcl pin_status,#20                            ' move wc flag to pin_status 
              cmp      pin_status,one wz              ' check pin status = 1 (high)      
      if_e  jmp       #:start                                  ' jump to start code running
              jmp  #:button                                   ' else keep waiting
:start    mov     loop_length, loop_reset     'start main code running

and when I press button (pin 13), I get the button high,

but for some reason the code never starts,
if I make cmp one,one wz the code runs, so it seems the test if not right

when I press the button, my logic analyzer shows the button is pressed

it seems the code is broken, I also tried
:button waitpeq Pin13_Dsel1,Pin13_Dsel1 ' pin 13 button to run code.

which had the same result,

thanks in advance

regards

Jeff

Comments

  • Jeffrey KaneJeffrey Kane Posts: 48
    edited 2022-05-14 07:31

    additional data:

    just for sanity check I wrote this in spin

    CON
            _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    
            Pin13 = 13                     'pin connected to a LED via a resistor
    
    VAR
      long  symbol
    
    OBJ
      pst  : "FullDuplexSerial"
    
    PUB test_pin
    
        pst.Start(31, 30, %0000, 115200)
    
        dira[Pin13] := 0                 'set direction
    
        repeat                           'forever
          if INA[13] == 1
            pst.str(string("Pin13 is High:", 13))          'set it high
          else
           pst.str(string("Pin13 is low",13))         'one second
    
          waitcnt(clkfreq + cnt)       'one second
    
    PRI private_method_name
    
    
    DAT
    name    byte  "string_data",0`
    

    the output from this when I use the PST is, when pressing the key
    Pin is low
    Pin is low
    Pin is low
    Pin is low
    Pin is High:
    Pin is High:
    Pin is High:
    Pin is High:
    Pin is High:
    Pin is low
    Pin is low
    Pin is low

    anyway, also don't get why this doesn't seem to work for me

    :button test waiteq_test,INA wc if_c jmp #:start jmp #:button

    I thought maybe this helps

    Jeff

  • JonnyMacJonnyMac Posts: 8,308
    edited 2022-05-06 19:13

    If you're looking for a button press (or IO state) you can use waitpxx instructions. This bit of code will take the pin to monitor in the par register, and then write false (0) or true (-1) based on the state of the pin. I tested with an active-low button and it works (code is attached).

    dat 
    
                            org       0
    
    entry                   rdlong    t1, par                       ' get pin # from par
    
                            mov       btnmask, #1                   ' convert to mask
                            shl       btnmask, t1
    
    btn_loop                mov       t1, #0                        ' set button state = false
                            wrlong    t1, par
    
                            waitpne   btnmask, btnmask              ' wait for press
                            neg       t1, #1                        ' set button state = true
                            wrlong    t1, par
    
                            waitpeq   btnmask, btnmask              ' wait for release
                            jmp       #btn_loop
    
    ' --------------------------------------------------------------------------------------------------
    
    btnmask                 res       1                             ' mask for input pin
    
    t1                      res       1                             ' work vars
    t2                      res       1
    t3                      res       1
    
                            fit       $1F0
    

    BTW, your code samples will be easier to read if you put three back-ticks (`) on the line above and the line after -- this will cause the forum to format it for you.

  • JonnyMacJonnyMac Posts: 8,308
    edited 2022-05-06 19:42

    This shows that you can do it with test, but if there's no compelling reason not to use waitpxx, I'd do that.

    ready                   mov       t1, #0                        ' set button state = false
                            wrlong    t1, par
    
    wait_press              test      btnmask, ina          wc
          if_c              jmp       #wait_press
    
                            neg       t1, #1                        ' set button state = true    
                            wrlong    t1, par                                                    
    
    wait_release            test      btnmask, ina          wc             
          if_nc             jmp       #wait_release
    
                            jmp       #ready
    

    This works, too. Again, I was using an active-low input, so 0 = pressed.

    BTW, I think your problem may have been with

    rcl pin_status,#20
    

    What you really want to do is put the C flag into bit0 of pin_status. With the RCL instruction, I don't think you'll ever get pin_status to be 1 which is your target value.

    This update works with the style you're using -- but you're using four instructions where you could use one.

    wait_press              test      btnmask, ina          wc
                            muxnc     pinStatus, #(1<<0)            ' !c --> pinStatus.bit0
                            cmp       pinStatus, PRESSED    wz
          if_ne             jmp       #wait_press
    
  • Jeffrey KaneJeffrey Kane Posts: 48
    edited 2022-05-14 07:30

    Hello,

    thank you for the code to test my button,
    the good news is that it work(ish)

    here is the code, I think yours was P2, so I trimmed it down a little, anyway, the button works, what I mean is that the button works when I press reset, if I press reset I get (on the PST), this output, I pressed reset button 4 times,

    started button testing
    Pressed
    released
    started button testing
    Pressed
    released
    started button testing
    Pressed
    released
    started button testing
    Pressed
    released

    so it seems to be happy, except when I press my pin13 button, which is active high, vs active low in your code.

    Here is my code, with ticks'

    `{Object_Title_and_Purpose}
    
    
    CON
            _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    
            Pin13 = 13                     'pin connected to a LED via a resistor
    
    VAR
      long  symbol
      long  btnState
      long  param1
      long  param2
    
    OBJ
      pst  : "FullDuplexSerial"
    
    PUB test_pin | last
    
    
        pst.Start(31, 30, %0000, 115200)
    
        pst.str(string("started button testing ", 13)) 
    
        btnState := 2
        cognew(@entry, @btnState)
        last := false
    
       repeat
        if btnState <> last
          last := btnState
          if last == false
            pst.str(string("released", 13))          'set it high
          else
            pst.str(string("Pressed", 13))
    
       waitcnt(clkfreq + cnt)       'one second
    
    PRI private_method_name
    
    
    DAT
    
                            org       0
    
    entry                   rdlong    t1, par                       ' get pin # from par
    
                            mov       btnmask, #1                   ' convert to mask
                            shl       btnmask, t1
    
    btn_loop                mov       t1, #0                        ' set button state = false
                            wrlong    t1, par
    
                            waitpne   btnmask, btnmask              ' wait for press
                            neg       t1, #1                        ' set button state = true
                            wrlong    t1, par
    
                            waitpeq   btnmask, btnmask              ' wait for release
                            jmp       #btn_loop
    
    ' --------------------------------------------------------------------------------------------------
    
    btnmask                 res       1                             ' mask for input pin
    
    t1                      res       1                             ' work vars
    t2                      res       1
    t3                      res       1
    
                            fit       $1F0`
    

    so I don't get it, in spin it works fine, press the button all is good, normally I would think my button is broken, but the spin code works fine, and it matches my LA, also in my pasm code, i sent the and'ed INA data to the LA, and it also shows the pin going low to high when pressed, when the button is not pressed the INA shows nothing high, (button not pressed), I think I doing something dumb in my code, but the same thing happens when I use your code, but the button is simply wired to pin 13. and tied to 3.3 volt when the button is pressed, causing it to go active high. normally low.

    I have to think about this for awhile

    thanks for the code, I'll keep trying

    regards

    Jeff

  • I'll try switching it to active low,

    regards

    Jeff

  • Depending on the button type you might try a debounce time delay of 20 or 30 milliseconds because the contacts in a normally open push button will bounce between closed and open for some milliseconds before settling in the closed position. The value of the delay depends on the type of switch you’re using.

    Something like this:

    • Wait for button press
    • Do action
    • Wait for 20 or 30 milliseconds
    • Wait for button release
  • ok, but I'm not seeing bounce, but worth trying, here is the LA, of the low to high

  • I think I need some resistors, so I'll see Monday, button is in the lower left corner, goes to pin 13 on the mini prop board.

  • JonnyMacJonnyMac Posts: 8,308

    thank you for the code to test my button,

    You're welcome.

    the good news is that it work(ish)

    It works. Period. I tested it.

    I think yours was P2,

    Nope, it's P1 (I've been doing this a long time, I know the difference).

    so I trimmed it down a little

    If you're hungry and a stranger hands you a meal, do you throw some of it away before trying it?

    I think I need some resistors,

    I know you need resistors. If you want your button to be active-high (1 when pressed), put a pull-down between the pin and ground. If you want your button to be active-low (0 when pressed), put a pull-up between the pin a Vcc (3.3v). For buttons 10K pull-down/pull-up is a bit of a standard.

    I reconfigured my board and it runs fine using active-high -- I just had to exchange the waitpne and waitpeq instructions.

  • JonnyMacJonnyMac Posts: 8,308

    Depending on the button type you might try a debounce time delay of 20 or 30 milliseconds because the contacts in a normally open push button will bounce between closed and open for some milliseconds before settling in the closed position. The value of the delay depends on the type of switch you’re using.

    Sandy makes a good point. This is how I implemented it in the demo I posted earlier.

    dat
    
                            org       0
    
    entry                   mov       t1, par                       ' t1 is start of hub values (btnState)
    
                            rdlong    t2, t1                        ' get pin #
                            mov       btnmask, #1                   ' convert to mask
                            shl       btnmask, t2
    
                            add       t1, #4                        ' point to send long (param1)
                            rdlong    btnticks, t1   
    
    
    btn_loop                mov       t1, #0                        ' set button state = false
                            wrlong    t1, par
    
    wait_press              waitpeq   btnmask, btnmask              ' wait for press
                            mov       t1, cnt
                            add       t1, btnticks
                            waitcnt   t1, #0
                            test      btnmask, ina          wc      ' re-scan
          if_nc             jmp       #wait_press                   ' if not pressed, wait again
    
                            neg       t1, #1                        ' set button state = true
                            wrlong    t1, par
    
                            waitpne   btnmask, btnmask              ' wait for release
    wait_release            jmp       #btn_loop
    
    
    ' --------------------------------------------------------------------------------------------------
    
    PRESSED                 long      1
    pinStatus               long      0
    
    btnmask                 res       1                             ' mask for input pin
    btnticks                res       1                             ' debounce delay
    
    t1                      res       1                             ' work vars
    t2                      res       1
    t3                      res       1
    
                            fit       $1F0
    
  • jon,

    I appreciate you help, and yes, agreed to your comments, monday I will add the resistors, I know your code works, and I know you have been at this for awhile, I did try switching the waits, but just to test, but the button didn't work, so hardware issue.

    by the way, so does spin do things differently internally when checking pins?

    regards

    Jeff

  • JonnyMacJonnyMac Posts: 8,308
    edited 2022-05-07 00:01

    so does spin do things differently internally when checking pins?

    No. That said, the P1 and P2 interpreters are quite complex as the interleave multiple instructions in small sections of code.

    Consider this line of code:

      x := ina[13]
    

    In Spin, we could have a single pin (as shown) or a pin range, and we could even swap the order of the pin range. For a single-pin input, the mechanism I showed you in the demo is the approach most people seem to take with a single pin (have a look in fullduplexserial which is one of the earliest P1 drivers released).
    -- set pin mask to 1
    -- shift mask left by pin #
    then...
    -- test against ina register; result is in C flag

    Another approach:
    -- read ina into temp variable
    -- shift temp right by pin #
    -- and temp with #1

    For multiple simultaneous inputs there is more to the process
    -- create pins mask from number of pins to scan
    then...
    -- read ina into temp variable
    -- shift temp right by LSB pin number
    -- and temp with group mask

    This blurb takes two pins passed in the via par register, extracts them, creates a mask for the number of the pins in the range, then samples those inputs.

    entry                   rdlong    t1, par                       ' get packed pins
    
                            mov       lsbpin, t1                    ' extract pins
                            and       lsbpin, #$1F
                            mov       msbpin, t1
                            shr       msbpin, #8
                            and       msbpin, #$1F
    
                            mov       t2, msbpin                    ' # pins
                            sub       t2, lsbpin
                            add       t2, #1
    
                            neg       swmask, #1                    ' mask = all 1s
                            shl       swmask, t2                    ' create inverted mask
                            neg       swmask, swmask                ' invert range mask
                            sub       swmask, #1 
    
    read_switch             mov       temp, ina                     ' sample inputs
                            shr       temp, lsbpin                  ' align for lsb
                            and       temp, swmask                  ' mask off other pins  
    

    There are lots of assembly wizards (I'm not one of them, though I do write working code) that may have more thoughts. Listen to them.

  • That multiple pin reading would be quite handy, anyway Monday I'll do this (not sure about the 100 ohm), I'll go with the 10K first

    and get back with the button test results

    regards

    Jeff

  • JonnyMacJonnyMac Posts: 8,308

    The 100-ohm resistor will protect the pin if it's made an output and low and the button is pressed. Most of us don't put those series resistors on production boards, but they are found on educational products, and for good reason.

  • Well, this now works. but I went a slightly different way, I never got the P13 working under asm for a waitpne or waitpeq, i think it is a board issues on my design, so I went back to spin and did it that way by passing parms

    basically it is fairly simple.

    in the spin code i did this:

    in the asm code I did this:

    and the spin parms list

    and the asm parms list

    what i did find was that starting the cogs, as far as accessability, you need to wait alittle bit

    so this is the cog starts

    comments are welcome, I will eventually go back to a better test of the button 13, It will work if you use a breadboard, so that will eventually happen

    regards

    Jeff

  • Jeffrey KaneJeffrey Kane Posts: 48
    edited 2022-05-11 18:57

    Forgot to show the button working, here is an example of when you press the button.
    the flow is left to right, first the button is detected, then the program start executing
    and as mentioned in thread, it needed a debounce routine, without it you get to many pulses.

Sign In or Register to comment.