Shop OBEX P1 Docs P2 Docs Learn Events
timing pulse edge with CTRA register (is it possible?) — Parallax Forums

timing pulse edge with CTRA register (is it possible?)

courtenscourtens Posts: 101
edited 2013-03-22 13:37 in Propeller 1
I based all my code on the main clock (cnt) but realized that what I really need is a time counter from a pulse edge.

I would like to code a function that provides me with the time (in clock counts) starting from the time a trigger last went on.

In other words, each time the signal goes on - the counter gets reset to zero. Calling the function returns the clock counts that have gone by since the trigger last went on.

Can this be done using one of the CTRA registers? I did read AN001 (about Propeller Counters) but somehow it is not clicking. More examples would be helpful.

For me the speed and accuracy is very important here, because I use this number as a base for all further time sensitive calculations.

Thanks in advance for your suggestions on how to best do this.
«1

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2013-02-22 11:38
    The closest you can get is to use POS mode (%01000) to count the time the trigger is positive (or NEG mode for a negative going signal). You'd need for the cog to watch the trigger for a negative going edge, then read the CTRA value and zero CTRA for the next time. You're not going to get the counter to do all the work by itself. The initialization code in the cog will have to wait for the trigger to be false and zero CTRA for the first pulse's setup. Each time the cog reads CTRA, it will store the value in hub memory and you'll have a Spin function that'll return the last value stored.
  • jmgjmg Posts: 15,173
    edited 2013-02-22 14:05
    courtens wrote: »
    In other words, each time the signal goes on - the counter gets reset to zero. Calling the function returns the clock counts that have gone by since the trigger last went on.

    There is no HW Clear, but there is a GATED Clock mode, that Adds FRQx (Usually =1) to PHSx on every CLK, while the Gate is HI.
    ( POS mode mentioned in #2)

    You can then sense the GATE going low, [Count now Freezes] Read and Clear PHSx in SW, then the HW waits until GATE next goes high, when it resumes counting from Zero.
    This does need a (small) minimum LOW time.

    Usually you need two WAIT phases, one for =\_ when you capture/clear inSW, and another for _/= which is used to ready the WAIT =\_

    If you can spare another pin, I think you can use 'POS detector with feedback' mode, and now wait for TWO pins, A and B(A@T-1), and those two bits will will be 01 for one single sample time, on a falling edge - so now a single wait can be used.
  • courtenscourtens Posts: 101
    edited 2013-02-22 17:23
    I think I was able to get it to work by using the logical %11111 CTRMODE so that each tick gets counted -- but it is not as fast as doing it mathematically from the clock and a timestamp! Doing it mathematically it takes 48 ticks, doing it using the ctra counter it takes 746 ticks! That is a long time to reset the counter to zero and write the counter to some memory.

    This is my code (the signal I am monitoring is a video field signal)
    'Set up the counters
      ctra := %11111 << 26 + video_field_trigger_pin      'counter A in POSdetect mode  
      ctrb := %11111 << 26 + laser_trigger_pin            'counter B in POSdetect mode  
      frqa := frqb := 1                                   'increment 1 per pulse   
      phsa := phsb := 0                                   'reset count registers
                                  
    
      repeat
    
    '              sets wait for pin to go low=0, or high=1
    '            &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;    
    '            &#9474; 
    '            &#9474;  sets pin number, pin P6 equals six zeros
    '            &#9474;&#9484;&#9472;&#9472;&#9472;&#9472;&#9488;
    '            &#9474;&#9474;    &#9474;                                                                  
        waitpeq(%1000000, |< video_field_trigger_pin, 0)           
        A_total := phsa          'save highest count                          
        phsa := 0                'reset count registers       
        waitcnt(2_000_000 + cnt) 
    
    
  • courtenscourtens Posts: 101
    edited 2013-02-22 18:50
    now the question is what is more accurate? If time is not an issue. I would assume waitcnt() would be possibly faster (better?)
    repeat while phsa < 2_000_000
    

    or
    waitcnt(600+cnt)
    
  • jmgjmg Posts: 15,173
    edited 2013-02-22 19:39
    courtens wrote: »
    now the question is what is more accurate? If time is not an issue. I would assume waitcnt() would be possibly faster (better?)
    repeat while phsa < 2_000_000
    

    or
    waitcnt(600+cnt)
    

    More 'accurate' at what ? - waitcnt has the best (lowest) granularity, but it is not checking a pin.

    The WAIT family of opcodes work to 1 CLK cycle, so they have (much) less granularity than any read-and-Check polling.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-02-22 20:20
    You have to remember that Spin is interpreted. It takes a whole bunch of Propeller instructions to perform any Spin statement. To get the kind of resolution you're wanting, you'll have to use assembly language to set up the counter and check for the end of the measurement period as I described earlier. A typical routine that does what your Spin routine does could be:
    CON video_field_trigger_pin = 1   ' for example, I/O pin 1
    
    VAR long countVar
    
    pub initialize
       countVar := 0
       cognew(@cogIt,@countVar)
    
    pub returnCount
       return countVar
    
    DAT
              org   0
    cogIt     mov    ctra,mask1
              mov    frqa,#1
    myloop    waitpeq  bit1,bit1   ' wait for video_field_trigger_pin to be a one
              mov   phsa,#0   ' clear the counter
              waitpne  bit1,bit1   ' wait for video_field_trigger_pin to be a zero
              mov   temp,phsa   ' get count value
              wrlong   temp,par   ' copy count to location passed in PAR
              jmp    #myLoop
    
    mask1     long    %11111 << 26 + video_field_trigger_pin
    bit1      long   |< video_field_trigger_pin
    temp      res   1
    
  • Mike GreenMike Green Posts: 23,101
    edited 2013-02-22 20:49
    You don't really need to use the counter, but can use the system clock directly for this:
              org   0
    cogIt     waitpeq  bit1,bit1   ' wait for video_field_trigger_pin to be a one
              mov   baseTime,cnt   ' initialize the counter
              waitpne  bit1,bit1   ' wait for video_field_trigger_pin to be a zero
              mov   tempTime,cnt   ' end of the interval
              sub    tempTime,baseTime
              wrlong   tempTime,par   ' copy interval to location passed in PAR
              jmp    #cogIt
    
    bit1      long   |< video_field_trigger_pin
    baseTime  res   1
    tempTime  res   1
    
    Here there's no error since the first WAITPNE/MOV time cancels the second WAITPEQ/MOV and the WRLONG isn't involved in the timing.
  • courtenscourtens Posts: 101
    edited 2013-02-22 21:56
    Mike Green and jmg -- thank you so much for all the help!

    It is kind of scary to think that reading the assembly language code snippet is starting to look like something that can be read (by me that is...) and somewhat understood. I tried to get more familiar with the assembly language, but did not find easy example codes and how-to's, so I gave up on that idea some time ago.

    I was trying to stay away of having to start a new cog just for that task, that is why I really liked the register counter idea,

    Sofar I wrote all the code using timestamps and cnt as reference, but the code was getting messy and hard to trouble shoot. And I was getting tired of following this kind of workaround to avoid the logic pitfall when the counter goes from 2,147,483,647 to -2,147,483,648
    ...
    
        waitpeq(000, |< video_field_trigger_pin, 0)          'wait for Pin to go LOW -- going low has a cleaner edge                  
        video_start_time_local := cnt   
        if video_start_time_local > last_start_time_local 
          elapsed_time := video_start_time_local - last_start_time_local    ' normal situation
        else    
          elapsed_time := (POSX-last_start_time_local)+(POSX+video_start_time_local) 
        video_start_time_master :=  video_start_time_local
        video_start_time_master_last := last_start_time_local
    
    ...
    

    I love the idea of having these two counters available (it would be nice if there would be a third one ... but two will have to do.)

    I just realized that my requirements on the resolution or "granularity" as jmg so nicely states is 824 counts, which is 1/3 of an HD frame line (80_000_000 / 29.97 / 1080 / 3). So technically speaking if checking on the count or doing something with it, should stay under 824 count. So 746 ticks is OK.

    PS. It is not only the actual interval time that is of interest to me. I am actually much more interested in the timing of three different occurring events that need to happen within two time-windows; and during that phase of one frame. I need to know the tick count from the edge to these different events.
  • kuronekokuroneko Posts: 3,623
    edited 2013-02-22 22:02
    Mike Green wrote: »
    There's an error of a few system clock cycles due to the variable delay from when the WAITPEQ is satisfied until the WRLONG can access hub memory. This could be anywhere from maybe 5 to 12 clock cycles (62.5ns to 150ns). I could be off a cycle or two.
    FWIW, there is no error. hubops sample their parameters with the same timing as non-hubops (i.e. immediately). Only then do they wait. Also, your waitpeq will never exit and you're writing shadow[phsa] to hub.
  • JonnyMacJonnyMac Posts: 9,108
    edited 2013-02-23 08:28
    If you can tolerate transient use of the counters in your main cog this is an easy way to a very accurate measurement of your pulse.
    pub get_pulse_width(pin) | mask
    
      ctra := (%01000 << 26) | pin                                  ' pos detector
      frqa := 1
    
      mask := 1 << pin                                              ' convert pin to bit mask
    
      waitpne(mask, mask, 0)                                        ' wait for gap
      phsa := 0                                                     ' clear phsa
      waitpeq(mask, mask, 0)                                        ' wait for pulse
      waitpne(mask, mask, 0)
    
      return phsa                                                   ' return pulse width
    
  • courtenscourtens Posts: 101
    edited 2013-02-23 10:02
    To clear things up a bit, as the posts are heading in a wrong direction: I need to measure "other" different events within a time window which is based from the edge of that trigger. I am not as much interested in the phase time of that one pulse. So I was coding things like this, which is fast:
    time_stamp_A := cnt
    time_stamp_B := 0
    ...
                                                             'check during time window 0 to 10_000  for event B
    
    repeat while get_passed_time(time_stamp_A) < 10_000 and time_stamp_B == 0
            if ina[monitor_event_pin_B] > 0
              time_stamp_B := cnt
    ...
    
    
    PRI get_passed_time(time_stamp) | now
            now := cnt
            if now > time_stamp 
              return (now - time_stamp)                     ' normal situation
            else    
              return ((POSX - time_stamp) + (now - NEGX))
    

    and now learned that I can also code it like this. It uses less code, but takes longer to process: which makes my time_stamp_B less accurate.
    phsa := 0
    time_stamp_B := 0
    ...
                                                             'check during time window 0 to 10_000  for event B
    
    repeat while phsa  < 10_000 and time_stamp_B == 0
            if ina[monitor_event_pin_B] > 0
              time_stamp_B := cnt
    ...
    
    

    but is there a better why to do this sort of thing using assembly language to make it faster? Not sure.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-02-23 11:24
    You can still use the waitpne, but with two possible exits. This depends on having an extra pin available to act as a flag for completion of the 10000 cycle interval. Something like this:
    [SIZE=1][FONT=courier new]PUB snippet
    [/FONT][/SIZE][SIZE=1][FONT=courier new]  timeStamp_B := 0
    [/FONT][/SIZE][SIZE=1][FONT=courier new]  ctra := %00100 << 26 + flagPin   ' nco mode, output to flagPin
      phsa := 10000
      frqa := -1       ' flagPin will go 0->1 at end of interval
      waitpne(0, (|< flagPin) | (|< monitor_event_pin_B), 0)  
           ' high on either pin exits
      timeStamp_B := phsa   ' quick capture phsa (or cnt if you want)
      if timeStamp_B > 0   ' positive value is within interval.
        timeStamp_B := 10000 - timeStamp_B
    [/FONT][/SIZE]
    
    The latency is deterministic between exiting the wait and capturing the value of phsa, so it could be adjusted for better absolute accuracy. How accurate are you expecting?
  • courtenscourtens Posts: 101
    edited 2013-02-23 11:58
    You can still use the waitpne, but with two possible exits. This depends on having an extra pin available to act as a flag for completion of the 10000 cycle interval. Something like this:
    [SIZE=1][FONT=courier new]PUB snippet
    [/FONT][/SIZE][SIZE=1][FONT=courier new]  timeStamp_B := 0
    [/FONT][/SIZE][SIZE=1][FONT=courier new]  ctra := [[/FONT][/SIZE][SIZE=1][FONT=courier new]0/0][SIZE=1] [/SIZE]01000 [/FONT][/SIZE][SIZE=1][FONT=courier new]<< 26 + flagPin   ' nco mode, output to flagPin
      phsa := [/FONT][/SIZE][SIZE=1][FONT=courier new]10000
      frqa := -1       ' flagPin will go 0->1 at end of interval
      waitpne(0, (|< flagPin) | (|< monitor_event_pin_B), 0)  
           ' high on either pin exits
      timeStamp_B := phsa   ' quick capture phsa (or cnt if you want)
      if timeStamp_B > 0   ' positive value is within interval.
        timeStamp_B := 10000 - timeStamp_B
    [/FONT][/SIZE]
    
    The latency is deterministic between exiting the wait and capturing the value of phsa, so it could be adjusted for better absolute accuracy. How accurate are you expecting?

    Very very nice!!! This looks like a much better approach. I did not know you could to that. I think this is it :lol:

    Do I need to set the flagPin as input and output?

    The only disadvantage of using this code is that one has to be carfull when to "set" the flagPin
  • Mike GreenMike Green Posts: 23,101
    edited 2013-02-23 12:27
    Make flagPin an output, but don't connect it to anything. What happens is that the input logic of an I/O pin tests the actual state of the I/O pin. If the I/O pin is set as an output, any of the input instructions (like WAITPNE) actually sense the output state of the I/O pin.
  • courtenscourtens Posts: 101
    edited 2013-03-20 12:21
    Sorry for being silent for so long. Now I am back at it, and really would like to get this to work.
    You can still use the waitpne, but with two possible exits. This depends on having an extra pin available to act as a flag for completion of the 10000 cycle interval. Something like this:
    [SIZE=1][FONT=courier new]PUB snippet
    [/FONT][/SIZE][SIZE=1][FONT=courier new]  timeStamp_B := 0
    [/FONT][/SIZE][SIZE=1][FONT=courier new]  ctra := 100 << 26 + flagPin   ' nco mode, output to flagPin
      phsa := 10000
      frqa := -1       ' flagPin will go 0->1 at end of interval
      waitpne(0, (|< flagPin) | (|< monitor_event_pin_B), 0)  
           ' high on either pin exits
      timeStamp_B := phsa   ' quick capture phsa (or cnt if you want)
      if timeStamp_B > 0   ' positive value is within interval.
        timeStamp_B := 10000 - timeStamp_B
    [/FONT][/SIZE]
    
    The latency is deterministic between exiting the wait and capturing the value of phsa, so it could be adjusted for better absolute accuracy. How accurate are you expecting?

    Tracy Allen, somehow this code is not working for me. My flagPin is always high. I even tried to set it low, but even that is not working. How would I set the FlagPin to go high only after say 3_380_000 counts?

    This is what I have
    [FONT=courier new] [SIZE=1]                             phsb:=0          phsb:=0                
    Pin 6 (no signal)              v                v                     
    &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9484;&#9472;&#9472;&#9472;
                                   &#9474;&#9474; Signal        &#9474;&#9474;               &#9474;&#9474;   
                                   &#9492;&#9496;               &#9492;&#9496;               &#9492;&#9496;   
    [/SIZE][/FONT][SIZE=1]
    [FONT=courier new][SIZE=1]  ctrb := 111 << 26                    ' count everything mode (set CTRB CTRMODE 
                                              ' and << 26 is to set all other bits to z[/SIZE]ero)                     
      frqb := 1                               ' +1 per tick                    
      phsb := 0                               ' reset count register
    
      '--------
      ctra := 100 << 26 + video_flagPin    ' nco mode (numerically controlled oscillator)                                      
      frqa := -1                              ' -1 per tick, flagPin will go 0->1 at end of interval                                   
      phsa := 10_400_000                      ' set [SIZE=1]interval[/SIZE][/FONT][/SIZE]
    [SIZE=1][FONT=courier new]
      'this is what I am suing in the loop to ho[SIZE=1]ld
      '[SIZE=1]i[SIZE=1]f[/SIZE] the [SIZE=1]hold is [SIZE=1]too long I wha[SIZE=1]nt the hold to[SIZE=1] break
      'for that I would like to [SIZE=1]be using[/SIZE] counter [SIZE=1]A[/SIZE][/SIZE][/SIZE][/SIZE][/SIZE][/SIZE][/SIZE]
        waitpne(000000, 000000, 0)      ' hold if flagPin 7 is low and 6 is HIGH[/FONT][/SIZE]
    
    

    I think I just found a solution. This is working -- but the counter is only counting every other count (very strange)
    [SIZE=1][FONT=courier new]  frqa := $300                                                          
      phsa := 0[/FONT][/SIZE]
    

    now I am witnessing a strange counting behavior. I am using counter B as a "logical" counter (one count per clock tick); but for some reason it is only counting 1/2 of the counts it should get.

    Is this normal for counter B?
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-03-20 13:40
    Usually when a pin seems to be stuck high, it usually means that some other thread has set it to be a high output. It comes out high no matter what because of wired-OR. And the dira for that pin needs to be set as an output--my snippet did not do that. I see you found a solution anyway.
  • courtenscourtens Posts: 101
    edited 2013-03-20 14:26
    Usually when a pin seems to be stuck high, it usually means that some other thread has set it to be a high output. It comes out high no matter what because of wired-OR. And the dira for that pin needs to be set as an output--my snippet did not do that. I see you found a solution anyway.

    Thank you Tracy! YES - I did find something in the code that was pulling up that flagPin. I fixed it, and now your code is working! Very nice. However, I am only getting 1 count for 2 cycles. This is very strange. Is there something that could have changed my clock in that cog?
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-03-20 15:25
    Please show how more detail of how counter B is set up. It should count every edge, if that is what it is supposed to do. And why the snippet...
    frqa := 300 '???
    phsa := 0
  • courtenscourtens Posts: 101
    edited 2013-03-20 16:15
    Please show how more detail of how counter B is set up. It should count every edge, if that is what it is supposed to do. And why the snippet...
    frqa := 300 '???
    phsa := 0

    I dumped the frqa := 300 and phsa := 0 approach all together. It worked to kill the loop, but is less elegant then your code.

    This is all the code in that cog total (171 bytes.) I reserved 200 for it (50 lonsg)
    [SIZE=1][FONT=courier new]PUB cog_video | VS_cnt_local, last_VS_cnt_local, video_VS_cnt_local, video_timeStamp_B_local, elapsed_time_local, video_flagPin
    
      set_pin_to_input(video_field_trigger_pin)
      video_flagPin := 7  ' P7
      set_pin_to_output(video_flagPin)                                                
      cog_video_COGID := COGID
                                                       
      ctra := %00100 << 26 + video_flagPin    ' nco mode (numerically controlled oscillator)                         
      frqa := -1                                                            
      phsa := 4_000_000                       ' set in[SIZE=1]t[/SIZE]erval
                                                                        
      ctrb := %11111 << 26                    ' count everything mode 
      frqb := 1                               ' +1 per tick                    
      phsb := 0                               ' reset count register
      
      repeat                 
        
        if video_timeStamp_B_local < 4_000_000  
          if VS_cnt_local > last_VS_cnt_local 
            elapsed_time_local := VS_cnt_local - last_VS_cnt_local    ' normal situation
          else    
            elapsed_time_local := (POSX-last_VS_cnt_local)+(POSX+VS_cnt_local)  
        else
          elapsed_time_local := 0
                              
        ' write to global vars  
        elapsed_time :=  elapsed_time_local
        video_timeStamp_B := video_timeStamp_B_local
    
        turn_Off(7)                                                                                
                                                                       
        waitcnt(100_000+cnt)                                          '[SIZE=1] make [SIZE=1]sure P7 it is back HIGH[/SIZE][/SIZE]
    
    ''     &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;       
    ''     &#9474;  vertical sync is on P6      (6)  %01000000  &#9474;  
    ''     &#9474;  reserved flag pin is on P7  (7)  %10000000  &#9474;        
    ''     &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                                                 
        last_VS_cnt_local := VS_cnt_local
                                        
        waitpne(%01000000, %11000000, 0)                               ' hold if 7 is LOW and 6 is HIGH 
                        
        video_timeStamp_B_local := phsb                                ' save highest count on B counter[/FONT][/SIZE]
    [SIZE=1][FONT=courier new]    phsb := 0                                                      ' reset B counter
    [/FONT][/SIZE][SIZE=1][FONT=courier new]     
        VS_cnt_local := cnt[/FONT][/SIZE][SIZE=1][FONT=courier new]
        phsa := 4_000_000                                                             
                                                                                         
        waitcnt(1_000+cnt)                                             ' to prevent bounce
        
        if video_timeStamp_B_local < 3_400_000      
          VS_cnt := VS_cnt_local
        else
          VS_cnt := 0
                       [/FONT][/SIZE]
    


    The phase duration for PAL video is 3_200_000 and I am getting ony 1_599_952 for elapsed_time; only half the expected value. So is video_timeStamp_B: 1_599_382

    I could just multiply by 2 -- but something is off if it is suppose to count every count ?!?


  • kuronekokuroneko Posts: 3,623
    edited 2013-03-20 16:23
    @courtens: Likely to be unrelated to your actual problem but local variables are not initialised. IOW before you use them give them a known value.
  • kuronekokuroneko Posts: 3,623
    edited 2013-03-20 18:42
    Odd, the method you posted works for me. I faked a 3M2 cycle pulse which has a small low pulse embedded. Elapsed time is shown as 3M2. Can you verify timeout behaviour and sync pulse timing by other means, i.e. is you sync pulse what you expect it to be?
    CON
      _clkmode = XTAL1|PLL16X
      _xinfreq = 5_000_000
    
    CON
      video_flagPin = 7
      
    OBJ
      serial: "FullDuplexSerial"
    
    VAR
      long  elapsed_time
      long  video_timeStamp_B
      long  VS_cnt
      long  stack[32]
      
    PUB null
    
      serial.start(31, 30, %0000, 115200)
      cognew(@pulse, 0)
      cognew(cog_video, @stack{0})
      waitcnt(clkfreq*3 + cnt)
      
      repeat
        serial.dec(elapsed_time)
        serial.tx(13)
        waitcnt(clkfreq/2 + cnt)
        
    PUB cog_video | VS_cnt_local, last_VS_cnt_local, video_VS_cnt_local, video_timeStamp_B_local, elapsed_time_local
    
      dira[video_flagPin]~~                                                           
                                                       
      ctra := %00100 << 26 + video_flagPin    ' nco mode (numerically controlled oscillator)                         
      frqa := -1                                                            
      phsa := 4_000_000                       ' set interval
                                                                        
      ctrb := %11111 << 26                    ' count everything mode 
      frqb := 1                               ' +1 per tick                    
      phsb := 0                               ' reset count register
      
      repeat                 
        if video_timeStamp_B_local < 4_000_000  
          if VS_cnt_local > last_VS_cnt_local 
            elapsed_time_local := VS_cnt_local - last_VS_cnt_local    ' normal situation
          else    
            elapsed_time_local := (POSX-last_VS_cnt_local)+(POSX+VS_cnt_local)  
        else
          elapsed_time_local := 0
                              
        ' write to global vars  
        elapsed_time :=  elapsed_time_local
        video_timeStamp_B := video_timeStamp_B_local
    
    '   turn_Off(7)                                                                                
                                                                       
        waitcnt(100_000+cnt)                                          ' make sure P7 it is back HIGH
    
    ''     &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;       
    ''     &#9474;  vertical sync is on P6      (6)  %01000000  &#9474;  
    ''     &#9474;  reserved flag pin is on P7  (7)  %10000000  &#9474;        
    ''     &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                                                 
        last_VS_cnt_local := VS_cnt_local
                                        
        waitpne(%01000000, %11000000, 0)                               ' hold if 7 is LOW and 6 is HIGH 
                        
        video_timeStamp_B_local := phsb                                ' save highest count on B counter
        phsb := 0                                                      ' reset B counter
         
        VS_cnt_local := cnt
        phsa := 4_000_000                                                             
                                                                                         
        waitcnt(1_000+cnt)                                             ' to prevent bounce
        
        if video_timeStamp_B_local < 3_400_000      
          VS_cnt := VS_cnt_local
        else
          VS_cnt := 0
    
    DAT             org     0
    
    pulse           mov     dira, mask
                    mov     cnt, cnt
                    add     cnt, #9
    
    loop            waitcnt cnt, delay
                    andn    outa, mask
                    nop
                    or      outa, mask
    '{timeout}      waitpeq $, #0
                    jmp     #loop
    
    delay           long    3_200_000
    mask            long    |< 6
    
                    fit
                    
    DAT
    
  • courtenscourtens Posts: 101
    edited 2013-03-21 08:48
    kuroneko wrote: »
    Can you verify timeout behaviour and sync pulse timing by other means, i.e. is your sync pulse what you expect it to be?

    My sync pulse is what I expect it to be ... yes. And the timeout behavior (flagPin) is also working well.

    Are you getting a value of 3M2 for the elapsed_time?


    I am trying to find an explanation for the counters behavior - but some how can't. What is strange is that somehow counter A & B are only counting one clock cycle for every 2 clock cycles. This is not what I intend it to do. It is like if this one cog is running at 40MHz for counter A & B but 80MHz for the cnt clock. Very strange.

    If I use this code in place of the above posted code it gives me the correct clock count for the two counters. But this is not the way I expected spin to work. This would be a "quick fix" but with no logical explanation of why the counters are not counting properly.
    [SIZE=1][FONT=courier new]  frqa := [COLOR=#ff0000][SIZE=2][B]-2[/B][/SIZE][/COLOR]   [COLOR=#ff0000]'was -1[/COLOR]
                                                  
      ' further down in the code  ...   
                                        
      frqb := [/FONT][/SIZE][SIZE=1][FONT=courier new][COLOR=#ff0000][SIZE=2][B]2[/B][/SIZE][/COLOR][/FONT][/SIZE][SIZE=1][FONT=courier new]  [COLOR=#ff0000] 'was 1[/COLOR][/FONT][/SIZE]
    [SIZE=1][FONT=courier new]          
      ' further down in the code  ...   
    
    [/FONT][/SIZE][SIZE=1][FONT=courier new]  elapsed_time :=  elapsed_time_local * [/FONT][/SIZE][SIZE=1][FONT=courier new][COLOR=#ff0000][SIZE=2][B]2[/B][/SIZE][/COLOR][/FONT][/SIZE]   [COLOR=#ff0000] [SIZE=1][FONT=courier new]'was [SIZE=1]not [SIZE=1]multiplied[/SIZE] x2[/SIZE][/FONT][/SIZE][/COLOR]
    
    

    So with this quick fix in place I am getting the expected 3M2 counts per period (phase), but without doubling it I am only getting half the counts. Something is not right.

    Would this kind of behavior point to a memory collision somewhere?
  • jmgjmg Posts: 15,173
    edited 2013-03-21 12:57
    Err, you mention Vertical Sync and PAL, but 80e6/3.2e6 = 25Hz, which is not any PAL sync I know...?
  • courtenscourtens Posts: 101
    edited 2013-03-21 14:06
    jmg wrote: »
    Err, you mention Vertical Sync and PAL, but 80e6/3.2e6 = 25Hz, which is not any PAL sync I know...?

    PAL is 25 frames per second ... so 25Hz is right ... or 20uS per frame or 3_200_000 counts per frame.
  • jmgjmg Posts: 15,173
    edited 2013-03-21 14:54
    courtens wrote: »
    PAL is 25 frames per second ... so 25Hz is right ... or 20uS per frame or 3_200_000 counts per frame.

    Try this :http://en.wikipedia.org/wiki/PAL
    The vertical timings are:
    Vertical frequency 50 Hz

    Frame rate in the PALs I know, are all 50Hz, however they do interlace, which may be where your 25Hz figure has come from.
  • courtenscourtens Posts: 101
    edited 2013-03-21 20:05
    jmg wrote: »
    Try this :http://en.wikipedia.org/wiki/PAL
    The vertical timings are:
    Vertical frequency 50 Hz

    Frame rate in the PALs I know, are all 50Hz, however they do interlace, which may be where your 25Hz figure has come from.

    PAL frame rate is 25 fps, NTSC is 29.97!

    Frame rate is not the same as AC rate (Hz)

    My VS (vertical sync) pulse is one pulse per frame (NOT to be confused by fields!!!)
  • kuronekokuroneko Posts: 3,623
    edited 2013-03-21 20:42
    courtens wrote: »
    PAL is 25 frames per second ... so 25Hz is right ... or 20uS per frame or 3_200_000 counts per frame.
    Assuming you mean 20ms per frame I get 20ms/12.5ns = 1M6 cycles. OTOH 25Hz comes down to 40ms in my book (3M2 cycles).
  • courtenscourtens Posts: 101
    edited 2013-03-22 09:01
    kuroneko wrote: »
    Assuming you mean 20ms per frame I get 20ms/12.5ns = 1M6 cycles. OTOH 25Hz comes down to 40ms in my book (3M2 cycles).

    kuroneko, yes. I am sorry ... I meant mS and not uS ... and not 20 but 40 per frame. So it is 40mS per frame and 20mS per field, and there are 2 files in one video frame. So one PAL frame has 3m2 cycles

    And the vertical sync that the code is monitoring is a short pulse that goes low, one time per frame.
    [FONT=courier new][SIZE=1]                            [SIZE=1]setting[/SIZE]
    [/SIZE][/FONT][FONT=courier new] [SIZE=1]                             phsa:=[/SIZE][/FONT][SIZE=1][FONT=courier new]4_000_000[/FONT][/SIZE][FONT=courier new][SIZE=1]  phsa:=[/SIZE][/FONT][SIZE=1][FONT=courier new]4_000_000[/FONT][/SIZE]
    [FONT=courier new] [SIZE=1]                             phsb:=0          phsb:=0                [/SIZE][/FONT][FONT=courier new][SIZE=1] 
    Pin 6 (no signal)              v                v                      
    &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9484;&#9472;&#9472;&#9472;
                                   &#9474;&#9474; Signal        &#9474;&#9474;               &#9474;&#9474;   
                                   &#9492;&#9496;               &#9492;&#9496;               &#9492;&#9496;   [/SIZE][/FONT]
    

    But back to my spin misbehavior question in post 20. Somehow my register CTRA and CTRB are not counting one tick per cycle, but only every other tick per cycle. It is as if they would be taking turns in the counting department. And so I am ending up with only half the counts that would be expected for the duration of one frame. I expect 3M2 but get only 1M6 per frame. Is this normal behavoir, or is this some hardware bug? I thought that the two counters would count every clock count.

    This is how I set up the two counters:
    [SIZE=2][FONT=courier new] ctra := [SIZE=2]%00[/SIZE]100 << 26 + video_flagPin  ' nco mode (numerically controlled oscillator)
    frqa := -1                            ' -1 per tick on phsa
    phsa := 4_000_000                     ' set interval
    ctrb := [/FONT][/SIZE][SIZE=2][FONT=courier new][SIZE=2]%[SIZE=2]11[/SIZE][/SIZE][/FONT][/SIZE][SIZE=2][FONT=courier new]111 << 26                  ' count everything mode
    frqb := 1                             ' +1 per tick
    phsb := 0                             ' reset count register[/FONT][/SIZE]
    

    I plan on using these counters in other parts of my code, and would like to know how they work -- or am I witnessing some memory collision that is messing up the counting? It just is all very strange. Thanks for the help!
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-03-22 10:44
    4_000_000 clock cycles at clkfreq = 80MHz is 0.05 second. Is that ctra pulse coming out at the right length? I've lost track of how the ctrb %11111 mode is supposed to be connected to the signal. I got the idea that it was supposed to be, detect time to pulse, or 0.05 second, whichever comes first.

    I don't think the Prop is lying to you. Do you have a 'scope or logic analyzer where you can visualize the signal?
  • jmgjmg Posts: 15,173
    edited 2013-03-22 12:42
    courtens wrote: »
    And the vertical sync that the code is monitoring is a short pulse that goes low, one time per frame.

    Get another instrument, and measure that vertical sync rate. Many multimeters have frequency counters.
Sign In or Register to comment.