Sinewaves using interrupts.


Closed Thread
Results 1 to 26 of 26

Hybrid View

  1. #1
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,604


    Did you find this post helpful? Yes | No

    Default

    Hi,
    On a project I was working on I found that the latency with DT-INTS-18 was 29uS at 20Mhz, that's 145 cycles. I measured this with the scope triggering on the external signal that was firing the interrupt and then setting an output high as the very first thing in the ISR.

    29uS is is basically 30% of the time when interrupting at 12kHz then it takes roughly the same amount of time to restore all the registers when leaving the ISR.

    Now, this was with the ISR declared as a PBP handler. I now see that you have the handler declared as an ASM-handler (but still written in) PBP. This makes it quite a bit faster since DT-INTS doesn't save the PBP system variables. BUT because of this you need to be VERY (I mean VERY) careful about what you do in your ISR if you declare it as type ASM but writes it in PBP. In THIS case it may not matter since you aren't doing anything in your main routine but once you start to add stuff there AND have an interrupt handler using the system vars without saving them you are in trouble.

    I found that an interrupt declared as ASM with the DT-INTS has a latency of around 40 cycles.

    You can read about my findings in this thread.

    /Henrik.

  2. #2
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Hi Henrik,

    thanks for the info (& the link to your thread - I'll read it tonight as it's not exactly a quick 'snappy read'!) - just to clarify, I'm using scalerobotic's code ....so anything declared as ASM, PBP etc...at this stage of my 'pic programming for dummies' learning curve.....blissfully washes over me! (in my naive programming world, I'm still convinced the earth is still flat & if you sail towards the horizon, you will fall off over the end)

    I've already picked up that when using ASM interrupts, that you have to be careful what you get up to in the interrupt handler (ie get in, get out asap - handle the stuff in your main code), but I've no intention of doing much in there (bar the odd port toggle to assist with scope observations!)

    Re generating sine waves - I've actually a couple of AD9835 ICs winging their way over the North Atlantic to me as I type - they seem to be a rather quite serious way of generating sine waves! (but while waiting I thought I'd have a dabble with this PWM method, just to start getting up to speed in the black art of Sinewaveology!)
    Last edited by HankMcSpank; - 1st October 2010 at 13:43.

  3. #3
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,604


    Did you find this post helpful? Yes | No

    Default

    Hi,
    It's not just get in get out, I'm afraid.

    PBP has a bunch of internal system variables that it uses for its needs. If you use DT-INTS and declare the handler as an ASM type handler DT-INTS doesn't save those internal system variables before entering the ISR beacuse you told it the ISR is written in ASM. (Which doesn't use PBP's system variables). But in this case the handler IS written in PBP even though it's declared as ASM type so you need to be very careful.

    It means that if that main program is in the middle of a calculation (or HSEROUT or a anything) that happens to use one or more of the system variables when the interrupt occurs AND the code in the handler ALSO need to use these variables you're pretty much screwed.

    I've only looked at this briefly but this particular handler...
    Code:
    sine:
        TMR1L = timerone.byte0
        TMR1H = timerone.byte1     
        CCPR1L = sineval[STEPCOUNT]>>1 
        stepcount = stepcount -1
        if stepcount = 0 then stepcount = 32
        toggle PortB.4 
     
    @    INT_RETURN
    ...seems to use system variable T1 so IF your main code happens to use a PBP statement that also needs T1 it's going to be a mess.

    Now, your main code (at least the one you posted) is a simple Pause and Goto and it does not seem to use T1 so you get away with it. Once you add code to the main routine that needs T1 it'll start acting up.

    It is possible to do what is being done here by carefully examining the generated code for the interrupt handler to determine which PBP system variables it uses and then save and restore only those variables.

    I hope that makes SOME sense.

    /Henrik.

  4. #4
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default

    Hi Hank (and gang),

    I know I'm the assembly language "outsider" here but I agree that interrupt 'overhead' may be a problem. If you were writing the application in assembler I would make a couple suggestions like these;

    <1>
    Consider upgrading to one of the 'enhanced' 16F1x devices which can run at 32-MHz (125-nsec Tcy) with full interrupt context save and restore built-in (= very low interrupt overhead).

    <2>
    Research DDS (Direct Digital Synthesis) and consider using a DDS-PWM or a DDS-R2R method for generating your sine waves. It may not be a good fit for your particular application but it is relatively easy to characterize frequency parameters and performance. For example, here's the characterization for an ISR "engine" for a 10-KHz 12F1822 Sine/Square/Sawtooth/Triangle wave DDS-PWM Signal Generator (using a 32-MHz clock);

    Code:
    ;
    ;  Fdds (DDS frequency) is the reciprocal of the 8-usec PWM period...
    ;
    ;    Fdds (Freq DDS) = 1 / 0.000008 = 125000-Hz
    ;
    ;  frequency resolution is Fdds (DDS frequency) divided by
    ;  the phase accumulator bit width (2^24)...
    ;
    ;    Fres (Freq Resolution) = Fdds / 2^24 = 0.007450580596923828125 Hz
    ;
    ;  to calculate the phase offset for a 10-KHz Fout signal...
    ;
    ;    Phase = INT((Fout / Fres) + 0.5)
    ;    Phase = INT((10000 / 0.007450580596923828125) + 0.5) = 1342177
    ;
    ;    --< or >--
    ;    Phase = INT(Fout / (Fdds / 2^24) + 0.5) = 1342177
    ;    Phase = INT(2^24 / (Fdds / Fout) + 0.5) = 1342177
    ;
    ;  to calculate the actual frequency output (Fout)...
    ;
    ;    Fout = Phase * Fres
    ;    Fout = 1342177 * .007450580596923828125 = ~9999.998 Hz
    ;
    ;    --< or >--
    ;    Fout = Fdds / (2^24 / Phase) = ~9999.998 Hz
    ;    Fout = Phase / (2^24 / Fdds) = ~9999.998 Hz
    ;
            org     0x004
    v_int
            banksel PIR1            ; bank 0                          |B0
            bcf     PIR1,TMR2IF     ; clear TMR2 interrupt flag       |B0
            movf    Phase+0,W       ; Accum = Accum + Phase           |B0
            addwf   Accum+0,F       ;                                 |B0
            movf    Phase+1,W       ;                                 |B0
            addwfc  Accum+1,F       ;                                 |B0
            movf    Phase+2,W       ;                                 |B0
            addwfc  Accum+2,F       ;                                 |B0
            movf    Accum+2,W       ; use 8 most significant bits     |B0
            addwf   FSR1L           ; as pwm table (array) address    |B0
            movf    INDF1,W         ; WREG = duty cycle, 0..255       |B0
            banksel CCP1CON         ; bank 5                          |B5
            bcf     CCP1CON,DC1B0   ; clr duty cycle bit 0            |B5
            bcf     CCP1CON,DC1B1   ; clr duty cycle bit 1            |B5
            lsrf    WREG,W          ; shift duty cycle bit 0 into C   |B5
            skpnc                   ; bit 0 = 1? no, skip, else       |B5
            bsf     CCP1CON,DC1B0   ; set duty cycle bit 0            |B5
            lsrf    WREG,W          ; shift duty cycle bit 1 into C   |B5
            skpnc                   ; bit 1 = 1? no, skip, else       |B5
            bsf     CCP1CON,DC1B1   ; set duty cycle bit 1            |B5
            movwf   CCPR1L          ; set duty cycle bits 7..2        |B5
            retfie                  ;                                 |B?
    ;
    The ISR "engine" for the little 12F1822 USB Signal Generator uses 26 cycles (3.25-usecs) or about 40% of the 64 cycles between interrupts. That leaves plenty of time in the main program to poll the serial port and collect a new signal "type" character and/or a new 24-bit frequency phase offset data from the PC host application.

    One problem I see trying to use DDS to generate sine waves for your application is the number of samples you might need to generate a phase shift. If you need 5° shifts it would require at least 72 samples per cycle. That means your upper frequency limit with a 125-KHz DDS would be only 1736 Hz. If you needed 2° resolution with a 5000 Hz upper frequency limit then you would need an Fdds of 900-KHz. That might be difficult even for the much faster DDS-R2R method.

    Cheerful regards, Mike
    Last edited by Mike, K8LH; - 1st October 2010 at 15:27.

  5. #5
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Thanks Henrik & Mike.

    I've no specific goal in mind here...just to have a play (a man can never have too many sine wave tools at his disposal!) ....that said I would like to be able to resolve any generated frequency to two decimal places between say 50Hz-5Khz .... upon reflection, since making my initial post at the top of this thread I'm actiually not too worried about phase wrt generating sine waves with PICs.

    I have to say, I'm having a right old head trip to to what Oscillator setup (& PIC) I need to be able to get that aforementioned two decimal place frequency resolution for that region - I need to cordon off the dining room while I have a think about this! What a nightmare it is trying to configure all this for the required frequency ...& presumably to make .01Hz increments possible, it would need a counter (accumalator?) that's in decimal along with an array dividable by 10 - not to mention a clock cycle that's also divideable by 10?!!



    oh, btw....Does anyone else get tired of typing coffee, red, Tesla, bread etc? (at least change the questions once in a while lol)
    Last edited by HankMcSpank; - 1st October 2010 at 16:36.

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


    Did you find this post helpful? Yes | No

    Default

    Ok, I'll give part of it a go:

    For a 5K signal with 32 samples, thats 32 x 5000 = 160,000/sec times to hit the interupt. With no real numbers to use here, lets say it takes 100 instructions to "hit" the int. So thats 1,600,000 ins/sec or 1.6mips. so to start off, i would think at a min 8 meg clock (2mips)

    The rest of the math depends on how the signal is generated. for instance using hpwm or maybe old school R2R D/A.

    Yes i get tired of the question
    -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!

  7. #7
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default

    Someone told me 16 PWM outputs per cycle could generate a decent filtered sine wave. If PBP can handle a much lower 20-KHz (50-usec) interrupt (with 20-MHz clock), maybe we could get Hank to check out the waveforms on his scope? For 16 outputs per cycle he could use an Fout frequency of 20000/16=1250-Hz. For 20 outputs per cycle he could use an Fout frequency of 20000/20=1000-Hz.

    So how would you PBP gurus convert this DDS engine for Hank's 20-MHz 16F690 to PBP (Accum and Phase are 24-bit variables)?

    Code:
    //
    //  setup CCP in PWM mode for 20-KHz (50-usecs) with prescale 1,
    //  postcale 1, and PR2=250-1 (20-MHz clock)
    //
    //  Fdds = 1 / 0.00005 = 20000 Hz
    //  Fres = 20000 / 2^24 = 0.0011920928955078125
    //  Phase (1250-Hz) = INT(1250 / 0.0011920928955078125 + 0.5) = 1048576
    //  Phase (1000-Hz) = INT(1000 / 0.0011920928955078125 + 0.5) =  838861
    //
    void interrupt()               //
    { pir1.TMR2IF = 0;             // clear TMR2 interrupt flag
      Accum = Accum + Phase;       // add phase offset to Accum
      ccpr1l = sine[Accum >> 16];  // setup next PWM duty cycle
    }
    We'd also need a 256 element sine table with PWM values of 0..250. Here's the output from my handy dandy Sine PWM Table Generator;

    Code:
    Number of steps: 256
       Output range: 250
     Table or Array: a
    
            125,128,131,134,137,140,143,146
            149,152,155,158,161,164,167,169
            172,175,178,181,183,186,189,191
            194,196,199,201,204,206,208,211
            213,215,217,219,221,223,225,227
            228,230,232,233,235,236,237,239
            240,241,242,243,244,245,246,246
            247,248,248,249,249,249,249,249
            250,249,249,249,249,249,248,248
            247,246,246,245,244,243,242,241
            240,239,237,236,235,233,232,230
            228,227,225,223,221,219,217,215
            213,211,208,206,204,201,199,196
            194,191,189,186,183,181,178,175
            172,169,167,164,161,158,155,152
            149,146,143,140,137,134,131,128
            124,121,118,115,112,109,106,103
            100,097,094,091,088,085,082,080
            077,074,071,068,066,063,060,058
            055,053,050,048,045,043,041,038
            036,034,032,030,028,026,024,022
            021,019,017,016,014,013,012,010
            009,008,007,006,005,004,003,003
            002,001,001,000,000,000,000,000
            000,000,000,000,000,000,001,001
            002,003,003,004,005,006,007,008
            009,010,012,013,014,016,017,019
            021,022,024,026,028,030,032,034
            036,038,041,043,045,048,050,053
            055,058,060,063,066,068,071,074
            077,080,082,085,088,091,094,097
            100,103,106,109,112,115,118,121
    Last edited by Mike, K8LH; - 1st October 2010 at 18:31.

  8. #8
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Sure, I'd be more than happy to run any test code posted up here, and respond with related scope screen shots.

    But please note, I only have a PIC16F690 & 20Mhz resonator at my disposal

    (that said I think I have a 20Mhz Xtal i my drawer somewhere if thats significant!)

    Quote Originally Posted by mackrackit View Post
    We could change it so the answers would be nice and long like:

    a pesticide used to kill lice?
    DICHLORODIPHENYLTRICHLOROETHANE
    When I buy the stuff every other week, I just ask for the shortned name - DDT ...my chemist normally charges me one thousand, one hundred & thirty three pence per bottle
    Last edited by HankMcSpank; - 1st October 2010 at 18:50.

  9. #9
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    966


    Did you find this post helpful? Yes | No

    Default

    Hi Hank

    If you're planning to use the digitally synthesised sine wave for audio purposes, please re-consider the number of samples. 16 samples are good enough to generate a sine wave for the CRO, but for the ear,.... well, it's a different game altogether.

    I had used the DDS technique, albeit with a PSOC, to generate pure tones (sinewaves of fixed frequency) for a clinical audiometer. You will get a clean sine wave on the scope, but, the distortion present in the wave will make it unsuitable for any audio purist. So, I had to switch over to the AD9832 which should be quite similar in function to the 9835(I haven't checked)

    The AD9832 is a 1024 point sampled wave DDS IC. The results I obtained from this are just excellent. Before this, I had used a ML2036 which is now obsolete.

    You might achieve the tones, but, you may not like the sound you get using a 16 point DDS. Let me not discourage your collaborative effort, but look at it as a gentle helmet I've gifted you to save the remaining hair on your head LoL

    Cheers

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


    Did you find this post helpful? Yes | No

    Default

    I want to get clear about something interupt related here. If I have a pure ASM isr, does that mean I don't have to worry about PBP stuff at all when I enter and exit? So for instance, if I set PIE for timer 1 and GIE, I know my interupt will fire any time. I also know the PIC will tend to W,STATUS, and PCLATH, (more or less depending on device). So I don't need to worry about anything else? And if I address a user defined variable in my ISR, I do that with _VariableName? If its that easy, thats wonderful.

    Sorry Hank, not trying to hijack your thread, just seems a good place to ask. I am cooking up something related to sine wave generator for you.

    @Dave and all the other kind folks that moderate for us, Thank You. I HAVE noticed this is one of the best spam free forums I have seen. I do know thats takes a LOT of work, and if my having to answer a question everytime I post helps, its the least I can do. Have to admit though, I preview my post most times, then forget to answer again. But I hope sooner or later I will learn. I have telsa spelled tesla almost every time now
    -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
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924


    Did you find this post helpful? Yes | No

    Default

    oh, btw....Does anyone else get tired of typing coffee, red, Tesla, bread etc? (at least change the questions once in a while lol)
    Not me.
    I do get aggravated by the spammer/bots though. I still deal with at least a half dozen every day and I think the other moderators deal with as many themselves. The question thing gets who knows how many.

    We could change it so the answers would be nice and long like:
    a type of explosive?
    TRINITROPHENYLMETHYLNITRAMINE
    or
    a pesticide used to kill lice?
    DICHLORODIPHENYLTRICHLOROETHANE

    But then auto complete would work for them also... if you are not a bot.
    Dave
    Always wear safety glasses while programming.

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