Shop OBEX P1 Docs P2 Docs Learn Events
Propagate pulse signal — Parallax Forums

Propagate pulse signal

Carlos D. LopezCarlos D. Lopez Posts: 9
edited 2010-04-06 15:04 in Propeller 1
Hi,

I'm trying to generate a pulse after a delayed time based on an input pulse. Say pin0 is my trigger, and then after 10k counts set pin1 on for 1000 counts, then after 10_000 more counts set pin2 and then set pin3.

I'm trying to do this inside of a loop that generates a quadrature signal on pins 16 through 19.

here is my code

CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000

VAR
  long pause_counts
  byte quad_cog

PUB start
  stop
  set_Hz(82_250)
  quad_cog := cognew( @quad_entry, @pause_counts ) + 1

PUB stop
  if quad_cog
    cogstop( quad_cog~ - 1 )

PUB set_Hz( Hz )
  ' the update rate is 4x faster than the frequency
  pause_counts := ((clkfreq >> 2) + (Hz>>1) ) / Hz
  'pause_counts:= clkfreq / Hz  

DAT
ORG 0 'Begin at Cog RAM addr 0

{{
        This will be run in its own cog, meaning:
        - we need our own copy of dira
        - we get our own copy of outa
        - I need to get the frequency info from the Hub RAM
          (address is in the PAR register)
}}
quad_entry
        mov quadvalue, all_quad_vals_twice
'        mov outa,all_quad_vals_twice
        mov dira, pin_mask
        add dira, out_mask
        add dira, ledout
        mov outputcount, #0
        
        mov timestamp,#511
        add timestamp,cnt

loop_forever

        mov triggerled, #0
        mov mytrigger, ina                      'Get input all at a time
        and mytrigger, #1                       'Mask only pin one
        mov triggerled, mytrigger
                
        cmp mytrigger, #1 wz                    'if triggered reset counter
  if_z  mov outputcount, #0

        add outputcount, #1                     'Add to counter
        mov MYKoutput, #0
'
        cmp waitM, outputcount wc
  if_c  jmp labelMag     'Magenta 
labelretMag
        cmp waitY, outputcount wc
  if_c  jmp labelYel     'Yellow
labelretYel
        cmp waitK, outputcount  wc
  if_c  jmp labelBlk     'Black
labelretBlack           


        rdlong delay_counts,par
        waitcnt timestamp, delay_counts
        
        ror quadvalue,#4   'rotate quadrature output
        mov outavalue, quadvalue
        shr outavalue, #7  'make blanks for first 7 pins
        shl outavalue, #7

        shl triggerled, #22
        add outavalue, triggerled
        
        add outavalue, MYKoutput
        mov outa, outavalue
        jmp #loop_forever

labelMag
        cmp outputcount, waitM100 wc
   if_c mov MYKoutput, #%1100010
        jmp #labelretMag
labelYel
        cmp outputcount, waitY100 wc
   if_c mov MYKoutput, #%1010100
        jmp #labelretYel
labelBlk
        cmp outputcount, waitK100 wc
   if_c mov MYKoutput, #%0111000
        jmp #labelretBlack
        
{===== PASM constants and parameters =====}
pin_mask                long %1111 << 16
out_mask                long %1111110
all_quad_vals_twice     long %1001_0101_0110_1010____1001_0101_0110_1010
Delay                   long 12_000_000
waitM                   long 10_408
waitM100                long 11_508
waitY                   long 20_816
waitY100                long 21_916
waitK                   long 31_224
waitK100                long 32_324
ledout                  long %1 << 22

{===== PASM scratch variables =====}
' Remember, all RES variables _MUST_ come after all LONG variables 
delay_counts            res 1
timestamp               res 1
quadvalue               res 1
outavalue               res 1
MYKoutput               res 1
outputcount             res 1
mytrigger               res 1
triggerled              res 1
' make sure this whole thing fits inside a single cog
FIT 496




This is not working. I'll appreciate any help

