PDA

View Full Version : Zero cross detect - switching audio



HankMcSpank
- 30th October 2011, 12:32
So I'm wanting to have an audio switch that only actually switches at a zero crossing point (or very near to zero)...this will only involve audio upto about 1.5khz in frequency.

My thinking here is to use a PIC's comparator ....ie toggling when zero points are 'crossed' (this will be a single supply circuit, 'zero' will actually be about 1/2 VCC), but how do I implement the associated code?

At a high level, I reckon it'd be something along these lines...

1. A switch is pressed
2. wait until the comparator's output logic level is *not* what it was at the time of the switch being pressed (ie a zero cross has happened)
3. raise the necessay control voltage to invoke the actual audio switch.

.....now steps 1 & 3 I'm ok with, but how in code would I do step 2? Upon the switch being pressed, the comparator's output could either be high or low (it'd be random), I want to 'trap' quickly the opposite condition of what it is at the time of the switch being pressed.

Ideas?

dhouston
- 30th October 2011, 13:11
All of the PIC inputs have protection diodes so all you need is a current limiting resistor. Look at the Microchip AN236 (p3& p20) which uses just a 5meg resistor to get ZC from the 120VAC powerline.

Jerson
- 30th October 2011, 13:55
Hi Hank

I think you can get the comparator to interrupt you at every zero crossing. That is the easy part.

What I suggest is setup the framework to get the zero crossing detector (ZCD) interrupts when the comparator threshold is breached.

1 - enable the ZCD interrupts only when the switch is pressed.
2 - On interrupt, do your audio switching thing which will be within a fraction of a mS away from the Zero crossing. That depends on whether you use the leading edge or trailing edge for trigger; disable the interrupt again so you have just 1 event per switch press
3 - wait for switch release

Hope that helps
Jerson

HankMcSpank
- 30th October 2011, 14:34
Hi Jerson,

I anticipate the actual switch involved being pressed very rapidly (think 'teen on an arcade button'!) ...I'd be worried about the overhead of getting in/out of any interrupt *after* trapping the switch being pressed, so I was thinking of an IOC interrupt for capturing the switch being pressed & then somehow trapping the next comparator toggle in the IOC interrupt routine.

At the minute the best I can come up with, is something along these (high level) lines...



Sw_Interrupt: 'IOC interrupt handler
'
stored_comparator_level = comparator_output_level ' store the present comparator logic level nb: I've not delved to get the actual registers involved, this is high level stuff!
'
while comparator_output_level = stored_comparator_level 'keep looping until there's a mismatch
wend
'
'ok, to drop out of above wend and get to this point, then there must be a mismatch (a zero cross - comparator toggle) so let's continue
'
PortA.1 = 1 ' switch PortA.1 high immediately after comparator has toggled (ie the control voltage to the audio switch)
...blah blah


Not even sure if you can use a while/wend like that?

PS Dave - you've lost me...this has nothing to do with AC mains?! (I'm talking low level audio zero cross detect)

cncmachineguy
- 30th October 2011, 15:00
Hank that looks like good logic to me, but to make sure I get where you are heading -
on switch press, call ISR,
Inside ISR, wait for the signal to cross zero (in either direction, max time here would be .3333mS?)
Crossed so do what needs to be done and leave.

Yes you can use while/end like that.
Don't forget to set/clear the IOC caller so as not to re-trigger as soon as you leave.

HankMcSpank
- 30th October 2011, 15:13
Inside ISR, wait for the signal to cross zero (in either direction, max time here would be .3333mS?)


Hi Bert...thanks for the confirmation - yes, you understand what I'm trying to do ...what I would add at this point is the full sequence of events really needs to be like this...

1. Switch gets pressed
2. IOC interrrupt routine Entered

hang around at this point, until....


3. comparator toggles (zero cross) -> Audio switch control voltage get's 'enabled' as quickly as possible thereafter.

hang around at this point, until....

4.Switch gets released (finger removed!)
5. comparator toggles (another zero cross)-> Audio switch control voltage get's 'disabled' as quickly as possible thereafter.
6. exit the IOC switch interrupt routine.

