Measuring audio phase shift through a circuit with a PIC


Closed Thread
Results 1 to 40 of 50

Hybrid View

  1. #1
    Join Date
    Jul 2003
    Location
    USA - Arizona
    Posts
    156


    Did you find this post helpful? Yes | No

    Default

    So on the picture and data on post#15 things were looking honky-dory (you were measuring at least down to 161 counts on CMP2). Your new posts state that now CMP2 will not go below 336. Basic question; what changed?

  2. #2
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by languer View Post
    So on the picture and data on post#15 things were looking honky-dory (you were measuring at least down to 161 counts on CMP2). Your new posts state that now CMP2 will not go below 336. Basic question; what changed?

    Apologies...I've only just seen your question from a day or so ago - firstly that's very sharp of you to pick up on that detail

    What changed?

    I wish I knew....when it looked hunky dory...I didn't probe to deeply (I guess the - at the time - relief overcame me & I was a bit premature saying all was well!), I sort of put it to one side...a couple of nights later I came back to it & couldn't get the darned count down.

    I've not changed the circuit....and have only window dressed the code (I can't genuinely say what I might have benn window dressed - but it will have been minimal!), but early indications here since getting home is that it might be related to the amount of text I'm squirting out with the HSEROUT command (which I queried myself the other night...and acetronics spotted earlier today!)

    I only had a slim window of opprtunity before domestic commitments kicked in....but when 1000Hz (a nice round number to work with) was fed into comp1 I saw the count drop from 5,000 to something like 4600 when I put an Hserout in amongst the count storing! So is it related to amount of debug text I wonder?

    I'm using Paul's excellent idea of keeping it simple & plagiarising the simple code he kindly provided (less his one typo! ) ...first step is to get a good solid Comp 1 derived timer count for 1000Hz (which @20Mhz should be 5000 - and indeed it is using paul's code )...I'll then augment from there (ie bring comp2 into play)
    Last edited by HankMcSpank; - 29th September 2010 at 19:35.

  3. #3
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Ok, success (of sorts)

    By keeping it simple, this code works (many thanks to Paul, whose code sample I used, albeit in McSpank-esque form here)...

    Code:
    PIR2.5 = 0    'Clear the Comp1 interrupt flag
    Comp1Time = 0
    
    Main_Loop:
            WHILE PIR2.5 = 0       
            GOTO Main_Loop
            WEND
            TMR1H = 0                    
            TMR1L = 0
            PIR2.5 = 0
            Comp1_count:
            WHILE PIR2.5 = 0
            goto Comp1_count
            wend 
            Comp1Time.Highbyte = TMR1H  
            Comp1Time.Lowbyte = TMR1L
            TMR1H = 0                    
            TMR1L = 0
            PIR2.6 = 0
            'HSEROUT [dec Comp1Time,13, 10]  
            Comp2_count:
            WHILE PIR2.6 = 0
            goto Comp2_count
            wend
            Comp2Time.Highbyte = TMR1H  
            Comp2Time.Lowbyte = TMR1L
            TMR1H = 0                    
            TMR1L = 0
            HSEROUT ["C1=",dec Comp1Time,9,"C2=", dec comp2time, 13, 10]
            PIR2.5 = 0
            goto Main_Loop
    ie the C2 count decrements nice & smoothly (& below 336 - yay!) & totally in line with the amount of phase lag....

    (green trace is comp1 - non lagged, yellow trace is into comp2 & lagged a miniscule amout)



    .....I can get all the way down to 13-14(ish) below which the C2 count gets very jittery (ie successive counts eg 5, 11, 6, 12, 5, - you can see some 19s in that stream above)....but a comp2 count of 13 @1kHz is granular enough for me (accuracy to within 0.936 degrees @1kHz). I'm elated...*BUT*

    Quite clearly my original way is causing some issues (p& almost certainly to do with my poor sequence &/or coding), so if this way of doing it works, how can I integrate it into my main program?

    My first attempt just now failed...

    Here's the screen output...

    C1=4909 C2=13
    C1=4903 C2=13
    C1=4909 C2=13
    C1=4909 C2=13
    hello
    C1=4903 C2=13
    C1=4909 C2=13


    ie that C1 count has dropped?!! (even though the incoming frequency has remained at 1Khz)

    here's what I did (disclaimer: I didn't know how to get the main body of program to 'jump' to to the interrupt handler when Comp1 interrupted, so I deferred back to DT's method as the initial 'trigger')...

    Code:
    Comp1Time       var  word    ' used to amalgamate TMR1 High & Low Bytes.
    Comp2Time       var  word
    
          
    INCLUDE "DT_INTS-14.bas"     ' Base Interrupt System  PO90OOO9
    INCLUDE "ReEnterPBP.bas"     ' Include if using PBP interrupts
    
    ASM
    INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
            INT_Handler   CMP1_INT,  _Comp1_Int,   PBP,  yes
        endm
        INT_CREATE               ; Creates the interrupt processor
    ENDASM
    
    T1CON.0= 1  'start timer
    
    Comp1Time = 0 'clear down Comp1Time, prior to starting.
    comp2Time = 0  'clear down Comp2Time, prior to starting
    
    @ INT_ENABLE  CMP1_INT     ; enable Comparator 1 interrupts
    PIR2.5 = 0    'Clear the Comp1 interrupt flag
    Comp1Time = 0
    Comp2Time = 0
    
    'Main body of Code****************************************************************
    
    Main:
    hserout ["hello", 13, 10]
    pause 20
    goto Main
    
    END
    
    '**********************Comp1 interrupt handler*********************************************************
    Comp1_Int:
    Comp1_Loop:
            WHILE PIR2.5 = 0       
            GOTO Comp1_Loop
            WEND
            TMR1H = 0                    
            TMR1L = 0
            PIR2.5 = 0
            Comp1_count:
            WHILE PIR2.5 = 0
            goto Comp1_count
            wend 
            Comp1Time.Highbyte = TMR1H  
            Comp1Time.Lowbyte = TMR1L
            TMR1H = 0                    
            TMR1L = 0
            PIR2.6 = 0
            'HSEROUT [dec Comp1Time,13, 10]  
            Comp2_count:
            WHILE PIR2.6 = 0
            goto Comp2_count
            wend
            Comp2Time.Highbyte = TMR1H  
            Comp2Time.Lowbyte = TMR1L
            TMR1H = 0                    
            TMR1L = 0
            HSEROUT ["C1=",dec Comp1Time,9,"C2=", dec comp2time, 13, 10]
            PIR2.5 = 0
            
    @ INT_RETURN
    Last edited by HankMcSpank; - 29th September 2010 at 22:25.

  4. #4
    Join Date
    Jul 2003
    Location
    USA - Arizona
    Posts
    156


    Did you find this post helpful? Yes | No

    Default

    This is most excellent.

    You may have already corrected this, but on the original code the analog inputs for the comparators are not enabled (ANSEL.6 and ANSEL.7). Minor thing, but shouldn't hurt to follow the datasheet.

    I do agree with other suggestions, since the inputs are already digital there is not need to use the comparators. But to use the IOC (interrupt-on-change) you would most likely need to go for PORTA or PORTB (which have individual IOC bits for each input).

    General suggestion for interrupt use: keep everything short; do only the absolute minimum inside the interrupt routine.

    Even though the use of the HW USART (HSEROUT) is a plus, you should still try to do this outside the interrupt routine. Do the timer stuff inside the interrupt (i.e. clear and set timer, etc). Make a flag that tells you the interrupt "fired"; and in the main loop manipulate the data to be sent out (and send it out). I think the CCP module maybe a much better candidate for what you are doing (duh, except you would need a PIC with two CCP modules - never mind).
    Last edited by languer; - 29th September 2010 at 22:15.

  5. #5
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by languer View Post
    You may have already corrected this, but on the original code the analog inputs for the comparators are not enabled (ANSEL.6 and ANSEL.7). Minor thing, but shouldn't hurt to follow the datasheet.
    I had thought the ANSEL turned on/off the AtoD for a given pin - certainly my comparators have been working with the corresponding ANSEL deselected? I had a similar discussion with Melanie & she considered them digital....

    http://www.picbasic.co.uk/forum/show...1127#post81127 extract here....

    Quote Originally Posted by Melanie View Post
    Whether you consider a Comparator OUTPUT as analog I suppose is up to you. I consider Comparators INPUT as ANALOG but technically their OUTPUT is DIGITAL since it can only be a High or a Low. RC4 is the OUTPUT for Comparator 2. If you are using Comparator 2, you DON'T want to set that pin to ANALOG (because ANALOG refers really only to INPUTS), but you want DIGITAL OUTPUT.
    Since then I've assumed digital & therefore deselected the analog!!


    Quote Originally Posted by languer View Post
    I do agree with other suggestions, since the inputs are already digital there is not need to use the comparators. But to use the IOC (interrupt-on-change) you would most likely need to go for PORTA or PORTB (which have individual IOC bits for each input).
    I already use IOC (for switching) in the program that this melarkey is destined for - in my blissfully naive planet of "don't understand", for now, I'd prefer to keep the two interrupt variants apart! (for fear of IOC contention)

    Quote Originally Posted by languer View Post
    General suggestion for interrupt use: keep everything short; do only the absolute minimum inside the interrupt routine.
    I would agree with that, but what I've found is that unless I do stuff inside the routine, then the counts go to pot! (that's not to say I shouldn't strive to do such stuff outside the routine, but as of yet, I'm having the most success keeping it 'controlled' where I know where/when it's going to be used!

    Quote Originally Posted by languer View Post
    Even though the use of the HW USART (HSEROUT) is a plus, you should still try to do this outside the interrupt routine. Do the timer stuff inside the interrupt (i.e. clear and set timer, etc). Make a flag that tells you the interrupt "fired"; and in the main loop manipulate the data to be sent out (and send it out). I think the CCP module maybe a much better candidate for what you are doing.
    I'd love to get that HSEROUT outside....but I think therein lies the possible original problem?

    It would be nice to slowly build the picture up to see when the trouble occurs, but to do that I need some clever person to tell me how I can 'trigger' the code that 'works' above into action while the main program is running?
    Last edited by HankMcSpank; - 29th September 2010 at 22:31.

  6. #6
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Ok, this seems to work (ie it allows a 'main body' of program to run, with an interrupt handler)....

    Code:
    Comp1Time       var  word    
    Comp2Time       var  word
    phase_shift     var  word
    c               var  word
    dummy           var word
    
    
    T1CON.0= 1  'start timer
    
    Comp1Time = 0 'clear down Comp1Time, prior to starting.
    comp2Time = 0  'clear down Comp2Time, prior to starting
    
    PIR2.5 = 0    'Clear the Comp1 interrupt flag
    
    INCLUDE "DT_INTS-14.bas"     ' Base Interrupt System  PO90OOO9
    INCLUDE "ReEnterPBP.bas"     ' Include if using PBP interrupts
    
    ASM
    INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
            INT_Handler   CMP1_INT,  _Comp1_Int,   PBP,  yes
        endm
        INT_CREATE               ; Creates the interrupt processor
    ENDASM
    
    T1CON.0= 1  'start timer
    
    Comp1Time = 0 'clear down Comp1Time, prior to starting.
    comp2Time = 0  'clear down Comp2Time, prior to starting
    
    @ INT_ENABLE  CMP1_INT     ; enable Comparator 1 interrupts
    
    Top:
            c = 3600
            dummy = comp2time * c  
            phase_shift  = DIV32 comp1time
            HSEROUT ["  C1=",dec Comp1Time,9,"  C2=", dec comp2time,9, "phase_shift=", dec phase_shift/10,".",dec phase_shift//10, 13, 10]
            goto top
    
    Comp1_Int:
            PIR2.5 = 0
        Loop1:
            WHILE PIR2.5 = 0       
            GOTO Loop1
            WEND
            TMR1H = 0                    
            TMR1L = 0
            PIR2.5 = 0
            
            Comp1_count:
            WHILE PIR2.5 = 0
            goto Comp1_count
            wend 
            Comp1Time.Highbyte = TMR1H  
            Comp1Time.Lowbyte = TMR1L+2
            TMR1H = 0                    
            TMR1L = 0
            PIR2.6 = 0
            'HSEROUT [dec Comp1Time,13, 10]
                
            Comp2_count:
            WHILE PIR2.6 = 0
            goto Comp2_count
            wend
            Comp2Time.Highbyte = TMR1H  
            Comp2Time.Lowbyte = TMR1L+6
            TMR1H = 0                    
            TMR1L = 0
            if comp2time> comp1time-23 then comp2time = 0
            'HSEROUT ["C1=",dec Comp1Time,9,"C2=", dec comp2time, 13, 10]
            PIR2.5 = 0
    @ INT_RETURN
    The actual final phase calculation jitters about a bit (but I suspect that down to the somewhat jittery quality of my audio input signal into the PIC comparators)...



    Now I'm sure there are more efficient ways of doing the above - but for now, it work s& I'm chuffed!

    The actual final phase calculation jitters about a bit (but I suspect that down to the somewhat jittery quality of my audio input signal into the PIC comparators!)...




    Listen guys - a great collaborative effort there - I can't thank you all enough....hopefully this gives a bit of closure to a long & painful saga!
    Last edited by HankMcSpank; - 30th September 2010 at 00:25.

  7. #7
    Join Date
    Feb 2010
    Location
    USA, New England
    Posts
    164


    Did you find this post helpful? Yes | No

    Default

    Hi Hank,

    One more suggestion...

    It takes a long time (relatively speaking) to send out your serial string. In PBP Ints, I'm pretty sure the interrupt is not responded to until the HSEROUT line is finished. So if code space isn't a particular issue at this time, try changing
    Code:
    HSEROUT ["  C1=",dec Comp1Time,9,"  C2=", dec comp2time,9, "phase_shift=", dec phase_shift/10,".",dec phase_shift//10, 13, 10]
    to (get ready for it...)
    Code:
    HSEROUT [" "]
    HSEROUT ["C"]
    HSEROUT ["1"]
    HSEROUT ["="]
    HSEROUT [dec Comp1Time]
    HSEROUT [9]
    HSEROUT [" "]
    HSEROUT ["C"]
    HSEROUT ["2"]
    HSEROUT ["="]
    HSEROUT [dec comp2time]
    HSEROUT [9]
    HSEROUT ["p"]
    HSEROUT ["h"]
    HSEROUT ["a"]
    HSEROUT ["s"]
    HSEROUT ["e"]
    HSEROUT ["_'}
    HSEROUT ["s"]
    HSEROUT ["h"]
    HSEROUT ["i"]
    HSEROUT ["f"]
    HSEROUT ["t"]
    HSEROUT ["="]
    HSEROUT ["dec phase_shift/10]
    HSEROUT ["."]
    HSEROUT [dec phase_shift//10]
    HSEROUT [13]
    HSEROUT [10]
    Or/and shorten what you are sending....

    Best Regards,
    Paul

  8. #8
    Join Date
    Jul 2003
    Location
    USA - Arizona
    Posts
    156


    Did you find this post helpful? Yes | No

    Default

    This is an excellent work, and very easy to follow and read through. You should consider placing this in the Wiki or Project section.

    In a sort of backwards way, I had one of those aha moments out of this thread.

    I had thought the ANSEL turned on/off the AtoD for a given pin - certainly my comparators have been working with the corresponding ANSEL deselected? I had a similar discussion with Melanie & she considered them digital....
    This is absolutely true for the outputs (i.e. comparator output) as they will be either high or low. This is, however, not true for the inputs (i.e. comparator input) as your are using their analog nature to compare (in your case) against a reference (this is also alluded to on the post you mention);which is what I was referring to (ANSEL.6 and ANSEL.7). In summary, comparator outputs are digital, comparator inputs are analog.

    This is what was nagging me; something does not look correct, yet it behaves correctly (maybe). Then came the aha moment. You run the analog signal through the schmidt triggers effectively converting it from analog to digital. Then you feed the signal into the comparator. So why do you even need a comparator? You really don't, BUT, for your system you really need some sort of comparator (not an analog one, a digital one so you can trigger on its change of state). And, perhaps unbeknownst to you, that's what you created. By letting the comparator input pins be digital, you created a digital comparator (sort of like a logic gate) - very cool.

    With that said, you probably could save the schmidt triggers and run the analog waveforms straight to the comparator (they would have to be conditioned / buffered before hitting the comparator). But you have the concept working, so I would not change it now.

    Again, very nice job.

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts