Timing Pulse Generation

Home Up

bullet

My main goal for the Prop is to produce precise timing for an H-Bridge DC-DC converter.  This requires 1-us precision.

bullet

With the Prop at 80 MHz, each cogs is executing 20 MIPS.  So, each assembly instruction (that doesn't use hub) takes 50 ns.  So, the basic resolution is 50 ns.  The maximum frequency is 10 MHz with a 100-ns period.

bullet
It may be possible to use multiple, interleaved cogs to do better.
bullet
Also possible to use counters within a cog to get 12.5 ns resolution
bullet
Also possible to use system counter to get 12.5 ns resolution 
bullet

Since SPIN is interpreted at run time, it is probably difficult to a priori determine the timing of a piece of SPIN code.  So, the plan is to do this in assembly.  But, we'll take a look at SPIN timing anyway.   Maybe can work with counter module?

bullet

The following is all with the 80 MHz clock speed (12.5 ns period).

bullet

Download the code for the examples below here.

bullet

Using Spin

bullet

Taking a look at SPIN code timing...

bullet

Using WaitCnt (from Manual's Toggle example):

bullet

PUB Toggle(Pin, Delay, Count)
{{Toggle Pin, Count times with Delay clock cycles in between.}}

dira[Pin]~~ 'Set I/O pin to output direction
repeat Count 'Repeat for Count iterations
!outa[Pin] ' Toggle I/O Pin
waitcnt(Delay + cnt) ' Wait for Delay cycles 

bullet
Turns out that minimum "Delay" is 381.  This is due to the time it takes the SPIN interpreter to process the command.  With a delay of 381 (4.762 us), the Toggle pulse is 21.00-us wide and the period of the cycle is 42.00 us.
bullet
This is no where near what we need!
bullet

Using !OutA chain 

bullet
Instead of using WaitCnt, to insert delay, just using a chain of !OutA commands.  This is probably about the fastest that SPIN can affect the output without using the counter module.
bullet PUB Toggle2(Pin, Delay, Count)
{{Toggle Pin, Count times with Delay clock cycles in between.}}

dira[Pin]~~ 'Set I/O pin to output direction
!outa[Pin]
!outa[Pin]
!outa[Pin]
!outa[Pin]
!outa[Pin]
!outa[Pin]
!outa[Pin]

  bullet

This produces a train of pulses with 9.20-us width and 18.40-us period.  Again, this is not fast enough to achieve 1-us timing.
bullet

Using Counter Module

bullet
This seems a little tricky, but maybe can program the counter module with SPIN to get the desired output...
bullet
Trying this code (adapted from the Propeller Counters App Note).
bullet

PUB Toggle3(Pin)
'Use cog's counter module to toggle at clock speed

dira[Pin]~~ 'Set I/O pin to output direction
' mode PLL BPIN APIN
ctra := %00100_000 << 23 + 1 << 9 + Pin 'Establish mode and APIN (BPIN is ignored)
frqa := $8000_0000 'Set FRQA so PHSA[31] toggles every clock
'repeat 'infinite loop, so counter

bullet
This produces a 12.6-ns wide pulse with 25.0-ns period!  So, it seems we can get fast behavior with SPIN.
bullet
But, what I really need is to control pulses on 2 pins.  One is on for 54 us, then off for the balance of 110-us period.  The other should be off for 55 us, then on for 54 us, then off for the balance.
bullet
Problem is that I want to be able to generate exactly 100 of these pulses and then stop.  I don't see an easy way to do this precisely...
bullet

Using Assembly

bullet

Fast Toggle Loop

bullet
This is a slightly modified version of the first example in deSilva's assembly guide.  It was modified to only affect pin7 instead of pins0..7
bulletPUB Toggle4
'toggle with assembly
    cognew(@ex01A, 0)


DAT
    ORG 0
ex01A
    MOV DIRA, #$80 '(Cell 0) Make P7 output
    MOV pattern, #0 '(Cell 1) Initialize output parameter
loop
    MOV OUTA, pattern '(Cell 2) Output the pattern to P7
    ADD pattern, #$80 '(Cell 3) Toggle P7 output
    JMP #loop '(Cell 4) repeat loop

pattern LONG $AAAAAAAA '(Cell 5)
    FIT 496
bullet
This produces a 150-ns pulse width 300-ns period
bullet
Each instruction takes 50-ns, so this makes sense as there are 3 instructions in the toggle loop.
bullet

Hard Coded Toggling

bullet
In order to achieve 50-ns pulse width, we can hard code the toggling:
bullet
PUB Toggle5
'toggle with assembly
    cognew(@HardCode, 0)


DAT
    ORG 0
HardCode
    MOV DIRA, #$80 '(Cell 0) Make P7 output
    MOV OUTA, #0 'init to 0
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
    XOR OUTA, #$80 'toggle
'now stop
    COGID thisCog
    COGSTOP thisCog


thisCog LONG 5 '0=SPIN, 1=keyboard, 2=mouse, 3=VGA, 4=VGA, 5=This


    FIT 496
bullet
This produces 6 pulses with 50-ns width and 100-ns period.
bullet
But, we can only have 496 instructions, so the total possible burst length is 24.8 us.  But, I need about 200 ms of pulses, so this won't work...  
bullet

Using  CMP n,CNT

bullet
What I'd really like to do is control two (or more) pins, each with pulse parameters:
bullet
Delay:  wait this long from start time before starting pulse
bullet
Width:  pulse is this long
bullet
And, global parameters:
bullet
Period:  start over again after this time
bullet
# in Burst:  repeat for this number of periods
bullet
Because I only need 1-us precision, I can afford a few extra instructions on the loop.  Each instruction is 50 ns.  So, I need 20 instructions in the loop...
bullet
Finally, got it going with 1-us loop time!  Here's the core code:
bullet
InitClock
        'get initial clock time
        MOV StartCNT,CNT
        
        'Start period loop
CycleLoop
        NOP   'to syncronize cycle and burst loops
        NOP     
BurstLoop
        MOV pattern1, DMaskT0 '#$00  're-init output pattern
        
        MOV thisCNT, CNT 'get current clock time
        SUB thisCNT, StartCNT  'calc offset from period start time
        'see if it is time to start pulse
        CMP thisCNT, DelayA wz, wc
        IF_AE OR pattern1,DMaskA
        CMP thisCNT, DelayB wz, wc
        IF_AE OR pattern1,DMaskB
        CMP thisCNT, DelayC wz, wc
        IF_AE OR pattern1,DMaskC
        'see if time to end pulse
        CMP thisCNT,WidthA wz, wc
        IF_AE XOR pattern1,DMaskA
        CMP thisCNT,WidthB wz, wc
        IF_AE XOR pattern1,DMaskB
        CMP thisCNT,WidthC wz, wc
        IF_AE XOR pattern1,DMaskC
        'output pattern
        MOV OUTA, pattern1  
        'see if time to end period
        CMP thisCNT,Period wz, wc
        IF_B JMP #CycleLoop
        'start new period
        MOV StartCNT, CNT
        DJNZ NBurst,#BurstLoop 
bullet
Sadly, can only control 3 channels this way (was hoping for 4)
bullet
 Could probably do more channels with more elaborate code, but this way is nice and simple.
bullet
Have Implemented this and posted the "Delay Generator Demo" to user forum.  Can also be found here in the programming section..

 

 

 

 

 

 

 

Copyright 2007 Raymond Allen