Share Your [Working] Spin2 Snippets, Please :)

2

Comments

  • evanhevanh Posts: 9,041
    edited 2020-03-12 - 00:25:14
    You can have the DIRL-WRPIN-WXPIN-DIRH along with filling out initial parameters in a setup routine before the servo loop actions, and then simply adjust WYPIN in the servo loop. The new Y value takes effect on the next frame period.
  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-12 - 00:29:13
    cgracey wrote: »
    It is not possible to read back the smart pin configuration.
    Well, darn.
  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-12 - 00:28:59
    evanh wrote: »
    You can have the DIRL-WRPIN-WXPIN-DIRH along with filling out initial parameters in a setup routine before the servo loop actions, and then simply adjust WYPIN in the servo loop. The new Y value takes effect on the next frame period.
    Yep, I did see that behavior -- was looking to avoid a second method. The nice thing is that there's no "servo loop" now unless I want to do ramping. If that's case, I'd know the servo is setup and can use wypin.
  • You can do WYPIN's whenever you want. It will just grab the current value at the beginning of each new frame.
  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-12 - 17:46:45
    While looking for something else in a parts bin I found a quadrature encoder. Using this with the P2 requires almost no code.
    My pins for the encoder:
      ENC_SW = 34  { I }
      ENC_B  = 33  { I }
      ENC_A  = 32  { I }
    
    I created a constant that sets the B pin as the next up from A.
      SP_ENC = %0000_0001_000_0000000000000_00_01011_0              ' B pin is +1 from A
    
    To initialize the encoder:
      pinstart(ENC_A, SP_ENC, 0, 0)
    
    Finally, a little test loop. In this case pressing the button on the encoder zeros the count.
      repeat
        if (pinread(ENC_SW) == YES)                                 ' check button
          pinfloat(ENC_A)                                           ' reset count
          pinlow(ENC_A)                                             ' reactivate
          
        position := rdpin(ENC_A)                                    ' get encoder count
        term.tx(term.HOME)
        term.fstr1(string("Encoder\r-- position = %d    "), position sar 2)
        waitms(25)
    
    The encoder I have has detents and gives four counts per click. I use sar 2 as it's slightly faster than / 4.
  • JonnyMac,
    It's reasonably safe to assume a pin is configured as you last left it. If someone were to use your code in a system, it would generally be a bug to have more than one piece of code messing with the same pin.
    So, just do wypin's to move the servo. :)

  • @cgracey When using the quadrature encoder mode, is it possible to preset the count when the pin is in reset?
  • cgraceycgracey Posts: 12,677
    edited 2020-03-12 - 19:50:12
    JonnyMac wrote: »
    @cgracey When using the quadrature encoder mode, is it possible to preset the count when the pin is in reset?

    No. The count is cleared to zero.
  • If you wrpin to select long repository and then read in that long, will it hold the previously written wxpin value?

    Or, is this somehow cleared when long repository mode is selected?
  • In my case, Ray, I'm trying to duplicate features in my P1 quadrature encoder object.

    1) You can preset the encoder to any value in its defined range
    2) You can range limit the value of the encoder

    It's a cold, rainy day in SoCal, so I'm going to put on some more coffee and figure it out with a couple of offset variables in my P2 object.
  • evanhevanh Posts: 9,041
    edited 2020-03-12 - 21:09:30
    Rayman wrote: »
    Or, is this somehow cleared when long repository mode is selected?
    A little oddly, repository smartpin modes retain the Z value, and can be read out with RDPIN, even while unconfigured - WRPIN #0, pin. And another oddity is DIR must be raised for WXPIN to work. Presumably to action the Z change.

  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-13 - 18:10:58
    I'm not much of an Arduino user, but I do appreciate the millis() function as it's very useful for differential timing. In many of my P1 projects I create "maintenance" cog that runs a 1ms loop so that I can update a global variable called millis. With the 64-bit counter in the P2, we can duplicate the Arduino's millis() function very easily.
    pub millis() : ms | lo, hi, tixms
    
    '' Return milliseconds since reset.
    
      org
                            getct   hi                    wc        ' get cnt (now)
                            getct   lo 
                            rdlong  tixms, #$44                     ' get clkfreq
                            qdiv    tixms, ##1000                   ' get ticks/ms
                            getqx   tixms
                            setq    hi                              ' divide cnt by ticks/ms
                            qdiv    lo, tixms
                            getqx   ms
      end
    
    If I did the math correctly the 64-bit counter running on my 200MHz system will not roll-over for about 2900 years. :)

    If @cgracey finds room in the Spin2 interpreter engine I think this would be a worthy addition.

    Edit: Corrected capture of system counter.
  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-13 - 18:12:20
    Another approach for event timing. Use mark() to capture the system counter at the beginning of the event, and delta_ms() to return the elapsed time in milliseconds.
    pub mark() : lo, hi
    
    '' Return 64-bit system counter.
    
      org
                            getct   hi                    wc        ' get cnt (now)
                            getct   lo 
      end
    
    
    pub delta_ms(mlo, mhi) : ms | dlo, dhi, tixms
    
    '' Return delta milliseconds between mark point and system counter.
    
      org
                            getct   dhi                   wc        ' get cnt (now)
                            getct   dlo 
                            sub     dlo, mlo              wc        ' delta := now - mark
                            subx    dhi, mhi
                            rdlong  tixms, #$44                     ' get clkfreq
                            qdiv    tixms, ##1000                   ' get ticks/ms
                            getqx   tixms
                            setq    dhi                             ' divide delta by ticks/ms
                            qdiv    dlo, tixms
                            getqx   ms
      end
    

    Edit: Corrected capture of system counter.
  • YanomaniYanomani Posts: 968
    edited 2020-03-13 - 18:05:44
    Hi Jon

    Please, check last silicon's instruction spreadsheet.

    To ensure you can grab a full 64-bit CT properly, you'll need to change the operations order, as follows:
    org
                            getct   hi                    wc        ' get 64-bit cnt
                            getct   lo
    
                            rdlong  tixms, #$44                     ' get clkfreq
                            qdiv    tixms, ##1000                   ' get ticks/ms
                            getqx   tixms
                            setq    hi                              ' divide cnt by ticks/ms
                            qdiv    lo, tixms
                            getqx   ms
    end
    

    The first getct (with wc) would retrieve the upper long, and shields the next getct (without wc) against any possible interrupts that could, eventually, occur in between them.

    Otherwise, if an interrupt event occurs right in the middle of the sequence, the 64-bit value integrity could be lost.

    Hope it helps

    Henrique
  • Thank you, Herique -- that's a detail I missed (so used to P1 I don't think about interrupts). I originally had it as you suggest, but thought it best to grab the low part first as it's changing the fastest. Will update my code. Again, thanks.
  • You're welcome, ever!

    I've been following your code examples with real interest, as some kind of a "shot" of insight.

    ATM, while I wait for some very important changes in my day-by-day life, I prefere to read, understand and try to edit other people's work, as a thought exercise.

    Keeps my mind fresh, and my back muscles firmly attached to that chair, while, perhaps, Corona just passes by, next street or in front of my actual residence.
  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-13 - 21:05:28
    Well, I'm very late to the P2, and considering how many cool new features there are, find that one could become overwhelmed. To that end I am tackling little things, one chunk at a time, and, hopefully, some of my little experiments will prove useful to others. Thank you for the feedback as it helps me to improve my own code. I've written dozens of commercial programs for the P1, and one client is asking about the P2. I want to be ready to port that code to the P2 when they're actually ready start a new project. It's an exciting device.
  • Another reason to order them as high then low - It's undocumented but I think Chip has implied that GETCT WC has a hidden +2 to the 64-bit count so that it's then count aligned to the partnering subsequent regular GETCT.

  • evanh wrote: »
    Another reason to order them as high then low - It's undocumented but I think Chip has implied that GETCT WC has a hidden +2 to the 64-bit count so that it's then count aligned to the partnering subsequent regular GETCT.

    That's right. I need to review the documentation to make sure that's covered.
  • YanomaniYanomani Posts: 968
    edited 2020-03-13 - 21:51:38
    I believe I've found it, though, eventually, Chip did any other changes, which I wasn't able to find (yet :lol: ).

    https://forums.parallax.com/discussion/comment/1453465/#Comment_1453465
  • evanhevanh Posts: 9,041
    edited 2020-03-14 - 01:02:27
    That verilog bamboozles me. I don't understand things like 32'h2. EDIT: And I thought regscan() was to be ignored too, but that snippet is basically all regscans.

  • That verilog bamboozles me. I don't understand things like 32'h2.
    I don't, either -- and it's peppered through the instruction spreadsheet.
  • AribaAriba Posts: 2,255
    edited 2020-03-14 - 12:45:45
    32'h2 means hexadecimal 2 with a size of 32 bits, in Spin you would write: $00000002

    'regscan is a macro and includes the always @() if I remember correct. But that Verilog is not really understandable without seeing the macro.

    Andy
  • There's a menagerie of symbols and operators inside the regscan brackets. How does that all work? Is that Chip just being concise where it would be clearer done as lots of individual lines per regscan?

  • YanomaniYanomani Posts: 968
    edited 2020-03-15 - 02:39:39
    About four years ago (Got in Himmel!!!), Chip did told us about his motivations while doing the regscan macro, and how it's used along the code.

    forums.parallax.com/discussion/comment/1379869/#Comment_1379869

    Give the timespan between posts (macro definition versus CT use-case) I really don't know if he has edited, or even completelly overhauled it, in order to get the last code the way he wanted, in order to complete the actual P2 incarnation.

    JIT: IMHO, and under the light of the comments appended to the ctlx and cthx-defining macro-expansions, 'h2, 'h1 and 'h0 were simply three moments in time (sysclk-wise), being 'h2 the "now" (or "last"), and 'h1/'h0 just the two preceeding/previous states, thus suggesting the use of registers, if not to hold the whole CTh/l state, at least some important/valuable results, produced at each stage of the logic.

    Based on the above premises, and, sure, from a layman' POV (myself), they are barely/mostly readable/understandable, mainly because the comments were explaining what he had been coding.
  • cgraceycgracey Posts: 12,677
    edited 2020-03-14 - 14:56:27
    Here is the REGSCAN macro:
    `define regscan(regname, reginit, regcond, regval)	\
    	always @(posedge clk or negedge resn)		\
    	if (!resn)					\
    		regname <= reginit;			\
    	else if (regcond)				\
    		regname <= regval;
    

    The terms are as follows:

    1st: The name of the register (group)
    2nd: The initialization value on chip-wide reset
    3rd: The condition on which it is loaded
    4th: The value with which it is loaded

    Having all registers receive the same chip-wide reset allows the synthesis tools to generate the scan chain, where all the registers (flipflops) on the chip get chained together in a serial fashion for writing and reading. I think Wendy broke all this into five scan chains which work over sets of pins when the TEST pin is high.
  • JonnyMacJonnyMac Posts: 6,595
    edited 2020-03-21 - 08:43:00
    It's easy to generate a burst of precisely-timed pulses with the smart pin pulse/cycle mode:
    pub pulses(pin, count, khz) | x
    
    '' Output count pulses on pin
    '' -- khz is output frequency (e.g., 10 = 10_000hz)
    ''    * duty cycle is 50%
     
      x := 2 #> (clkfreq / (kHz * 1000)) <# $FFFF                   ' ticks in period
      x |= ((x >> 1) << 16)                                         ' high ticks
      pinstart(pin, P_OE | P_PULSE, x, 0)                           ' configure smart pin
      wypin(pin, count)                                             ' output the pulses
    
    Thanks to Chip and Roy for sorting me out on the order of things -- the count value must be written into Y after the smart pin is configured.
  • evanhevanh Posts: 9,041
    edited 2020-03-21 - 08:49:10
    There is a gotcha to be aware of with the pulse modes. These modes cycle their pulse "base period" from the moment DIR is raised. This means that any WYPIN pulses/steps to be produced at the pin will only begin at the start of the following base period after WYPIN was executed. There is an exception: If in transition mode (M=%00101) and the base period = 1 (WXPIN #1), then there is no gotcha.

    It only shows up as a complication when trying to phase align the timing of two components like with SPI clock and data for example.

  • It only shows up as a complication when trying to phase align the timing of two components like with SPI clock and data for example.
    Thanks for the tip, Evan -- my next step was to experiment with smart pin SPI output.
  • Cool. Sorry for all the edits, I like to get it clear and precise but that always seems to need many iterations.
Sign In or Register to comment.