Shop OBEX P1 Docs P2 Docs Learn Events
PNut/Spin2 Latest Version (v47 - Cooperative multitasking added to Spin2, up to 32 tasks) - Page 11 — Parallax Forums

PNut/Spin2 Latest Version (v47 - Cooperative multitasking added to Spin2, up to 32 tasks)

18911131470

Comments

  • RaymanRayman Posts: 14,755
    @JonnyMac I posted this in Mixed Signal Scope thread... Maybe helps you:
    The docs for NCO duty mode are not very clear...
    It doesn't actually tell you how to set the %duty.
    
    I just played with it and see now that Y controls duty.
    Y=$FFFF_FFFF is 100% duty, Y=$8000_0000 is 50% duty and Y=0 is 0% duty.
    
    Makes some sense now...
    
    X controls the minimum pulse width apparently. Not exactly sure how...
    
  • whicker wrote: »
    Does what Chip said on April 8 (scroll up) also apply here? Does the first y in pinstart have to be 0?
    Should pinstart( ) be modified to have two y values? (Before and after?)
    I tried that -- it didn't make a difference.
  • X controls the minimum pulse width apparently. Not exactly sure how...
    Thanks for the nudge, @Rayman. I changed the value of X and am now getting better output. Going to build a table to determine how X affects the output frequency. It could be that at 1, the capacitance of my 'scope lead was destroying the signal.
  • AribaAriba Posts: 2,690
    edited 2020-04-11 17:57
    This gives a 100 kHz Signal with a 100ns high-pulse on my scope:
      _clkfreq = 100_000_000
     
    PUB Duty() | x,y
      x := 10
      y := 1 frac 100
      pinstart(34, %01_00111_0, x, y)
      repeat
    

    Andy
  • JonnyMacJonnyMac Posts: 9,159
    edited 2020-04-11 18:29
    I got that, too, Andy. I did a quick test to determine how X affects output frequency.

    For duty cycle in range 0.01 to 0.50...
    fr = clkfreq / X * duty_cycle
    
    Note that 50% is the highest frequency because that value causes a carry every other cycle.

    With X at 1 I'm guessing my 'scope probe could not handle the frequency.

    391 x 336 - 9K
  • A minor documentation (ver. 34m) change. In PUB MinimalSpin2Program() 'first PUB method executes
    PINWRITE(63..56, GETRND) 'write a random pattern to P63..P56 needs () after GETRND

    John Abshier

  • cgraceycgracey Posts: 14,206
    Here is an NCO-duty smart pin program that updates at 1MHz and makes a 50% duty output:
    CON
      _clkfreq	= 180_000_000
      UpdateRate	= 1_000_000	
      BaseTicks	= _clkfreq / UpdateRate
      DutyPercent	= 50
      DutyValue	= DutyPercent FRAC 100
    
    PUB go()
      PINSTART(56, P_OE | P_NCO_DUTY, BaseTicks, DutyValue)
      REPEAT
    
  • RaymanRayman Posts: 14,755
    What does update rate mean?
    I think I’d want it defined in terms of period in clocks and duty fraction (this one is just Y, easy)
  • Rayman wrote: »
    What does update rate mean?
    I think I’d want it defined in terms of period in clocks and duty fraction (this one is just Y, easy)
    Code written for a specific CPU clock speed falls apart in the real world when that speed changes.
  • RaymanRayman Posts: 14,755
    Which is why I proposed period in terms of clocks instead of frequency... But, it's just some math to convert...
  • cgraceycgracey Posts: 14,206
    I was trying to show the timing relationships. You could just define BaseTicks directly.
  • RaymanRayman Posts: 14,755
    Ok, I get it now. I think I'd change "update rate" to "NCO Frequency".
  • JonnyMacJonnyMac Posts: 9,159
    edited 2020-04-12 18:39
    Ok, I get it now. I think I'd change "update rate" to "NCO Frequency".
    In NCO_DUTY mode, for any given X, the output frequency will change with duty cycle, hence that may not be an accurate descriptor.
  • RaymanRayman Posts: 14,755
    I thought remembered there was something strange going on there...

    It'd be nice to be able to specify this in terms of NCO Frequency and Duty.
  • JonnyMacJonnyMac Posts: 9,159
    edited 2020-04-12 19:39
    Not with the NCO modes. In NCO_FREQ, you can specify the frequency but always get a duty cycle of 50%. In NCO_DUTY, you can specify the duty cycle, but the frequency varies (50% dc produces the highest frequency for any give X, dc of 1 produces the lowest [51..91 mirrors 1..49]). The only way to have control of both is with PWM_ modes, triangle being the most straightforward.
  • RaymanRayman Posts: 14,755
    Thanks, I can see that.
    But I still don’t understand exactly what baseticks setting does then...
  • X really acts like a clock divisor for the NCO modes. Internally the pin counts from X to 1, and then adds Y into Z. In NCO_FREQ, the pin output is z.[31]. In NCO_DUTY, the output is the carry bit after the addition.
  • RaymanRayman Posts: 14,755
    That sounds right. I hope there turns out to be an easier way to understand it in the future.
  • Thankfully, PWM allows one to control frequency and duty-cycle -- though the low-end frequency is limited by the 16-bit counts used.
  • AribaAriba Posts: 2,690
    edited 2020-04-12 22:40
    Not sure why the duty mode gets so much attention here. This mode is rather obsolet on the P2. Now we have real PWM and 16bit dithered DAC modes.
    Is there some application that needs duty mode?

    Andy
  • RaymanRayman Posts: 14,755
    edited 2020-04-12 22:25
    I have no idea what it's good for... Have to figure out what is does first...

    It's a good question though. Is there some intended use for this?
  • JonnyMacJonnyMac Posts: 9,159
    edited 2020-04-12 23:56
    I wonder if it's a carry-over from the P1 counter NCO and DUTY modes. While trying to figure out what was going on, I hooked up a P1 and could see the output on my 'scope. I couldn't with the P2 because I had X too small hence the output frequency was too fast for my 'scope probes. In the P1 I used NCO mode for creating a known frequency, and Chip used DUTY mode for the output of his stereo_dacs object that I use in my WAV player.
  • evanhevanh Posts: 16,032
    JonnyMac wrote: »
    ... and Chip used DUTY mode for the output of his stereo_dacs object that I use in my WAV player.
    That makes a lot of sense. Intended as a cheap DAC substitute. As I noted in the other topic, it does have very similar properties to sigma-delta.

  • RaymanRayman Posts: 14,755
    Andy's got me thinking about use case... Doesn't make any sense for audio when you have a DAC.

    But, if your driving some kind of external circuit that has digital and not analog control, might be useful...
  • evanhevanh Posts: 16,032
    edited 2020-04-13 00:17
    Right, and as Jon says, Chip probably threw it in because was in the prop1 and isn't a burden to include. Those two NCO modes will be the smallest circuit size of the smartpin modes. Well, except for the "repository" modes.
  • Those modes may have been included to facilitate quick porting from P1 to P2.
  • Cluso99Cluso99 Posts: 18,069
    edited 2020-04-13 04:18
    SPIN2 Questions

    Not sure of the best thread to ask, so I'll ask here...

    The docs imply that spin uses Cog $140-$1D7 (and of course $1F0-$1FF) and all LUT $200-$3FF. A memory diagram would be nice at some time.

    The docs imply that Cog registers $1D8-$1DF are for use between pasm and spin, and can be referenced as PR0-PR7 in spin.

    So that leaves Cog $000-$13F and registers $1E0-$1EF for p2asm routines, and $1D8-$1DF for common registers between spin2 and p1pasm?

    However, looking at the spin2 interpreter code, I see that cog_code starts at $132. So I presume the docs are wrong.

    P2 ROM Code

    Now the ROM Monitor/Debugger uses Cog registers $1E0-$1EF so these routines should be callable from spin2 :)

    But the ROM SD Driver uses Cog registers $1C0-$1DF so these routines cannot be called from Spin2 :(

    How do you call pasm from spin2

    These methods are listed
    CALL(Addr)      CALL PASM code at Addr, PASM code should avoid registers $140..$1D7 and LUT
    REGEXEC(Addr)   Load PASM code at Addr into registers and CALL it: WORD StartReg, WORD NumRegs, instructions
    REGLOAD(Addr)   Load PASM code at Addr into registers: WORD StartReg, WORD NumRegs, instructions
    

    I am guessing that the parameter "Addr" points to an address containing a structure...
      WORD @StartReg
      WORD NumRegs
      instructions ???
    
    but how do we tell the method where the code is located in hub ???

    Alternately, if "Addr" is the hub address, then how do we pass the word StartReg and the word NumRegs to the method?

    Looking at the interpreter code it looks like these routines are passed the hub address in the method call, and the hub address starts (ie prefixed) with two words (which are not loaded), the first being the cog address (to load into) followed by the length-1 (length of longs to load), and then followed by the code to be loaded.

    An example of their use would be nice please ;)
  • cgraceycgracey Posts: 14,206
    edited 2020-04-13 05:18
    Cluso99 wrote: »
    SPIN2 Questions

    Not sure of the best thread to ask, so I'll ask here...

    The docs imply that spin uses Cog $140-$1D7 (and of course $1F0-$1FF) and all LUT $200-$3FF. A memory diagram would be nice at some time.

    The docs imply that Cog registers $1D8-$1DF are for use between pasm and spin, and can be referenced as PR0-PR7 in spin.

    So that leaves Cog $000-$13F and registers $1E0-$1EF for p2asm routines, and $1D8-$1DF for common registers between spin2 and p1pasm?

    However, looking at the spin2 interpreter code, I see that cog_code starts at $132. So I presume the docs are wrong.

    P2 ROM Code

    Now the ROM Monitor/Debugger uses Cog registers $1E0-$1EF so these routines should be callable from spin2 :)

    But the ROM SD Driver uses Cog registers $1C0-$1DF so these routines cannot be called from Spin2 :(

    How do you call pasm from spin2

    These methods are listed
    CALL(Addr)      CALL PASM code at Addr, PASM code should avoid registers $140..$1D7 and LUT
    REGEXEC(Addr)   Load PASM code at Addr into registers and CALL it: WORD StartReg, WORD NumRegs, instructions
    REGLOAD(Addr)   Load PASM code at Addr into registers: WORD StartReg, WORD NumRegs, instructions
    

    I am guessing that the parameter "Addr" points to an address containing a structure...
      WORD @StartReg
      WORD NumRegs
      instructions ???
    
    but how do we tell the method where the code is located in hub ???

    Alternately, if "Addr" is the hub address, then how do we pass the word StartReg and the word NumRegs to the method?

    Looking at the interpreter code it looks like these routines are passed the hub address in the method call, and the hub address starts (ie prefixed) with two words (which are not loaded), the first being the cog address (to load into) followed by the length-1 (length of longs to load), and then followed by the code to be loaded.

    An example of their use would be nice please ;)

    The calibrated 8-channel ADC program I posted uses REGEXEC, which loads a program that starts with two words:

    http://forums.parallax.com/discussion/171394/adc-to-millivolts-running-in-background-of-spin2

    And, yes, the Spin2 docs need to be updated to reflect a PASM space of $000..$131.
  • Cluso99Cluso99 Posts: 18,069
    Hooray :)

    I've called the ROM Monitor/Debugger from spin :)

  • Cluso99Cluso99 Posts: 18,069
    edited 2020-04-13 07:48
    Chip,
    Is this legitimate?
    CON
      lmm_x         = $1e0          ' parameter passed to/from LMM routine (typically a value)
      lmm_f         = $1e1          ' parameter passed to      LMM routine (function options; returns unchanged)
      lmm_p         = $1e2          ' parameter passed to/from LMM routine (typically a hub/cog ptr/addr)
      lmm_p2        = $1e3          ' parameter passed to/from LMM routine (typically a 2nd hub/cog address)
      lmm_c         = $1e4          ' parameter passed to/from LMM routine (typically a count)
    
    PUB go()
        REG[lmm_x]  := $1000                                ' start address
        CALL(_HubHex8)                                      ' print in hex, 8 digits
        CALL(_hubTxCR)                                      ' print cr+lf
    
        REG[lmm_p]  := $1000                                ' start address
        REG[lmm_x]  := REG[lmm_p]                           ' copy start address
        CALL(_HubHex8)                                      ' print in hex, 8 digits
        CALL(_hubTxCR)                                      ' print cr+lf
    
        REG[lmm_x]  := $1000                                ' start address
        REG[lmm_x]  += 256                                  ' end addrs = start + length(bytes)
        CALL(_HubHex8)                                      ' print in hex, 8 digits
        CALL(_hubTxCR)                                      ' print cr+lf
    
    because...
    1) lmm_x = $00001000 correct
    2) lmm_x = $0000001F incorrect
    3) lmm_x = $F60BACE0 incorrect


    Next, after spin code, this DAT ORGH $4000 is set to hub $1000 and not $4000 (ie code is placed into hub at $1000)
    ''============[ HUB VARIABLES ]=================================================                                    
    DAT             
                    orgh    $4000
    str_fun         byte    "Fun with P2 ROM v010",13,10,0
    str_msg         byte    "More P2 fun...",13,10,0
                    alignl                                                                                                     
    ''---------------------------------------------------------------------------------------------------
    

    I have also noticed that some CALL statements appear to sometimes return missing the next CALL. I haven't tracked this down yet.
Sign In or Register to comment.