Input transition event counter

I am trying to use the CTRA function to count the number of positive edge transitions on an input pin. The pin is connected to the output of a comparator on a zero crossing voltage detector circuit. The output is a nice steady +Vdd/0 signal running at 60 Hz. I want the PHSA register to index by 1 for each transition from 0 to 1 on the input pin (i.e. FRQA=1). From reading the CTRA section in the manual (p 95-98) it looks like I should be using a CTRMODE of %01001 (POSEDGE detector) or %01011 (POSEDGE detector w/feedback). Instead of PSHA being indexed by 1 it seem is be indexing by 6, 7, 8 or 9 with each input transition. Am I missing something here?
Here is the test code I am using:
Here is the test code I am using:
CON
_clkmode = xtal1 + pll16x 'Must stay with the 16x (80 MHz for IR to work reliably)
_xinfreq = 5_000_000
' serial terminal baud rate (default I/O pins are 30 and 31):
PSTBaud = 115200
ZCPin = 5
OBJ
pst : "Parallax Serial Terminal"
VAR
LONG HzCounter, HZMode
PUB Main | i, j, k, l, m, n
pst.Start( PSTBaud )
pst.Clear
pst.Beep
pst.str(String("Initializing..."))
'Set zero cross pin as input
DIRA[ ZCPin ]~
'Start the CTRA counter to count 60 Hz pulses off the zero cross detector input pin.
' HzMode := %01010 << 26 'POSEDGE detector
HzMode := %01011 << 26 'POSEDGE detector w/feedback
HzMode += ZCPin 'Encode the zero cross pin number into the mode
pst.str( String( pst#NL, "HzMode: %" ) )
pst.bin( HzMode, 32 )
FRQA := 1 ' add 1 to the PHSA register for each input edge change detected detected.
CTRA := HzMode
PHSA := 0 ' Clear the counter
pst.str( String( pst#NL, "Testing 60 Hz counter... " ) )
repeat 5
i := PHSA
waitcnt( cnt + clkfreq )
j := PHSA
pst.str( String( pst#NL, "PHSA start: " ) )
pst.dec( i )
pst.str( String( " end: " ) )
pst.dec( j )
pst.str( String( " delta: " ) )
pst.dec( j-i )
pst.str(String( pst#NL, "Done."))
pst.str( String( pst#NL, "PHSA change counter... " ) )
REPEAT 5
PHSA := 0
REPEAT UNTIL PHSA > 0
i := CNT
PHSA := 0
REPEAT UNTIL PHSA > 0
i := CNT - i
j := PHSA
pst.str( String( pst#NL, "PHSA change CNT: " ) )
pst.dec( i )
pst.str( String( " PHSA end: " ) )
pst.dec( j )
{{ End of code}}
Comments
Andy
Comparators come with a small amount of hysteresis built-in, but perhaps the signal is too noisy for this? Simple low-pass filtering the input to the comparator might help with that. Or more positive feedback.
The comparator has good decoupling I hope...
If the comparator is slow, in combination with ground bounce noise and layout issues, it can detect multiple transitions as it hovers in the region of the Prop switching threshold. On the other hand, if the comparator is fast, in combination with layout issues, the comparator itself can oscillate as it passes through its transition point. Either way, multiple counts that call for more hysteresis or layout or bypassing changes.
I used a scope to verify the output and it looked nice and clean - however I don't think I have enough resolution in the scope to see if the signal was chattering faster than ~1 MHz at the transition points. Perhaps a larger hysterisis is in order by reducing the value of R16?
Andy
Do you need to know the exact point in time at which the zero-crossing occurs? Or is it only necessary to count them? In the former case, you have to be wary of adding too much hysteresis, as this will delay the reading of the zero-crossing. I would be much more inclined to use a software-mediated technique that looks for the first edge, then waits before setting up to detect another one.
-Phil
The reason for the counter is becuase I want to time various other on/off and timeout events with intervals exceeding the ~26.3 second limit of using the CNT timing method. Thus a 60 Hz counter would extend the integer rollover time to something like 414 days which is plenty. I am tring to do this without minimal code and consuming a cog to keep track of the ZCPin transistions.
Perhaps there is another more simple or more elegant way of accomplishing this?
If your earth falls off, thats 100K straight to the mains...
Look at VR37/VR68 high voltage resistors and use some meg ohms (10M+), to feed a ZCD.
A simple ZCD will use a Schmitt Buffer, and you can add a series CAP, to the series resistor, (gives phase lead) to allow a shunt cap to filter spikes, (gives phase lag) without adding phase errors,
OR you can skip the series cap, and simply know what the filter phase delay is, and correct that in SW.
SW can also compensate for slight DC offsets in ZCD, or +/- skews.
Indeed a 20M resistor is pretty weak there (perhaps if one added a few tens of pF in parallel it wouldn't be so bad). Certainly a percent or so of hysteresis is more usual and more inline with the kind of noise spikes that are likely to be superimposed on the inputs on a digital PCB. Again LPF on the input to the comparator might help, but I don't think extreme accuracy is needed in this circuit - extra hysteresis is a robust defence to false triggering.
1nF.HV 22Meg 68pF AC -----||------/\/\/\---+--||--GND VR68 | | +---74HC14--> Prop
Spice says the 1nf has ~ 30V pk across it, and the 68pF shunt gives a nominal zero crossing phase correction, and noise filter.
The HC14 clamp diodes will clamp the 8uA current from the 22Meg.
10Meg 120V AC -------/\/\/\-----> Prop Pin
Without hystersis, but no active component which can amplify the noise, so it may work better then the Comparator circuit.Andy
The output waveform is virtually symmetrical. On my bench, the duty cycle was 49.55%. And, most importantly, the Propeller is completely isolated from the mains.
-Phil
Shouldn't those optos be reverse connected ? - so they alternate conduction ?
Now I look again, I see they are reverse connected, my eyes are playing tricks...
-Phil
' This code debounces the ZC input to prevent noise from ' fouling the frequency detection waitlo1 mov t1, #DB_CYCLES ' wait for low :loop test zcmask, ina wc if_c jmp #waitlo1 djnz t1, #:loop waithi1 mov t1, #DB_CYCLES ' wait for leading edge of ZC :loop test zcmask, ina wc if_nc jmp #waithi1 djnz t1, #:loop neg period, cnt ' start period measurement waitlo2 mov t1, #DB_CYCLES ' wait for falling edge of ZC :loop test zcmask, ina wc if_c jmp #waitlo2 djnz t1, #:loop waithi2 mov t1, #DB_CYCLES ' wait for 2nd leading edge :loop test zcmask, ina wc if_nc jmp #waithi2 djnz t1, #:loop add period, cnt ' stop timing sub period, #4 ' remove overhead wrlong period, hubphase ' save to hub shr period, #8 ' divide into 256 segments