where did your .333mS number come from?

I don't need to trap the initial switch press too quick (anything sub 4mS will likely be ok), but from the comparator flipping state to the audio switch control voltage changing needs to be as blisteringly fast as I can make it (as obviously, the longer this bit takes the 'further' the AC signal is going to be away from 'zero') ..... 333us seems like a long time!

dhouston
- 30th October 2011, 15:57
The delay will vary with the frequency of the audio but if you always switch on the falling edge, you will be slightly ahead of ZC and can add a delay if needed. The app note I referenced details how to calculate the delays for 60Hz - you can adapt it to your audio frequencies.

HankMcSpank
- 30th October 2011, 16:19
Aah...tks Dave.

I should prpbably point out that I'm not after a perfect 'zero' switch...just ahem 'close to zero' (I guess what I really want is an 'avoid switching at signal voltage peak' type of switch!)

dhouston
- 30th October 2011, 16:29
I should prpbably point out that I'm not after a perfect 'zero' switch... Perfect would require calculating the difference between Logic 0 and Logic 1 vs ZC for each frequency and for both rising and falling edges. Close enuff is probably using Logic 0 on a falling edge to trigger the switch.

HankMcSpank
- 30th October 2011, 17:08
Close enuff is probably using Logic 0 on a falling edge to trigger the switch.

:-)

Bert, ok...just sussed, where you came up with the 333us number!

1.5khz maximum audio frequency expected = 1/1500 = 660us period .....therefore half a period would be 333us.

so 'zero cross to signal peak' (90 degrees) at that frequency would be about 150us..... if I can get within 10% of zero @1.5Khz I'd be very happy.

If I run the PIC at 16Mhz, I reckon I ought to be get reasonably close to zero - even at the maximum expected audio frequency of 1.5Khz - in my mind, 15us is a chunky amount of 'window' to get an audio IC switch after the PIC's comparator has toggled?

Jerson
- 31st October 2011, 03:59
I don't think you can check comparator levels; that would involve reading analog levels(ADC). What you can do is set the comparator threshold. Then the comparator tells you 'Above' or "Below" threshold by its output. This is what you use to trigger the comparator interrupt.

That's the reason I suggested you turn on the ZCD interrupt on switch press. Now, the very first int after switch press will be captured. You may need to clear the int flag before enabling the CMP interrupt so that you do not process the previous INT which has been flagged.

So, the pseudo code would look like



SW_Interrupt:
clear CMP interrupt pending flag
enable the CMP interrupt
clear SW interrupt flag(maybe an int on change)
EXIT INT

CMPINT:
Do audio switch(maybe a toggle of the port involved)
EXIT INT

HankMcSpank
- 31st October 2011, 09:45
I don't think you can check comparator levels; that would involve reading analog levels(ADC). What you can do is set the comparator threshold. Then the comparator tells you 'Above' or "Below" threshold by its output. This is what you use to trigger the comparator interrupt.
[/code]

