Shop OBEX P1 Docs P2 Docs Learn Events
Need help with fast (microsecod timing) code. — Parallax Forums

Need help with fast (microsecod timing) code.

Hello all, I'm new to the propeller and BS2, and programming for that matter. Ive read some threads and looked through some obvious sites, but I cant find a solution to this problem.

I need a square wave that I can vary from 5uS to 20uS. I just need to type the values in, then compile, I'm replacing some of my 555 timers and I want to start with a simple program for this application.

Heres my attempted code:

CON
_CLKMODE = XTAL1 + PLL4X 'low-speed crystal x 4
_XINFREQ = 5_000_000 'external crystal of 5 MHz

PUB main
dira [0] := 1
repeat
outa[0]:=1
waitcnt(clkfreq/100000+cnt)
outa[0]:=0
waitcnt(clkfreq/100000+cnt)


I have a 5Mhz crystal attached, but I'm not sure if its doing anything.
the physical circuit and other code does work. Oscilloscope says slower waves are possible.

Please help.

Comments

  • jmgjmg Posts: 15,173
    I need a square wave that I can vary from 5uS to 20uS. I just need to type the values in, then compile, I'm replacing some of my 555 timers and I want to start with a simple program for this application.

    for square waves also look at

    https://www.parallax.com/downloads/an001-propeller-p8x23a-counters

    There are timer modes for generating square waves.
    A few lines of code will set them up, and you can get 80MHz/N with possible 12.5ns edge jitter on non binary N.
    I have a 5Mhz crystal attached, but I'm not sure if its doing anything.
    the physical circuit and other code does work. Oscilloscope says slower waves are possible.
    If other code works, the 5MHz is ok.

  • Patrick ColemanPatrick Coleman Posts: 43
    edited 2015-10-19 07:24
    Thank you for your interest !

    Ive read the PDF before, and I see it can go fast (12.5ns), but is this related to the clock register?
    Do I load it with values, then use it?

    I also meant to say that id like to control the high and low time separately.


    EDIT:
    the following code did work up to 62uS:


    CON

    _CLKMODE = XTAL1 + PLL16X
    _XINFREQ = 5_000_000


    Pin = 0

    Frequency = 40_000
    PUB main
    dira [0] := 1
    repeat
    outa[0]:=1
    waitcnt(clkfreq/200000+cnt)
    outa[0]:=0
    waitcnt(clkfreq/200000+cnt)


    but I thought a 100kHz wave would be possible with a propeller.
  • SRLMSRLM Posts: 5,045
    A better form would be something like this:
    pin := 0
    delay := clkfreq/100000
    runningCNT := cnt
    
    repeat
        runningCNT += delay
        waitcnt(runningCNT)
        OUTA[pin] := !OUTA[pin]
    

    (note: the syntax may need some tweaking. It's been a while since Spin...)

    The basic idea is that you want your calculation of the next waitcnt point to not be extra on top of the waitcnt delay. If it is you'll get a slower and irregular frequency. As long as the loop can execute before the delay time point comes up this code will work. If you make the delay too short then you'll miss the window and have to wait 53seconds+ for it to roll over.
  • kwinnkwinn Posts: 8,697
    Thank you for your interest !

    Ive read the PDF before, and I see it can go fast (12.5ns), but is this related to the clock register?
    Do I load it with values, then use it?

    I also meant to say that id like to control the high and low time separately.


    EDIT:
    the following code did work up to 62uS:


    CON

    _CLKMODE = XTAL1 + PLL16X
    _XINFREQ = 5_000_000


    Pin = 0

    Frequency = 40_000
    PUB main
    dira [0] := 1
    repeat
    outa[0]:=1
    waitcnt(clkfreq/200000+cnt)
    outa[0]:=0
    waitcnt(clkfreq/200000+cnt)


    but I thought a 100kHz wave would be possible with a propeller.

    Software generated pulses of 100KHz and higher are possible with PASM, but not spin. You would have to use the counters in spin to get to that frequency.
  • kwinnkwinn Posts: 8,697
    Take a look at these objects.

    http://obex.parallax.com/search/signal generator.

    This particular one may do what you want and more.

    http://obex.parallax.com/object/688
  • jmgjmg Posts: 15,173
    ...
    I also meant to say that id like to control the high and low time separately.
    That changes things in Prop-Land, The P1 timers have no Classic-PWM modes, but if you search for real PWM examples (not the PDM (Pulse Density Modulation) that the timers create, some call PWM ).
    Assembly code will be needed to update the HI/LO times 'live', and there will be some lower limit on PWM times.

    If you have spare pins, you could use 2 pins and an external XOR gate, and use Counter-phase control to generate PWM,
    and that would have a LSB step of 12.5ns
  • kwinn wrote: »
    Take a look at these objects.

    http://obex.parallax.com/search/signal generator.

    This particular one may do what you want and more.

    http://obex.parallax.com/object/688

    Ive looked at that code, and it looks like it does what I want, I just don't know how to get it to work. I see numbers at the top for each waveform, but do I uncomment or change one ?

    I'm trying to avoid using my STM32 demo boards, but they do have dedicated timers.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2015-10-19 19:54
    I'd use one I wrote using only the cog counters. http://obex.parallax.com/object/482
    That offers the benefit of the highest resolution, 12.5ns with the 80MHz clkfreq. There are 400 clock transitions in your 5µs/100kHz scenario, which is not that many really given that you want to have varying times of high and low.

    There is a demo there, PWM_3ctrx_demo.spin. To use it in your one program you can include it as an object and then call its method that does the dirty work.
    OBJ
      freak : "PWM_3ctrx_demo"
    PUB freakout | pin, frequency,percent
      pin := 0  ' uses pin and pin+1.  Pin+1 is inverted.
      frequency := 100_000
      percent := 25   ' integer value as written
      freak.PWMctrx3(pin,frequency,percent)
      repeat ' this just keeps it alive and pulsing
    
  • jmgjmg Posts: 15,173
    edited 2015-10-19 19:53
    I'd use one I wrote using only the cog counters. <http://obex.parallax.com/object/482&gt;
    That link needs editing, somehow grabs the trailing > which needs manual removal.
    Test: http://obex.parallax.com/object/482
  • Thx jmg, got it.
  • Patrick ColemanPatrick Coleman Posts: 43
    edited 2015-10-19 20:53
    Ok ive got this code working as you guys have said to look at:
    (I see it ramps an LED from pin 6, so ill need to change that.)

    {{
    File: PWM_3ctrx.spin
    by Tracy Allen, 22 Aug 2010

    Generates conventional pwm with constant frequency & variable duty cycle
    using three cog counters to provide 0-100% on one pin and its complement on the second pin.
    The first two counters overlap phase to give 50% to 100% duty cycle
    and the third counter (in another cog) acts as an inverter to give the 50% to 0% complement.
    A pin swapping scheme keeps the full 0% to 100% and 100% to 0% on the complementary output pins.

    The first two counters are set to the same frequency but with a phase offset that is
    proportional to the desired duty cycle. The Prop inclusive OR pin logic makes the output high
    for 50% plus offset. The third counter (spare one in a different cog) is set up in NCO mode with
    feedback, so its output is the complement of its input, which looks at the output of the first
    two counters. This counter is used only as an inverter so its frqx and phsx settings do not matter.

    Operation is autonomous, without program intervention, once running at the selected
    frequency and duty cycle. An adjustment on the inverter cog counter is only necessary when the
    duty cycle changes over the 50% mark.

    This code spawns a cog for the inverter. Normally though, the inverter will use a spare counter
    in a cog that is used for some other purpose, either spin or pasm. The initialization of the
    counter then should be moved to the code for that cog. If the PWM will pass through the 50% mark,
    there needs to be a mechnism to swap the input and output pin assignment of the inverter.
    In this example the message is passed to the other cog simply by restarting it
    when the percent value passes through 50%.

    If you run this on a demo board, and change the pwmpin to 16,
    you can see the PWM effect on LEDs without a 'scope.
    }}

    CON

    _CLKMODE = XTAL1 + PLL16X
    _XINFREQ = 5_000_000

    VAR
    long testfreq, testpercent, pwmstack[10]
    byte cog, pwmpin,idx , pwxpin , pwypin, pwxold, command

    OBJ

    PUB pwmdemo
    pwmpin :=6 ' using p6 and p7 for the PWM output
    pwxold~~ ' start with this as -1, to force initial update
    repeat
    testfreq := 1000 ' 1000 Hz when clkfreq=80 MHz
    repeat idx from 1 to 3 ' 3 frequencies, 1, 2, 3 kHz
    repeat testpercent from 5 to 95 step 5
    PWMctrx3(pwmpin,testfreq*idx,testpercent)
    waitcnt(clkfreq/5 + cnt) ' pause 0..10 second
    repeat testpercent from 90 to 5 step 5
    PWMctrx3(pwmpin,testfreq*idx,testpercent)
    waitcnt(clkfreq/10 + cnt) ' pause 0..10 second


    PUB PWMctrx3(pin,frequency,percent) ' entry with frequency in Hz
    frequency := fraction(frequency,clkfreq,32) ' calculate angular frequency
    PWMctrx3a(pin,frequency,percent)

    '
    PUB PWMctrx3a(pin,frequency,percent) ' enter with angular frequency in counts per clock tick
    frqa := frqb := 0 ' don't advance during parameter update
    if percent<50 ' this is the pin swapping logic...
    pwxpin := pin+1
    pwypin := pin
    else ' percent >=50 ' ..keeps the 0-100% and its complement
    pwxpin := pin
    pwypin := pin+1
    if pwxpin<>pwxold
    start_pwmInverter
    pwxold := pwxpin
    percent := 50 - percent ' adjust for duty cycle, no phsx offset at 50%
    dira[pwxpin]~~ ' pin is PWM output, pin+1 is helper
    dira[pwypin]~ ' funny, can't do this here, have to do it in pwinverter??
    phsb := phsa + (42949672*percent) ' one percent phase lag is 42949672 counts
    frqa := frqb := frequency ' same frequency both channels
    ctra := ctrb := 00100 << 26 + pwxpin ' %0_00100_000_00000000_000000_000_000000 + pwxpin ' NCO mode counter a & b
    ' note that the counter output on pin is the inclusive OR of the two individual outputs


    PRI start_pwminverter
    ' spawn cog for inverter, see note, this will usually be tacked onto another cog's code
    ' in order to utilize a spare cog counter.
    if Cog
    cogstop(Cog~ - 1) 'Stop previously launched cog
    Cog := cognew(pwminverter, @pwmstack) + 1


    PRI pwminverter
    dira[pwypin]~~ ' remember each cog has its own direction registers!
    dira[pwxpin]~
    dira[23]~~ ' this for demo board,
    ctra := constant(%01001 << 26) + (pwypin << 9) + pwxpin ' %0_01001_000_00000000_000000_000_000000 + (pwypin<<9) + pwxpin
    repeat

    PRI fraction (y, x, b) : f ' calculate f = y/x * 2^b
    ' b is number of bits
    ' enter with y,x: {x > y, x < 2^31, y <= 2^31}
    ' exit with f: f/(2^b) =< y/x =< (f+1) / (2^b)
    ' that is, f / 2^b is the closest appoximation to the original fraction for that b.
    repeat b
    y <<= 1
    f <<= 1
    if y => x '
    y -= x
    f++




    {{
    ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
    │ TERMS OF USE: MIT License │
    ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
    │files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
    │modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
    │is furnished to do so, subject to the following conditions: │
    │ │
    │The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
    │ │
    │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
    │WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
    │COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
    │ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
    └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
    }}

    I'm still new at programming, hence moving on from the BS2 and trying to avoid the STM32. I'm going to look in more detail at this code, it looks complicated. but seems to do the high speed PWM thing.

    EDIT:
    I don't know if I can figure this out, its complicated and I think I'm just going to screw it up.
  • tonyp12tonyp12 Posts: 1,951
    edited 2015-10-19 21:11
    µS is pretty fast, 1µS = 1MHz. You say you need to vary it, I guess just the Hz and not its duty-width?
    Hardware counter (NCO single-ended) and you can set and forget,
    unless you need constant ramping up-down of the Hz after each cycle as then you will be very busy updating the FRQa values.

    But as you have cogs, one can be dedicated to do just that.


  • jmgjmg Posts: 15,173
    I'm going to look in more detail at this code, it looks complicated. but seems to do the high speed PWM thing.

    EDIT:
    I don't know if I can figure this out, its complicated and I think I'm just going to screw it up.

    The engine-room code is a little complex, but you just call it like this :
    freak.PWMctrx3(pin,frequency,percent)

    Very simple to use.
    If you are ok with only 0..50% range, then you can save a pin, and have up to 8 of these running.
  • what if I wanted 2 to 98 % -ish duty cycle?

    I'm still not sure, I cant seem to 2 of the 3 files from : [url="http://obex.parallax.com/object/482"[/url]

    the one I can get to work is just the simple LED ramping one.

    how do a call the freak.PWMctrx3(pin,frequency,percent) ? keep in mind ive only had a few days with spin.
  • jmgjmg Posts: 15,173
    what if I wanted 2 to 98 % -ish duty cycle?
    Then you will need to use the PWM_3ctrx code.

    That uses 3 counters at 2/COG, means you can fit 2 generators into 3 COGS or 4 into 6 or 5 into 8
    How many channels do you need for " replacing some of my 555 timers" ?


    The Counter phase approach used by Tracy, is pretty much the only way to get 2%~98% on 5us, as SW tracking code likely has higher minimum times.
    The HW approach of Counter phase allows 400 steps of Duty Cycle for 0.25% step size at 5us.



  • I just need a single PWM on a single pin. How do I use PWM_3ctrx.spin ?
  • I recall now that at high frequencies there is an offset and funny business in PWM_3ctrx due to delay that comes from Spin starting the counters a few microseconds apart. The frequency is good, but ratio is off. You don't notice that in PWM at 1kHz, but at 100kHz it is brutal. I'll look around for a later version that compensates for that or uses pasm to start it up. The main idea is to get those two cog counters both running at the same frequency but offset in phase by an exact amount.

    Patrick, you're asking how to use it. Can you explain a bit more what your goal is, as you say, "I'm replacing some of my 555 timers and I want to start with a simple program for this application." What application?
  • well my purpose is to have a square wave generator that can drive a transistor. I need to adjust frequency for high voltage transformers. so I can measure Volts-per-turn through an opto-isolator/IGBT and transformer.
  • tonyp12tonyp12 Posts: 1,951
    edited 2015-10-20 17:37
    You say square wave but also mention pwm, you know those are not the same?
    On the Prop1, having a adjustable freq square wave is way simpler than pwm as P1 does not have hardware pwm settings.
    As picture below show, pwm have a fixed freq but its duty can be adjusted (but is not a signal you would use with a transformer).

    on-off-pwm-duty-cycle.gif

  • tonyp12 wrote: »
    You say square wave but also mention pwm, you know those are not the same?
    On the Prop1, having a adjustable freq square wave is way simpler than pwm as P1 does not have hardware pwm settings.
    As picture below show, pwm have a fixed freq but its duty can be adjusted (but is not a signal you would use with a transformer).
    Your right I should have been more specific. And a variable duty cycle is what I need. your pics show it well.
Sign In or Register to comment.