Share Your [Working] Spin2 Snippets, Please :)

13»

Comments

  • No worries. I can hardly remember a post I didn't go back and edit -- seems like clicking the "Post Comment" button causes me see spelling errors or think of a better way to express an idea.
  • You can always reset the smart pin to clear the base count in progress.
  • JonnyMac wrote: »
    No worries. I can hardly remember a post I didn't go back and edit -- seems like clicking the "Post Comment" button causes me see spelling errors or think of a better way to express an idea.

    Haha! Me too and often a few times. It’s amazing how many times you have to read something to see all the typos etc, and of course all the incorrect autocorrections.
  • Cluso99 wrote: »
    JonnyMac wrote: »
    No worries. I can hardly remember a post I didn't go back and edit -- seems like clicking the "Post Comment" button causes me see spelling errors or think of a better way to express an idea.

    Haha! Me too and often a few times. It’s amazing how many times you have to read something to see all the typos etc, and of course all the incorrect autocorrections.

    I think that is a universal thing.
  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-21 - 16:59:48
    This comment in the pulses/cycle documentation:
    If X[31:16] is set to 0, the output will be high for the duration of Y > 0.
    ...allows us to create a non-blocking, BS2-style pulseout method.
    pub pulseout(pin, us) | m, x
    
    '' Output pulse on pin that is us microseconds long
    
      m := P_OE | P_PULSE                                           ' set pulse mode
      if (pinread(pin))                                             ' if pin is high
        m |= P_INVERT_OUTPUT                                        '  invert pulse
    
      x := 1 #> (clkfreq / 1_000_000) <# $FFFF                      ' set base timing
      pinstart(pin, m, x, 0)                                        ' setup smart pin
      wypin(pin, us)                                                ' output the pulse
    

    Edit: Added comments and detection of pin start to set inversion when necessary.
  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-21 - 17:56:14
    Here's an updated version of pulses() that also works with the pin's present state.
    pub pulses(pin, count, khz) | m, x
    
    '' Output count pulses on pin
    '' -- khz is output frequency
    ''    * duty cycle is 50%
    
      m := P_OE | P_PULSE                                           ' set pulse/cycles mode
      if (pinread(pin))                                             ' if pin is high
        m |= P_INVERT_OUTPUT                                        '  invert pulses
     
      x := 2 #> (clkfreq / (kHz * 1000)) <# $FFFF                   ' ticks in period
      x |= ((x >> 1) << 16)                                         ' pulse ticks
      pinstart(pin, m, x, 0)                                        ' setup smart pin
      wypin(pin, count)                                             ' output the pulses
    
  • Well, darn, something is amiss. My sleep schedule has been off for a couple weeks so I'm running tired.

    Was writing a bit of test code for a magazine article using the pulses() method. I connected my 'scope to a couple pins and ran this code.
      pinlow(32)
      pinhigh(33)
      waitms(10)
      
      repeat n from 1 to 8
        pulses(32, n, 10)
        pulses(33, n, 10)
        waitms(200)
    
    What I expected was high-going pulses on Ch1 (pin 32) and low-going pulses on Ch2 (pin 33) -- but both go low. Again, I'm tired, so please be kind when pointing out my silly error. :blush:
    800 x 480 - 22K
  • evanhevanh Posts: 9,042
    edited 2020-03-21 - 22:02:42
    For some reason the pinlow()/pinhigh() aren't working. Do they need a DIR control maybe? I've not used spin2.

    EDIT: If those already have smartpin mode set then OUT is overridden by the smartpin. Presumably there is a pinstop() method in spin2.

  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-21 - 22:52:08
    The pinlow() and pinhigh() methods translate directly to drvl and drvh in the interpreter. If I just run those lines once (not in a loop), they work; it is on the second and subsequent loops that things go off the rails. This version of pulses() fixes the problem, but is not as elegant as I'd like.
    pub pulses(pin, count, khz, level) | m, x
    
    '' Output count pulses on pin
    '' -- khz is output frequency
    ''    * duty cycle is 50%
    '' -- level defines pulse high (1) or low (0)
    ''    * output left in opposite state
    
      m := P_OE | P_PULSE                                           ' set cycles mode
      if (level == 0)                                               ' if low-going pulse
        m |= P_INVERT_OUTPUT                                        '  invert the output
     
      x := 2 #> (clkfreq / (kHz * 1000)) <# $FFFF                   ' ticks in period
      x |= ((x >> 1) << 16)                                         ' pulse ticks
      pinstart(pin, m, x, 0)                                        ' setup smart pin
      wypin(pin, count)                                             ' output the pulses
    
  • AribaAriba Posts: 2,255
    edited 2020-03-22 - 00:07:20
    If a pin is in smart-mode you can't read the input state of the pin with pinread(). You only get the 'done-flag' of the smart pin function, which is high after the first pulses are done.

    Maybe it works if you disable the smartpin mode before you read the current state. You anyway start the mode again with pinstart().
    pub pulses(pin, count, khz) | m, x
    
    '' Output count pulses on pin
    '' -- khz is output frequency
    ''    * duty cycle is 50%
    
      pinsetup(pin, 0, 0, 0)                                        ' disable smart pin mode <---
      m := P_OE | P_PULSE                                           ' set pulse/cycles mode
      if (pinread(pin))                                             ' if pin is high
        m |= P_INVERT_OUTPUT                                        '  invert pulses
     
      x := 2 #> (clkfreq / (kHz * 1000)) <# $FFFF                   ' ticks in period
      x |= ((x >> 1) << 16)                                         ' pulse ticks
      pinstart(pin, m, x, 0)                                        ' setup smart pin
      wypin(pin, count)                                             ' output the pulses
    

    Maybe pinfloat(pin) is enough to disable the smart mode...

    Andy
  • evanhevanh Posts: 9,042
    edited 2020-03-22 - 00:19:37
    JonnyMac wrote: »
    ... it is on the second and subsequent loops that things go off the rails.
    And there's the why. The smartpin mode is still set from prior iteration and therefore overriding the OUT.

    EDIT: Found the spin2 method for turning off the smartpin - pinclear().

  • If a pin is in smart-mode you can't read the input state of the pin with pinread(). You only get the 'done-flag' of the smart pin function, which is high after the first pulses are done.
    Thanks for the reminder, Andy, and the result I was getting makes perfect sense in that context.

    I think for the auto level mode, the pin would require an external pull-up or pull-down, so I'm going to leave the pulse level parameter in.
  • Note, smartpin modes are unaffected by a coginit. They are each a little processor themselves. Only a full chip hard reset will clear them all at once.

  • To completely unconfigure a smart pin in PASM:

    FLTL #pin
    WRPIN #0,#pin

    In Spin2:

    PINCLEAR(pin)
  • evanh wrote: »
    Rayman wrote: »
    And another oddity is DIR must be raised for WXPIN to work. Presumably to action the Z change.

    Or maybe because DIR=0 is the reset operation on the pin?

    I would like to see a guide for using the smart pins, at least some basic examples for those of us new to them. I finally got repository mode working between spin2 and pasm2 code.
  • evanhevanh Posts: 9,042
    edited 2020-03-23 - 05:32:02
    wmosscrop wrote: »
    evanh wrote: »
    And another oddity is DIR must be raised for WXPIN to work. Presumably to action the Z change.
    Or maybe because DIR=0 is the reset operation on the pin?
    Z is retained indefinitely for repository mode. Neither DIR low nor clearing the mode erases Z. That said, some modes do hold Z in reset while DIR is low.

    I would like to see a guide for using the smart pins, at least some basic examples for those of us new to them. I finally got repository mode working between spin2 and pasm2 code.
    Not quite a guide but there is this - https://forums.parallax.com/discussion/169542/p2-links-for-where-to-obtain-tools-sample-test-code-reference-only/p1
    and this - https://forums.parallax.com/discussion/169069/p2-tricks-traps-differences-between-p1-reference-material-only/p1
  • While Spin on the P1 was way too slow for this, I think that there should be no problem doing this directly in Spin2, rather than assembly since the speed will be limited by the LED timing anyway. I demonstrated this at the Tachyon code level on the P1 (even though in practice I used a cog code module), so Spin2 should work fine. I basically broke up each data bit into 3 periods, the "from low" to high "clock" period, the data period, and then the clock idle low period. Let's see it done in pure Spin2!

    Here is a Spin2 only code that uses the Async TX smart mode to drive WS2812B LEDs. It works down to 20 MHz sysclock! The Start and Stop bits of an async transmitter have just the right states, if you invert the output and use 3 TX-bits per WS2812 bit.
    CON
      _clkfreq  = 160_000_000
      WS = 47   'pin
    
    VAR
      long  luma[256]
    
    PUB main() | i,b
      repeat i from 0 to 255                           'generate 24bit patterns for 1 color byte
        luma[i] := %110_110_110_110_110_110_110_11'0
        repeat b from 0 to 7
          luma[i] ^= i.[b] << (21-b*3)
    
      b := (clkfreq/2_400_000 * $10000) & !255         '800kHz * 3
      pinstart(WS, P_ASYNC_TX + P_INVERT_OUTPUT + P_OE , b+21, 0)   '22 bits + start + stop = 24
    
      repeat
        repeat i from 0 to 255     'fade 3 LEDs demo
          wsrgb(i,0,0)
          wsrgb(0,i,0)
          wsrgb(0,0,i)
          waitms(25)
    
    PUB wsrgb(r,g,b)               'send patterns for a single LED
      wypin(WS, luma[g])           'green
      repeat until pinread(WS)
      wypin(WS, luma[r])           'red
      repeat until pinread(WS)
      wypin(WS, luma[b])           'blue
      repeat until pinread(WS)
    
    Andy

  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-24 - 07:04:14
    Finally wrapped my head around analog input using smart pins and made a simple object to turn any pin into an analog input that returns a user-specified range. This is really intended for simple inputs like potentiometers.

    Here's an example of setup:
      pot.start(JOY_X, -500, 500)                                   ' setup joystick input
    
    This will configure the JOY_X pin to analog input and read back -500 (pot at ground) to 500 (pot at 3.3v).

    The read() method in the object returns the scaled value. Here it is in the demo program:
      repeat
        waitms(100)
        term.fstr1(string("Joy X = %4d\r"), pot.read())
    
    While setup and calibration can be done in Spin2, I chose inline P2ASM so that the calibration code would work at any speed (see attached).

Sign In or Register to comment.