Measuring audio phase shift through a circuit with a PIC


Closed Thread
Results 1 to 40 of 50

Hybrid View

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


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by HankMcSpank View Post
    I use a 16f690 @20Mhz

    The 16F690's Comparator 1 receives the non lagged signal (set to internal VREF to trip at about 1/2 VCC)
    The 16F690's Comparator 2 receives the phase lagged signal (set to internal VREF to trip about 1/2 VCC too)

    Identical signals are fed into both comparators (bar the phase lag)

    DT's interrupts enabled for CMP1 & CMP2.

    On the scope the lag time measures about 20us - below which Comp2 will not decrement.

    I don't know enough about what's going on under the hood wrt interrupts (or timer1 zero-ing) to shine any more light on why the comp2 count won't go below 336...when clearly it should as the leading edge of the lagged signal gets close to zero lag. So being a bit wet nehind the ears, is there any other possible method I can use that circumvent this problem?
    I'm coming into this sort of late, although I've been more-or-less following this thread. Very interesting stuff!

    Anyway, here's an idea that may help--just use a single interrupt. When the first comparator causes the interrupt, get your tmr1 count and zero it, then wait in a tight loop, checking PIR2.6. That should reduce latency to an absolute minimum.

    something like
    Code:
    'Make sure the Comparator 2 interrupt handler is disabled!
    'Comparator1 Interrupt Handler++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    Comp1_Int:
            Comp1Time.Lowbyte = TMR1L  'Store away the timer1 count - this  will be the non lagged signal 'period' count.
            Comp1Time.Highbyte = TMR1H    
            TMR1H = 0                     'Set timer1 value to 0
            TMR1L = 0
            PIR2.6 = 0                     'Clear the Comparator C2 Interrupt Flag bit
    Keep_Waiting:
            WHILE  PIR2.6 = 0         'Check to see if the Comparator 2 interrupt flag has flipped
                goto Keep_Wating
            WEND
            Comp2Time.Lowbyte = TMR1L    'Store away the timer1 count again (ie once the lagged signal leading edge arrives - this is the lag count)
            Comp2Time.Highbyte = TMR1H    
    @ INT_RETURN
    You could also add some sort of check so that it would exit the loop if an unreasonable amount of time has elapsed.

    Best Regards,
    Paul

  2. #2
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    H Paul,

    Thank you very much for your input - truthfully, I was was getting too wrapped up in this over the weekend, but after drawing a blank with every avenue explored, I'm taking a self enforced mini break from that particular problem (I often find coming back to a project after a rest sparks new ideas & approaches). re your specific idea...I'll freely admit that I'm sort of out my depth when it comes to the inner working of interrupts (ie Picbasic interrupts vs ASM interrupts vs DT interrupts), but at one stage I do recall getting intensely intimate with the datasheet & having a "what the hell" pop at something *very* similar to what you mention - I saw no difference (but I will revisit in the light of your input)

    I could really do with some interrupt big hitters to chime in & outline a little a bit about how to get such time sensitive interrupt timings down to the bare minimum (assuming your suggestion isn't the only attack) ....becuase as it stands right now, I have *NO* (zilch, nada, zero, scratch) idea why that comparator2 interrupt count will not register below 336 when I feed a very slightly phase lagged signal into comp2 ...and alas, the my future (parked) status as a multimillionaire who invented widget X depends on getting that count to reflect the time lag between comp1 & comp2 tripping


    I'm in part slightly reticent to even push this one too much in the (highly possible) case there's something inherently wrong in my PIC /PICBasic approach - what I am convinced about is that the inputs to the comparators are without question correct - I may be pants at programming, but I know how to drive a scope, sig gen etc! (I think my youtube video illustrates the issue seems to be a valid one)

    if anyone out their in the global 'PIC interest land' feels up to the challenge - they could see themselves what happens when they feed near identically phased signals (ie a clock?) into comparator1 & comparator2 (that said an identical signal might cause problems with a race scenario?...but I concede that most don't have the faciilities or interest to setup an all pass to phase shift the two signals!)...in principle, with identical (phase) signals into both comparators, the count for comparator 2 ought to be very close to zero (like single digits)

    But I will come back to this (& first on the list will be your suggestion..if for no other reason thatn your is the only suggestion I have, lol) - I'm presently now working on Project Y - it's not gonna be the blockbuster that Widget X will be ...but got to keep keep my kids in Nike trainers somehow or other

    Edit: While I'm publicily declaring my woeful lack of grasp of time sensitive h/w & corresponding code....I also wonder if changing my PIC might help to get that comp2 count down? (I'm using a 16F690 not becuase it's necessarily the most suitable - but it came bundled with my PIKIT2 starter kit & I've stuck with it from new and have started to get the hang of it a little - when your grappling in the dark as often as am, you need a torch that's familiar!), but I see a chart like this http://www.microchip.com/en_us/technology/xlp/ & then wonder, is there a more efficient PIC for doing this type of stuff out there...??? (eg pics optimised for single instructions - not even sure what that means but the bar chart looks like a shocker!)
    Last edited by HankMcSpank; - 28th September 2010 at 23:48.

  3. #3
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    971


    Did you find this post helpful? Yes | No

    Default

    Hi Hank

    Since you're stuck, I wonder if you could post/PM your code of now so that I can take a whack at it. I'll see if I can find your problem with the min value of comp2 value.

    The barest minimum code which will compile and show the problem is sufficient. I should be able to run it.

    Regards

  4. #4
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Jerson View Post
    Hi Hank

    Since you're stuck, I wonder if you could post/PM your code of now so that I can take a whack at it. I'll see if I can find your problem with the min value of comp2 value.

    The barest minimum code which will compile and show the problem is sufficient. I should be able to run it.

    Regards
    Many thanks Jerson.

    The latest version of code was part of a hulking long program, but I found an earlier variant, which is purely deals with the comparator interrupt timer1 counting & therefore makes it a lot easier to look at...

    Code:
    @ __CONFIG _FCMEN_OFF & _HS_OSC & _WDT_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOR_OFF & _PWRTE_OFF
    
    DEFINE  OSC 20          ' set Oscillator at 20Mhz.
    DEFINE  NO_CLRWDT 1   ' PBP doesn't clear WDT automatically
    DEFINE HSER_TXSTA 24h ' Enable transmit
    DEFINE HSER_SPBRG 129 ' set USART to 9600 baud  @20Mhz
    
    '*********************************************************************************
    '16F690 Pin Connections....
    ' PIN# NAME     USE & CONNECTION
                    '  1   Vdd      +5VDC power supply
    TRISC.4 = 0     '  6   RC4      C2OUT
    TRISC.3 = 1     '  7   RC3      C12IN3- (comparator1 input)
    TRISC.2 = 1     '  14  RC2      C12IN2- (comparator2 input)
    TRISA.2 = 0     '  17  RA2      C1OUT
                    '  20  Vss      Ground
    '*********************************************************************************
    OSCCON.0 = %0001000 
    txsta = %10100100   'setup the tx register
    RCSTA.7 = 1         ' Enable RB7 for TX USART
    INTCON.0 = 0        ' clears the RABIF Flag (to 0), COULD be 1 on reset (unique to F690)
    ANSEL      = 0      'disable AtoD.
    ANSELH     = 0      'disable AtoD.
    
    'Turn on & Set up Comparator 1
    CM1CON0.7 = 1       'Comparator 1 on.
    CM1CON0.6 = 0       'C1OUT POLARITY BIT
    CM1CON0.5 = 1       '1 = C1OUT is present on the C1OUT pin (pin 17)
    CM1CON0.4 = 1       'C1OUT logic - 0 is not inverted  (1 for inverted)
    CM1CON0.3 = 0       'unimplemented
    CM1CON0.2 = 1       'Connect internally to the output of C1VREF   (or 0 for the the associated comp 'in' ext pin)
    CM1CON0.1 = 1       'this bit with bit 1 set the external incoming pin - in this case c12in3- (pin 7)
    CM1CON0.0 = 1       'this bit with bit 1 set the external incoming pin - in this case c12in3- (pin 7)
    
    'Turn on & Set up Comparator 2
    CM2CON0.7 = 1       'Comparator 2 on.
    CM2CON0.6 = 0       'C1OUT POLARITY BIT
    CM2CON0.5 = 1       '1 = C2OUT is present on the C2OUT pin (pin 6)
    CM2CON0.4 = 1       'C1OUT logic is not inverted  (1 for inverted)
    CM2CON0.3 = 0       'unimplemented
    CM2CON0.2 = 1       'Connect internally to the output of C1VREF (or 0 for the the associated comp 'in' ext pin)
    CM2CON0.1 = 1       'this bit with bit 1 set the external incoming pin - in this case c12in2- (pin 14)
    CM2CON0.0 = 0       'this bit with bit 1 set the external incoming pin - in this case c12in2- (pin 14)
    
    ' Setup the internal VREF
    VRCON.7 = 1         'Comparator1 CV Ref enable bit
    VRCON.6 = 1         'Comparator2 CV Ref enable bit 
    VRCON.5 = 0         'high or low range  0 = High Range, 1 = low range
    VRCON.4 = 0         '0.6V Reference Enable bit   ....0 is disabled
    VRCON.3 = 0         'these 4 bits set the divider of the VREF ladder 16 values - 7 should yield 1/2 VCC
    VRCON.2 = 1         'these 4 bits set the divider of the VREF ladder 16 values - 7 should yield 1/2 VCC
    VRCON.1 = 1         'these 4 bits set the divider of the VREF ladder 16 values - 7 should yield 1/2 VCC
    VRCON.0 = 1         'these 4 bits set the divider of the VREF ladder 16 values - 7 should yield 1/2 VCC
    
    
    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
            INT_Handler   CMP2_INT,  _Comp2_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
    @ INT_ENABLE  CMP2_INT     ; enable Comparator 2 interrupts
    
    'Main body of Code****************************************************************
    Main:
            HSEROUT ["comp1=",dec Comp1Time,9,"comp2Time=", dec comp2time, 13, 10]
            PAUSE 80
            goto Main
            end       
    
    'Comparator1 Interrupt Handler++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    Comp1_Int:
            Comp1Time.Lowbyte = TMR1L       'Store timer1 Low into a variable  
            Comp1Time.Highbyte = TMR1H      'Store timer1 high into a variable.
            TMR1H = 0                                   'Set the high part of the timer value to 0
            TMR1L = 0                                    'Set the low part of the timer value to 0
    
    @ INT_RETURN
    
    
    'Comparator2 Interrupt Handler++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    Comp2_Int:
            Comp2Time.Lowbyte = TMR1L       'Store timer1 Low into a variable 
            Comp2Time.Highbyte = TMR1H      'Store timer1 high into a variable.
            TMR1H = 0                                  'Set the high part of the timer value to 0
            TMR1L = 0                                   'Set the low part of the timer value to 0
            
    @ INT_RETURN
    Last edited by HankMcSpank; - 29th September 2010 at 09:21.

  5. #5
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    971


    Did you find this post helpful? Yes | No

    Default

    Hi Hank

    I may be wrong here, but, my suspicion is you are losing time in reentering PBP in your ISRs. See, a lot of PBP registers have to be saved even if they are not going to be used because you flagged your ISR to be coded using PBP functions.

    I suggest you slim it down by using ASM inside the ISR and avoiding ReEnterPbp. You should see better results.

    I might sound like a heretic here, but I prefer coding my ISR in ASM even though it may be painful to code.

    Regards

  6. #6
    Join Date
    May 2004
    Location
    NW France
    Posts
    3,653


    Did you find this post helpful? Yes | No

    Default

    Hi, Jerson

    + 1000 ...

    when I see the interrupts content (!) I do not understand why not to write them in . asm ...

    isn't worth saving and restoring all the PBP variables ... as saving and resetting TMR1 only need 4 more " _ " characters ...


    Now ... thinking to it ...

    if those measurements are " changed " while calculating frequency and Phase ...
    not so good ... eh !

    do not know about transmitting results nor ... ( didn't see any interrupt disabling around HSEROUT ...)

    Alain
    Last edited by Acetronics2; - 29th September 2010 at 13:07.
    ************************************************** ***********************
    Why insist on using 32 Bits when you're not even able to deal with the first 8 ones ??? ehhhhhh ...
    ************************************************** ***********************
    IF there is the word "Problem" in your question ...
    certainly the answer is " RTFM " or " RTFDataSheet " !!!
    *****************************************

  7. #7
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    As a relative PIC (& programming) n00b, even I realised that with every interrupt (& there'll be a whole heap of them generated here), some registers need to be stored away to be picked up again once the interrupt has finished. As the incoming audio frequency rises, the interrupt rate gets higher & higher eg at 2.5Khz, that's an interrupt every 400us...but it's worse than that, becuause there are two comparators, so it's actually an interrupt every 200us!

    So if having to store/restore registers every 200us, then it obviously makes sense to use the fastest interrupts - that's where I come unstuck ....I only presently know how to us DT's interrupts! (& I have no clue as to how fast they are vs ASM interrupts ...it's all a bit "Whoah...there goes scary stuff" at the moment!)

    Re your comment...

    I suggest you slim it down by using ASM inside the ISR and avoiding ReEnterPbp. You should see better results.

    bearing in mind the actualy routine is quite small....

    Comp1 Interrupt routine...
    store timer 1 count to a Variable "X"
    reset timer 1


    Comp2 Interrupt routine...
    store timer 1 count to a Variable "y"
    reset timer 1

    ..... would it be possible to at least get me started?

    Re the ISR - how would that be triggered?

    Re the ISR content - what ASM would that entail?

    I'm not expecting anyone to do this for me, but when you don't know where to even start....then any initial guidance is most welcome!

    Edit: Also, are there any suitable tools that can help me work out what's going on inside the PIC - I'm thinking along the lines of simulating in step time (vs real time) & seeing what's going on wrt registers.
    Last edited by HankMcSpank; - 29th September 2010 at 14:30.

  8. #8
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by prstein View Post
    Code:
    'Make sure the Comparator 2 interrupt handler is disabled!
    'Comparator1 Interrupt Handler++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    Comp1_Int:
            Comp1Time.Lowbyte = TMR1L  'Store away the timer1 count - this  will be the non lagged signal 'period' count.
            Comp1Time.Highbyte = TMR1H    
            TMR1H = 0                     'Set timer1 value to 0
            TMR1L = 0
            PIR2.6 = 0                     'Clear the Comparator C2 Interrupt Flag bit
    Keep_Waiting:
            WHILE  PIR2.6 = 0         'Check to see if the Comparator 2 interrupt flag has flipped
                goto Keep_Wating
            WEND
            Comp2Time.Lowbyte = TMR1L    'Store away the timer1 count again (ie once the lagged signal leading edge arrives - this is the lag count)
            Comp2Time.Highbyte = TMR1H    
    @ INT_RETURN
    You could also add some sort of check so that it would exit the loop if an unreasonable amount of time has elapsed.

    Best Regards,
    Paul
    I like Pauls approach, Seems to be the least amount of time between Comp1 and 2. one thing I would do, is program his while loop in ASM. This is because I have no idea how many instructions it takes using PBP. I think this will mask the issue of how long it takes to actually enter the handler. Which is what I think above folks are reffering to with the PBP include.

    heres the while loop in asm:
    Code:
         BCF PIR2,6       --> clears the comp 2 int flag
    HERE                    --> label to jump to
         BTFSS PIR2,6  --> test if comp 2 int flag is set
         GOTO HERE     --> not set, go back to test
    CONTINUE            --> Comp 2 int occured, do what ever needs to be done
    The above will take exactly 1 instruction to enter the loop, then 3 inscrutions to to run per loop. now for some math:

    you are running a 20mHz clock, so thats 5MIPS. so 1 instruction takes .0000002 sec to execute. At 1400 htz, each cycle takes .0071428 sec. that devided by 360 = .00000198sec per degree. so you should be able to measure to almost .5 degree. assuming comp2 fires between BCF and BTFSS, thats 3 instrution cycles, or .0000006 sec.(I think BTFSS may take 2 cycles when true)

    Someone please check my math, but these numbers show you have far too much overhead somewhere that can only be explained by the above posts.
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  9. #9
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by cncmachineguy View Post
    I like Pauls approach, Seems to be the least amount of time between Comp1 and 2. one thing I would do, is program his while loop in ASM. This is because I have no idea how many instructions it takes using PBP. I think this will mask the issue of how long it takes to actually enter the handler. Which is what I think above folks are reffering to with the PBP include.

    heres the while loop in asm:
    Code:
         BCF PIR2,6       --> clears the comp 2 int flag
    HERE                    --> label to jump to
         BTFSS PIR2,6  --> test if comp 2 int flag is set
         GOTO HERE     --> not set, go back to test
    CONTINUE            --> Comp 2 int occured, do what ever needs to be done
    The above will take exactly 1 instruction to enter the loop, then 3 inscrutions to to run per loop. now for some math:

    you are running a 20mHz clock, so thats 5MIPS. so 1 instruction takes .0000002 sec to execute. At 1400 htz, each cycle takes .0071428 sec. that devided by 360 = .00000198sec per degree. so you should be able to measure to almost .5 degree. assuming comp2 fires between BCF and BTFSS, thats 3 instrution cycles, or .0000006 sec.(I think BTFSS may take 2 cycles when true)

    Someone please check my math, but these numbers show you have far too much overhead somewhere that can only be explained by the above posts.
    I agree with the maths...and I agree with the summary (something somewhere is taking way too long). Now that I have a few people interested & feeding in ideas , I will pull the breadboard out of cold storage tonight & try Paul's code.


    Bert, re this...

    Code:
         BCF PIR2,6       --> clears the comp 2 int flag
    HERE                    --> label to jump to
         BTFSS PIR2,6  --> test if comp 2 int flag is set
         GOTO HERE     --> not set, go back to test
    CONTINUE            --> Comp 2 int occured, do what ever needs to be done
    That looks like what will happen when comp2 interrupts....but within my program, how do I setup the 'trigger' condition ...ie to get the program to go and do that when a comp2 interrupt has arrived?

    I will feedback the results (it might be late - ie 21.30 GMT-ish .....got to do the 'kids off to bed' rigamrole first! Hey there's an idea...rather than read them Noddy goes to the Seaside, I could read them some of the ASM code put forward by Bert!! )
    Last edited by HankMcSpank; - 29th September 2010 at 14:56.

  10. #10
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by HankMcSpank View Post
    Hey there's an idea...rather than read them Noddy goes to the Seaside, I could read them some of the ASM code put forward by Bert!! )
    LMAO, I always thought datasheets were better for this.
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

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


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by HankMcSpank View Post
    .got to do the 'kids off to bed' rigamrole first! Hey there's an idea...rather than read them Noddy goes to the Seaside, I could read them some of the ASM code put forward by Bert!! )
    My wife, back when she was studying to be an EMT, would recite her "protocols" (sort of flow charts for emergency medical actions) to get my daughter to go to sleep.

    Anyway, I've never used the DT interrupts. I've heard great things about them but never had cause to use them. I would do this by setting the registers for a single interrupt source, i.e. comparator 1. And I would use PBP interrupts (because I am a simple man...) at least at the offset. Once I had that working I would consider something more complicated (ASM interrupts) if the speed wasn't fast enough.

    Perhaps in the spirit of keeping it simple, don't use *any* interrupt routine. In the main loop, just keep checking the the state of the Comp1 interrupt flag, something like

    Code:
    PIR2.5 = 0    'Clear the Comp1 interrupt flag
    Main_Loop:
        WHILE PIR2.5 = 0
            GOTO Main_Loop
        WEND
            Comp1Time.Lowbyte = TMR1L  'Store away the timer1 count - this  will be the non lagged signal 'period' count.
            Comp1Time.Highbyte = TMR1H    
            TMR1H = 0                     'Set timer1 value to 0
            TMR1L = 0
            PIR2.6 = 0                     'Clear the Comparator C2 Interrupt Flag bit
    Keep_Waiting:
            WHILE  PIR2.6 = 0         'Check to see if the Comparator 2 interrupt flag has flipped
                goto Keep_Wating
            WEND
            Comp2Time.Lowbyte = TMR1L    'Store away the timer1 count again (ie once the lagged signal leading edge arrives - this is the lag count)
            Comp2Time.Highbyte = TMR1H    
            HSEROUT ["comp1=",dec Comp1Time,9,"comp2Time=", dec comp2time, 13, 10]
            PIR2.5 = 0    'Clear the Comp1 interrupt flag
            goto Main_Loop
    END
    Best Regards,
    Paul

  12. #12
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    971


    Did you find this post helpful? Yes | No

    Default

    Ok, just to show you what is involved in ASM interrupts, this is an example for your particular case. This is the first time I am trying something like this using DT_ints , so, I may be off the mark. Most times I do it the hard way - pure asm code. Someone please correct me if I am wrong here. You should be able to realize significant improvement in the values you see. Darrell's wrapper code is cool and if you still need to save some more, look at the generated LST file and you should be able to sneak a trick or two from there. The ISR vector is at location 0004 in the PIC. So, you will find a goto INTHAND at that address.

    In your case since you are not doing any math functions or gosubs in the INTs, you could keep the PBP code as-is and do away with the ASM. Can save you some agony


    Code:
    @ __CONFIG _FCMEN_OFF & _HS_OSC & _WDT_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOR_OFF & _PWRTE_OFF
    
    DEFINE  OSC 20          ' set Oscillator at 20Mhz.
    DEFINE  NO_CLRWDT 1   ' PBP doesn't clear WDT automatically
    DEFINE HSER_TXSTA 24h ' Enable transmit
    DEFINE HSER_SPBRG 129 ' set USART to 9600 baud  @20Mhz
    
    '*********************************************************************************
    '16F690 Pin Connections....
    ' PIN# NAME     USE & CONNECTION
                    '  1   Vdd      +5VDC power supply
    TRISC.4 = 0     '  6   RC4      C2OUT
    TRISC.3 = 1     '  7   RC3      C12IN3- (comparator1 input)
    TRISC.2 = 1     '  14  RC2      C12IN2- (comparator2 input)
    TRISA.2 = 0     '  17  RA2      C1OUT
                    '  20  Vss      Ground
    '*********************************************************************************
    OSCCON.0 = %0001000 
    txsta = %10100100   'setup the tx register
    RCSTA.7 = 1         ' Enable RB7 for TX USART
    INTCON.0 = 0        ' clears the RABIF Flag (to 0), COULD be 1 on reset (unique to F690)
    ANSEL      = 0      'disable AtoD.
    ANSELH     = 0      'disable AtoD.
    
    'Turn on & Set up Comparator 1
    CM1CON0.7 = 1       'Comparator 1 on.
    CM1CON0.6 = 0       'C1OUT POLARITY BIT
    CM1CON0.5 = 1       '1 = C1OUT is present on the C1OUT pin (pin 17)
    CM1CON0.4 = 1       'C1OUT logic - 0 is not inverted  (1 for inverted)
    CM1CON0.3 = 0       'unimplemented
    CM1CON0.2 = 1       'Connect internally to the output of C1VREF   (or 0 for the the associated comp 'in' ext pin)
    CM1CON0.1 = 1       'this bit with bit 1 set the external incoming pin - in this case c12in3- (pin 7)
    CM1CON0.0 = 1       'this bit with bit 1 set the external incoming pin - in this case c12in3- (pin 7)
    
    'Turn on & Set up Comparator 2
    CM2CON0.7 = 1       'Comparator 2 on.
    CM2CON0.6 = 0       'C1OUT POLARITY BIT
    CM2CON0.5 = 1       '1 = C2OUT is present on the C2OUT pin (pin 6)
    CM2CON0.4 = 1       'C1OUT logic is not inverted  (1 for inverted)
    CM2CON0.3 = 0       'unimplemented
    CM2CON0.2 = 1       'Connect internally to the output of C1VREF (or 0 for the the associated comp 'in' ext pin)
    CM2CON0.1 = 1       'this bit with bit 1 set the external incoming pin - in this case c12in2- (pin 14)
    CM2CON0.0 = 0       'this bit with bit 1 set the external incoming pin - in this case c12in2- (pin 14)
    
    ' Setup the internal VREF
    VRCON.7 = 1         'Comparator1 CV Ref enable bit
    VRCON.6 = 1         'Comparator2 CV Ref enable bit 
    VRCON.5 = 0         'high or low range  0 = High Range, 1 = low range
    VRCON.4 = 0         '0.6V Reference Enable bit   ....0 is disabled
    VRCON.3 = 0         'these 4 bits set the divider of the VREF ladder 16 values - 7 should yield 1/2 VCC
    VRCON.2 = 1         'these 4 bits set the divider of the VREF ladder 16 values - 7 should yield 1/2 VCC
    VRCON.1 = 1         'these 4 bits set the divider of the VREF ladder 16 values - 7 should yield 1/2 VCC
    VRCON.0 = 1         'these 4 bits set the divider of the VREF ladder 16 values - 7 should yield 1/2 VCC
    
    
    Comp1Time       var  word    ' used to amalgamate TMR1 High & Low Bytes.
    Comp2Time       var  word
    
    ;-- Place a copy of these variables in your Main program -------------------
    ;--   The compiler will tell you which lines to un-comment                --
    ;--   Do Not un-comment these lines                                       --
    ;---------------------------------------------------------------------------
    wsave   VAR BYTE    $20     SYSTEM      ' location for W if in bank0
    ;wsave   VAR BYTE    $70     SYSTEM      ' alternate save location for W 
                                             ' if using $70, comment wsave1-3
    
    ' --- IF any of these three lines cause an error ?? ------------------------
    '       Comment them out to fix the problem ----
    ' -- Which variables are needed, depends on the Chip you are using -- 
    wsave1  VAR BYTE    $A0     SYSTEM      ' location for W if in bank1
    wsave2  VAR BYTE    $120    SYSTEM      ' location for W if in bank2
    ;wsave3  VAR BYTE    $1A0    SYSTEM      ' location for W if in bank3
    ' --------------------------------------------------------------------------
    
    
    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   CMP_INT,  _Comp1_Int,   ASM, yes
            INT_Handler   CMP2_INT,  _Comp2_Int,   ASM,  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
    @ INT_ENABLE  CMP2_INT     ; enable Comparator 2 interrupts
    
    'Main body of Code****************************************************************
    Main:
            HSEROUT ["comp1=",dec Comp1Time,9,"comp2Time=", dec comp2time, 13, 10]
            PAUSE 80
            goto Main
            end       
    
    'Comparator1 Interrupt Handler++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    Comp1_Int:
    '        Comp1Time.Lowbyte = TMR1L       'Store timer1 Low into a variable  
    '        Comp1Time.Highbyte = TMR1H      'Store timer1 high into a variable.
    '        TMR1H = 0                                   'Set the high part of the timer value to 0
    '        TMR1L = 0                                    'Set the low part of the timer value to 0
    asm
        movf  TMR1L,w
        movwf _Comp1Time+0    ; the lsb
        movf  TMR1H,w
        movwf _Comp1Time+1    ; the msb
        clrw
        movwf TMR1L
        movwf TMR1H
    endasm
    
    @ INT_RETURN
    
    
    'Comparator2 Interrupt Handler++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    Comp2_Int:
    '        Comp2Time.Lowbyte = TMR1L       'Store timer1 Low into a variable 
    '        Comp2Time.Highbyte = TMR1H      'Store timer1 high into a variable.
    asm
        movf  TMR1L,w
        movwf _Comp2Time+0    ; the lsb
        movf  TMR1H,w
        movwf _Comp2Time+1    ; the msb
    endasm
            
    @ INT_RETURN
    Last edited by Jerson; - 29th September 2010 at 15:38. Reason: :)

  13. #13
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Hi Jerson,

    So am I getting this right - you are using DT's interrupt as the 'trigger' to enter an actual routine that has ASM within?

    Kind of a like hybrid solution?

    Apologies for the naive line of questioning, but what's the pros cons of the (3?) type of interrupts available to user of Picbasic....

    PICbasic Interrupts
    DT's Interrupts,
    ASM Interrupts.

    hi Paul,

    i'm digging that idea about keeping it simple - once we've got to the bottom of the 'overhead', I can think about putting the solution back as an interrupt.

    Great stuff guys - I've got a new spring in my step with all this.
    Last edited by HankMcSpank; - 29th September 2010 at 15:41.

  14. #14
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    971


    Did you find this post helpful? Yes | No

    Default

    Apologies for the naive line of questioning, but what's the pros cons of the (3?) type of interrupts available to user of Picbasic....

    PICbasic Interrupts
    DT's Interrupts,
    ASM Interrupts.
    No need for apologies. We all walked your way once upon a time.....

    PBP interrupts - the worst kind - you use them when you cannot think of anything else.
    It is as cruel as - execute one PBP statement, look for an interrupt, and repeat
    So, the real time nature of interrupts is lost.

    DT's interrupts - a superb wrapper to ease programmer pain
    Just use it and get your job done without having to bother with registers and internals connected with the particular interrupt you need.

    ASM interrupts - for those who like to drive Ferrari
    You know to drive it, don't look back. It is the fastest one there is!!! But you need to know how to ....

    Your best bet, DT_ints is your friend

    Cheers

  15. #15
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Thanks for the clarification...

    Quote Originally Posted by Jerson View Post
    No need for apologies. We all walked your way once upon a time.....

    Your best bet, DT_ints is your friend
    Except it seem most are now telling me to use ASM

    Does this mean I'm being unfaithful?!!

    Darrel - it's not you, i promise ...it's me.
    Last edited by HankMcSpank; - 29th September 2010 at 16:16.

  16. #16


    Did you find this post helpful? Yes | No

    Default

    These are some really good ideas comming forth. I can try Paul's idea, of one interupt
    and poll the the second in the ISR. I am already polling the CMCON.6 and 7. This should
    cut the processing time by a good bit.

    Something occured to me, since you are using schmitt triggers on the inputs, you also don't need to use the comparator interupts. You might find the CCP modules could do the same thing in a more effective way? Or change on portb. This also allows you to use other pics that don't have the comparators.

    I never put togeather my phase shifter. Need to get back on it.

    Interesting project!

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


    Did you find this post helpful? Yes | No

    Default

    Hi Jerson,

    Your right, of course, in everything you said. However there is a place for PBP interrupts. First, for beginners (and even people who, like me, use the absolute minimum of assembly) it is simple, straightforward, and easy.

    Second, that high overhead isn't a big factor if used judiciously. For example, here's the entire code for the main loop of one of my products:
    Code:
    On Interrupt goto IntHandler
    INTCON.1 = 0 	'clear the INT0 flag
    PIR1.5 =  0		'clear the USART interrupt
    enable
    '#############
    ' Start of Main Loop
    '#############
    Start:
    	if USB_ON = 1 then
    	  	bConnected = true   
    	else  'USB_ON = 0
    	  	bConnected = FALSE
    	endif	
    
    	if bConnected = false and bStayInFastMode = false then
    		OSCCON =  %10000000		'32kHz, periperals should run in sleep mode
    	endif
    	@ nop
    	@ sleep                                           'snooze soundly until woken
    goto Start
    '############
    ' End of Main Loop
    '############
    disable
    The main loop checks to see if USB (through an FTDI serial converter) is connected, and if so it stays awake. Otherwise it goes to sleep until the interrupt wakes it (which in this case happens to be either a pulse from an external RTC or data in the serial buffer). The other ~1000+ lines of code are after the "disable" so the PBP interrupt overhead is not in them. I'm sure there are other ways to accomplish the same end, but the above works perfectly. I probably could have moved the ENABLE to just before the "@ nop" and saved another few bytes even.

    Incidentally, @ nop and @ sleep are the full extent of my assembly knowledge...8^)

    With all that said, I really end up not using interrupts very much at all (except to wake a sleeping PIC). What I do is look at the interrupt flags when convenient for the code. This keeps it nice and simple and controlled. Like I said before, I am a simple man.

    Again, I'm not disagreeing or disputing anything you said, just trying to carve out some justification for PBP ints for us simpler folk. It just has to work, it doesn't (always) have to be pretty. Ferraris are nice I suppose, but I hear they're high-maintenance and sort of temperamental. I have a real good time kicking around on my little scooter; it certainly gets me there. If someone told me I had to use ASM ints I would have given up before I started.

    I really need to look into these DT Ints that everybody keeps talking about...

    Best Regards,
    Paul

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