Thanks.

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2010-04-05 15:32
    One of the main advantages of the Propeller is that it has multiple processors since sometimes complex problems become very simple once you dedicate a processor to each piece of the problem. Why not use one cog just to handle the delay and pulse generation?

    You could use a WAITPNE to wait for the trigger on pin 0, then a WAITCNT to wait for the 10K system clocks to go by, turn on pin 1, use a WAITCNT to wait for the 1K system clocks, turn off pin 1, use WAITCNT to wait for another 10K system clocks, then turn on pins 2 and 3, then use WAITPEQ to make sure the trigger is turned off and go back to wait for a new trigger. We're talking about maybe 15-20 instructions here. It's simple and straightforward.
  • Carlos D. LopezCarlos D. Lopez Posts: 9
    edited 2010-04-05 15:48
    Thanks for the response,

    That sounds good, the thing is that the counts are not propeller chip counts, but counts of my quadrature signal that I'm generating based on a specific frequency. That is why I am placing the code inside of the loop that generates these counts. So these 10k counts are not necessarily the system counts.
  • pjvpjv Posts: 1,903
    edited 2010-04-05 16:07
    Hello Carlos;

    This is a perfect application example for using the PropRTOS I entered in the Prop contest. Take a read through that, and on understanding it, I can then help you get this going very easily.

    Cheers,

    Peter (pjv)
  • Mike GreenMike Green Posts: 23,101
    edited 2010-04-05 16:09
    You can accomplish what you want pretty easily by using co-routines. The JMPRET instruction is a very easy way to implement this. One example of its use is the FullDuplexSerial driver which goes back and forth between the receive and transmit code this way. Another example is the initialization code in the TV driver which runs during the vertical retrace interval.

    You'd have a JMPRET in your quadrature counting code (JMPRET saveLoc,nextLoc). "saveLoc" is an uninitialized long variable in the cog. "nextLoc" is another long variable initialized to the address of the beginning of your pulse handling routine.
    handler   jmpret  nextLoc,saveLoc   ' return to quadrature code
                  test      pin0Mask,ina   wc
       if_nc    jmp      #handler             ' wait for pin 0 to go high
                  mov     counter,const10000
    nextLp1  jmpret  nextLoc,saveLoc
                 djnz      counter,nextLp1   ' wait for 10000 counts
                 or         outa,#%0010       ' turn on pin 1
                 mov      counter,const1000
    nextLp2  jmpret   nextLoc,saveLoc
                 djnz      counter,nextLp2   ' wait for 1000 counts
                 andn     outa,#%0010       ' turn off pin 1
                 mov      counter,const10000
    nextLp3  jmpret   nextLoc,saveLoc
                 djnz       counter,nextLp3  ' wait for 10000 counts
                 or         outa,#%1100      ' turn on pins 2 and 3
    nextLp4  jmpret   nextLoc,saveLoc
                 test       pin0Mask,ina   wc
       if_c     jmp       #nextLp4           ' wait for pin 0 to go low
                 andn      outa,#%1100    ' turn off pins 2 and 3
                 jmp       #handler           ' start all over again
    


    This will need some initialization in the main routine, but you should get the idea.
  • Carlos D. LopezCarlos D. Lopez Posts: 9
    edited 2010-04-05 17:47
    THanks for the response again, I added your code to mine and changed it a bit. But what I'm getting in pins 1 - 7 is the same pulse train I'm generating.
    Here's the code:


    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
    
    VAR
      long pause_counts
      byte quad_cog
    
    PUB start
      stop
      set_Hz(36_696)
      quad_cog := cognew( @quad_entry, @pause_counts ) + 1
    
    PUB stop
      if quad_cog
        cogstop( quad_cog~ - 1 )
    
    PUB set_Hz( Hz )
      ' the update rate is 4x faster than the frequency
      pause_counts := ((clkfreq >> 2) + (Hz>>1) ) / Hz
      'pause_counts:= clkfreq / Hz  
    
    DAT
    ORG 0 'Begin at Cog RAM addr 0
    
    {{
            This will be run in its own cog, meaning:
            - we need our own copy of dira
            - we get our own copy of outa
            - I need to get the frequency info from the Hub RAM
              (address is in the PAR register)
    }}
    quad_entry
            mov outa,all_quad_vals_twice
            mov outmask, pin_mask
            or outmask, #%1111110
            mov dira,outmask
            mov timestamp,#511
            add timestamp,cnt
            mov quadvalue, all_quad_vals_twice
    loop_forever
    nextLoc
            mov outMYK, #%0000000
            rdlong delay_counts,par
            waitcnt timestamp, delay_counts
            rol quadvalue,#4
            mov outvalue, quadvalue
            or outvalue, outMYK
            mov outa, outvalue
            jmp #loop_forever
    
    handler   jmpret        nextLoc,saveLoc   ' return to quadrature code
                  test      pin0Mask,ina   wc
       if_nc      jmp       #handler             ' wait for pin 0 to go high
                  mov       counter,const10000
    nextLp1   jmpret        nextLoc,saveLoc
                  djnz       counter,nextLp1   ' wait for 10000 counts
                  or         outMYK,#%1100010       ' turn on pin 1
                  mov        counter,const1000
    nextLp2  jmpret         nextLoc,saveLoc
                  djnz       counter,nextLp2   ' wait for 1000 counts
                  andn       outMYK,#%1100010       ' turn off pin 1
                  mov        counter,const10000
    nextLp3  jmpret         nextLoc,saveLoc
                  djnz       counter,nextLp3  ' wait for 10000 counts
                  or         outMYK,#%0011100      ' turn on pins 2 and 3
    nextLp4  jmpret         nextLoc,saveLoc
                 test       pin0Mask,ina   wc
       if_c     jmp         #nextLp4           ' wait for pin 0 to go low
                 andn       outMYK,#%0011100    ' turn off pins 2 and 3
                 jmp        #handler           ' start all over again
                 
    {===== PASM constants and parameters =====}
    pin_mask                long %1111 << 16
    all_quad_vals_twice     long %1001_0101_0110_1010____1001_0101_0110_1010
    Delay                   long 12_000_000
    pin0Mask                long %0001
    const1000               long 1000
    const10000              long 10_000
    
    {===== PASM scratch variables =====}
    ' Remember, all RES variables _MUST_ come after all LONG variables 
    delay_counts            res 1
    timestamp               res 1
    saveLoc                 res 1
    counter                 res 1
    quadvalue               res 1
    outvalue                res 1
    outmask                 res 1
    outMYK                  res 1
    ' make sure this whole thing fits inside a single cog
    FIT 496
    
    



    Thanks for your help.
  • Mike GreenMike Green Posts: 23,101
    edited 2010-04-05 17:58
    "nextLoc" needs to be a long variable initialized to the address of the co-routine (MOV nextLoc,#handler).

    You also need a "JMPRET saveLoc,nextLoc" somewhere in your quadrature counting code. Reread the 2nd paragraph in my earlier message.
  • Carlos D. LopezCarlos D. Lopez Posts: 9
    edited 2010-04-06 14:52
    Ok here is the code fixing the previous suggestion, but it doesn't work:

    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
    
    VAR
      long pause_counts
      byte quad_cog
    
    PUB start
      stop
      set_Hz(36_696)
      quad_cog := cognew( @quad_entry, @pause_counts ) + 1
    
    PUB stop
      if quad_cog
        cogstop( quad_cog~ - 1 )
    
    PUB set_Hz( Hz )
      ' the update rate is 4x faster than the frequency
      pause_counts := ((clkfreq >> 2) + (Hz>>1) ) / Hz
      'pause_counts:= clkfreq / Hz  
    
    DAT
    ORG 0 'Begin at Cog RAM addr 0
    
    {{
            This will be run in its own cog, meaning:
            - we need our own copy of dira
            - we get our own copy of outa
            - I need to get the frequency info from the Hub RAM
              (address is in the PAR register)
    }}
    quad_entry
            mov outa,all_quad_vals_twice
            mov outmask, pin_mask
            or outmask, #%1111110
            mov dira,outmask
            mov timestamp,#511
            add timestamp,cnt
            mov quadvalue, all_quad_vals_twice
    loop_forever
            mov outMYK, #%111111
            mov nextLoc, #handler
            jmpret saveLoc, nextLoc
    
            rdlong delay_counts,par
            waitcnt timestamp, delay_counts
            rol quadvalue,#4
            mov outvalue, quadvalue
            or outvalue, outMYK
            mov outa, outvalue
            jmp #loop_forever
    
    handler   jmpret        nextLoc,saveLoc   ' return to quadrature code
                  test      pin0Mask,ina   wc
       if_c      jmp       #handler             ' wait for pin 0 to go high
                  mov       counter,const10000
    nextLp1   jmpret        nextLoc,saveLoc
                  djnz       counter,nextLp1   ' wait for 10000 counts
                  or         outMYK,#%1100010       ' turn on pin 1
                  mov        counter,const1000
    nextLp2  jmpret         nextLoc,saveLoc
                  djnz       counter,nextLp2   ' wait for 1000 counts
                  andn       outMYK,#%1100010       ' turn off pin 1
                  mov        counter,const10000
    nextLp3  jmpret         nextLoc,saveLoc
                  djnz       counter,nextLp3  ' wait for 10000 counts
                  or         outMYK,#%0011100      ' turn on pins 2 and 3
    nextLp4  jmpret         nextLoc,saveLoc
                 test       pin0Mask,ina   wc
       if_nc     jmp         #nextLp4           ' wait for pin 0 to go low
                 andn       outMYK,#%0011100    ' turn off pins 2 and 3
                 jmp        #handler           ' start all over again
                 
    {===== PASM constants and parameters =====}
    pin_mask                long %1111 << 16
    all_quad_vals_twice     long %1001_0101_0110_1010____1001_0101_0110_1010
    Delay                   long 12_000_000
    pin0Mask                long %0001
    const1000               long 1000
    const10000              long 10_000
    
    {===== PASM scratch variables =====}
    ' Remember, all RES variables _MUST_ come after all LONG variables 
    delay_counts            res 1
    timestamp               res 1
    saveLoc                 res 1
    nextLoc                 res 1
    counter                 res 1
    quadvalue               res 1
    outvalue                res 1
    outmask                 res 1
    outMYK                  res 1
    ' make sure this whole thing fits inside a single cog
    FIT 496
    
    



    I also tried creating another file with just waitcnt, but I can't get it to run with the following sintax

    waitcnt (<countstowait> * clkfreq / <frequency> + cnt) this doesn't wait, here is my code:


    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
    
    VAR
      long pause_counts
      long waitcount
      byte mycogID
    
    PUB start
      stop
      setHz(45_250)
      mycogID := cognew( checkpins,0)
    
    PUB stop
      if mycogID
        cogstop( mycogID~ - 1 )
    
    PUB setHz(Hz)
      pause_counts := Hz
      waitcount := clkfreq / (2 ) 
      checkpins
          
    PRI checkpins | camming, Time
       DIRA := %111_0000000000000_111_111_0' << 20
       outa := %000000
       Time := cnt
       repeat
          if ina[noparse][[/noparse]0]==0
            camming := 0
          waitpne(%0000, %0001, 0)                       
          if ina[noparse][[/noparse]0]==1 AND camming == 0
              sendcam
              camming := 1
             
    PRI sendcam
          outa:=1
          outa:=1
          outa:=1
          outa:=0
          outa:=0
          outa[noparse][[/noparse]6]:=0
            
          'Time := Time + 10808 * clkfreq / pause_counts
          waitcnt(10_708 * clkfreq / pause_counts  + cnt)
          waitcnt(10_708 * clkfreq / pause_counts  + cnt)
    
          outa[noparse][[/noparse]20]:=0
          outa:= 1
          outa:= 0
                
          waitcnt(clkfreq / 5 + cnt)
          outa[noparse][[/noparse]20]:=1
          outa:=0
          outa:=1
          
          waitcnt(10_708* clkfreq / pause_counts + cnt)
          waitcnt(10_708 * clkfreq / pause_counts  + cnt)
          outa[noparse][[/noparse]21]:=0
          outa:=1
          outa:=0
                
          waitcnt(clkfreq / 5 + cnt)
          outa[noparse][[/noparse]21]:=1
          outa:=0
          outa:=1
          
          waitcnt(10_708 * clkfreq / pause_counts + cnt)
          waitcnt(10_708 * clkfreq / pause_counts  + cnt)
          outa[noparse][[/noparse]22]:=0
          outa[noparse][[/noparse]6]:=1
          outa:=0
          
          waitcnt(clkfreq / 5 + cnt)
          outa[noparse][[/noparse]22]:=1
          outa[noparse][[/noparse]6]:=0
          outa:=1
    
          'waitpeq(%0000, %0001, 0)
    
          
    
    



    Thanks for any help.
  • Mike GreenMike Green Posts: 23,101
    edited 2010-04-06 15:04
    The "mov nextLoc,#handler" is for initialization. It needs to be part of your initialization code, not the main loop.

    Please take a little time to try to understand what this code does. I know that JMPRET is an unusual instruction for most people, particularly when used this way, but it will be worth your time to try to understand what's going on here.

    The problem you're running into with CLKFREQ is overflow during the multiplication. 10_000 * CLKFREQ is much larger than 32 bits. You may need parentheses like: 10808 * (clkfreq / pause_counts)
Sign In or Register to comment.