But the comparator is only analogue on the input side (where I will preset the comparator threshold to be my circuit's ZC point ....about 1/2 VCC) ...it's output is digital & can therefore be read (I think), this from the associated PIC's datasheet (16f1828)...


18.2.2 COMPARATOR OUTPUT SELECTION
The output of the comparator can be monitored by reading either the CxOUT bit of the CMxCON0 register or the MCxOUT bit of the CMOUT register.



Sound reasonable?

Jerson
- 31st October 2011, 10:56
Of course you can 'read' the comparator output internally. I still feel you may be better off using an interrupt on the zero crossing as you might have some misses while polling the register in a code loop.

cncmachineguy
- 31st October 2011, 11:05
Hi Hank, I have to agree with Jerson here, his code suggestion is IMHO a better solution. hanging out in the ISR for .33uS seems a little wastful of the clock cycles available. And if the 1.5K is slower? then you are hanging out for a good while!

HankMcSpank
- 31st October 2011, 11:09
Of course you can 'read' the comparator output internally. I still feel you may be better off using an interrupt on the zero crossing as you might have some misses while polling the register in a code loop.

I guess my reticence to use the comparator interrupt method you describe is that I've absolutely no idea the latency between the comparator flipping to getting into the sub routine & being able to do something (this area for me will always be an enigma...in fact it's probably the largest impediment I'll contnue to face...if I don't know the timing impact of something, then I'll veer away from it!), and what is absolutely key for a 'close to zero cross' is that the moment the comparator flips, my switch control voltage needs to be raised as quickly as PIC-ly possible ....wouldn't a while/wend on the CxOUT bit be the quickest vs a comparator interrupt?

HankMcSpank
- 31st October 2011, 11:17
Hi Hank, I have to agree with Jerson here, his code suggestion is IMHO a better solution. hanging out in the ISR for .33uS seems a little wastful of the clock cycles available. And if the 1.5K is slower? then you are hanging out for a good while!

Hi Bert, for this application, the PIC won't be doing anything else (it's not like my main loop is waiting on the INT_RETURN) ....so once I'm in the interrupt routine, I can actually stay there for yonks (yes, I know everyone says, get in, get out asap......but surely that's for when your main is wating on the int_return?)

My *main* overpowering requirement here is that once the comparator flips, that I can raise the audio Switch IC control voltage as PICly ;-) as possible ....if you all think that a comparator interrupt will facilitate this quicker say vs a while/wend on the comparator output while inside a Switch derived IOC interrupt routine, then cool...I'll roll with it! (but in my noobesque, head, I'd always took it that there's a certain overhead getting out of the main loop & into an interrupt routine)

cncmachineguy
- 31st October 2011, 11:20
I don't remember off hand what the answer is, but DT_INT ASM type takes only a few cycles (I think) to get in. Or get in there the actual ASM way. But, no problem waiting around either. If you have nothing else you need to do.

Just saw your edit, If your main is really doing nothing, skip the ISR all together and just wait in main for the switch press.

HankMcSpank
- 31st October 2011, 11:25
Just saw your edit, If your main is really doing nothing, skip the ISR all together and just wait in main for the switch press.

ok, perhaps what I should have said(!), is that when the switch is pressed, it will supercede everything else that might/might not be going on in the (low priority stuff) main ...therefore once in the Switch IOC interrupt happens, I can hang out in the interrupt routine for as long as needs be! (the main will just have to wait!)


I don't remember off hand what the answer is, but DT_INT ASM type takes only a few cycles (I think) to get in.

As mentioned, I have no way of gauging this (I'm in "I think" territory too!), so when I seek something as time critical as catching a near zero cross, to my mind, I reckon it's better to be in there already & tracking the comparator output with a while/wend, then outside not knowing how long it'll take to get in!

cncmachineguy
- 31st October 2011, 11:33
Then I will have to agree with you. :) Now you could do it in reverse, on EVERY ZC, call ISR, Check for switch pressed or released, if it is, turn on thingy, of not leave.
Or use the ZC as the timing for main.

while not ZC :WEND
switch pressed do stuff
released do other stuff
continue to twiddle bits, flash LED's, whatever
goto main

As long as main takes less then 333uS (for a 1.5K period) you will never miss a beat, and I don't think you can get any faster

HankMcSpank
- 1st November 2011, 18:59
Hi Bert,

Apologies for the delay in coming back..... I don't really want to trigger an interrupt on every zero cross, as that will bog things down (there'll be heaps of them)...even though my main isn't doing much...it may get bigger & I'm still reeling from a similar thing with cap touch interrupts (basically to have a cap touch sensor feel 'zippy' you've got to generate a lot of interrupts ....I found to my cost how having a fairly modest interrupt rate quickly brought my main loop to its knees!)

I'd rather not go with the zero cross/switch close detect in the main loop, because as mentioned, it's not doing much at the moment...but I'm a terrible one for lobbing things into my main & making it bloaty in short order ...at least an interrupt will get priority no matter I may/may not do in my main!

Many thanks for everyone's input.