Sinewaves using interrupts.


Closed Thread
Results 1 to 26 of 26

Hybrid View

  1. #1
    Join Date
    Mar 2009
    Posts
    653

    Default Sinewaves using interrupts.

    I'm looking at scalerobotics (thanks Walter!) funky article wrt generating sine waves using DT's interrupts (in my nerdy-esque secret world - this has popped into "No1 slot" in my interest table!)

    I (think) I've grasped the concept - we're using timer1 to generate a precise interrupt ...at each interrupt, read a preset value from an array & this value is used to control a PWM stream, which if put through the correct filter, will produce a sine wave (have I got that bit right?)

    How granular do you think it's possible to go with the frequency - let's say if generating frequencies between 80Hz & 5Khz? (eg one decimal point, two decimal points ....no decimal points!)

    Also, I'm no filter expert...but what bandwidth can you get away with when using just the one simple RC filter? (ie max range of frequencies, again say starting at 80Hz)

    Also, if wantng to phase shift (vs an incoming signal) how granular could the phase shift 'steps' be?

    What I'm possibly thinking of doing, is to extract the frequency from an incoming guitar signal, then 'PIC generate' other sine wave frequencies from it (eg double the incoming guitar frequency) - but for maximum sonic flexibility, I have an intended use that rather than change the incoming frequency, (ie generate the same PIC generated sine frequency as the incoming guitar note), only shift the phase vs the original incoming signal.......do-able, or is this getting too taxing for a PIC?

    thanks!
    Last edited by HankMcSpank; - 2nd September 2010 at 11:31.

  2. #2
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default

    Thanks Hank! Glad to hear I am not the only nerd in the room.

    By jove, I think you've got it. Since the frequency is made from the value of the 16 bit timer, your precision is pretty good. Of course pre-scalers and post scalers could be used, depending on which timer, to broaden your frequency even more. So I would say you have lots of flexibility on the frequency.

    I am a filter newbie, so I only know that they are tuned to frequency. I noticed that Bruce had a book on filters ... and almost asked for that one as well....

    The 36 steps I used make it possible to offset the sines by 10 degree steps. Some people use 72 steps in their tables, and then that would be 5 degree offset. Not quite sure what you plan.

    What I'm possibly thinking of doing, is to extract the frequency from an incoming guitar signal, then 'PIC generate' other sine wave frequencies from it (eg double the incoming guitar frequency) - but for maximum sonic flexibility, I have an intended use that rather than change the incoming frequency, (ie generate the same PIC generated sine frequency as the incoming guitar note), only shift the phase vs the original incoming signal.......do-able, or is this getting too taxing for a PIC?
    I'm not sure if I follow exactly. You sometimes want to double the freqency, and sometimes off set the frequency, but keep the frequency? In any case, I think there is plenty of horsepower in the PIC to time your incoming frequency and also do sine out using hpwm. That is, as long as you find a good filter/sustainer to get a single frequency in for it to measure.

    http://www.picbasic.co.uk/forum/cont...-DT-interrupts
    Last edited by ScaleRobotics; - 3rd September 2010 at 16:20.
    http://www.scalerobotics.com

  3. #3
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by scalerobotics View Post
    Thanks Hank! Glad to hear I am not the only nerd in the room.

    By jove, I think you've got it. Since the frequency is made from the value of the 16 bit timer, your precision is pretty good. Of course pre-scalers and post scalers could be used, depending on which timer, to broaden your frequency even more. So I would say you have lots of flexibility on the frequency.

    I am a filter newbie, so I only know that they are tuned to frequency. I noticed that Bruce had a book on filters ... and almost asked for that one as well....

    The 36 steps I used make it possible to offset the sines by 10 degree steps. Some people use 72 steps in their tables, and then that would be 5 degree offset. Not quite sure what you plan.

    I'm not sure if I follow exactly. You sometimes want to double the freqency, and sometimes off set the frequency, but keep the frequency? In any case, I think there is plenty of horsepower in the PIC to time your incoming frequency and also do sine out using hpwm. That is, as long as you find a good filter/sustainer to get a single frequency in for it to measure.

    http://www.picbasic.co.uk/forum/cont...-DT-interrupts
    as a quick break after sorting my ongoing phase measuring conundrum tonight (with a lot of help!) ...i decided to have a quick pop at this before hitting the sack...



    Quite happy with the result - but how did you work out the value for 60Hz - you can likely see from the scope trace that I messed about with some prescalers & variable & ultimately managed to get a higher frequency (about 400Hz...that's not my code alongside, but your article!), but it was all a bit 'hit & hope'....but what's the scientific way of getting the required frequency?

    Also any idea of the maximum frequency obtainable?
    Last edited by HankMcSpank; - 30th September 2010 at 01:30.

  4. #4
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Ok, after staring at your code for 2 hours (ie until I actually looked like my Avatar!) .....your code slowly morphs into a magic eye puzzle with the words "Hank is a bit slow" popping out in 3D.

    I'd like to get to the bottom of how you set the frequency up for DDS related stuff - I think I get the jist.

    You are preloading timer1 with a 'preset count' to change the sine wave frequency (in your example FD85 ,which in decimal is 64901)

    Therefore Timer 1 is a 32 bit timer, which means it'll overlow at 65535 ...so you have 65535 - 64901 = 351 counts, before the code jumps to the interrupt handler (towards reading the next value in the sine wave array).

    Have I got this right?

    Ok, my PIC won't run at 40Mhz, so I can't copy your example 'like for like', but I'm getting an odd result - don't get me wrong, I get a decent sine wave, but not at the frequency I was expecting.

    Basically, when I type my particular settings into Mister_E's calc & divide his Interrupt frequency result by 32 (this being the amount of interrupts it takes to make one complete sine wave cycle?) ...the result is different to what I'm seeing on myscope!

    So...my settings.

    20Mhz Oscillator (ceramic resonator)
    16 bit timer
    1:1 prescaler
    Timer1 preloaded with 65122

    According to Mr E's calculator that should give an interrupt frequency of 12.048Khz - it should be just a matter of dividing that by 32 to get the sine wave coming out of the filter? (ie it takes 32 interrupts to build a full sine wave)

    therefore 12048/32 = 376.5Hz.

    But I'm seeing a 348Hz sine wave on my scope??

    So I wanted to check the actual interrupt frequency, therefore I added a 'toggle a pin' into your interrupt handler - that resulting square wave output registers @5580Hz ...this needs to be doubled this to get the actual interrupt rate, therefore the interrupt rate appears to be just 11160Hz (which if I divide by 32, surprise surprise is what my scope is seeing as a sine wave - 348.75Hz)

    I guess it takes time to service the interrupts & actually do stuff in the routine ...but that equates to about 30 timer1 counts going AWOL ...which seems a lot?

    So any idea why the discrepancy between Mister_E's calculator (which is surely right) & what I'm seeing on my scope (my scope is accurate btw!).



    Green trace (& text) relates to the sine wave, yellow trace relates to the square wave from the interrupt pin toggling (to trap the actual 'interrupt' frequency externally on my scope)

    Code:
    timerone var word 
     
    INCLUDE "DT_INTS-14.bas"     ; Base Interrupt System
    ;include "ReEnterPBP-18.bas"  ;not needed for ASM type interrupt service routines
     
    ASM
     
    INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
            INT_Handler   TMR1_INT,   _sine,   ASM,  yes
        endm
        INT_CREATE               ; Creates the interrupt processor
    ENDASM
    
    T1CON.5 = 0
    T1CON.4 = 0
    
     
    TMR1L = 255
    TMR1H = 254
    @   INT_ENABLE  TMR1_INT     ; Enable Timer 1 Interrupts  
    'timerone = $FD85   ;gives about 60 htz sine                ;gives about 60 htz sine 
    timerone = 65122  ;gives about 60 htz sine                ;gives about 60 htz sine 
    
    Main:
            pause 1
    GOTO Main
     
    '---[TMR1_INT - interrupt handler]------------------------------------------
     
    sine:
        TMR1L = timerone.byte0
        TMR1H = timerone.byte1     
        CCPR1L = sineval[STEPCOUNT]>>1 
        stepcount = stepcount -1
        if stepcount = 0 then stepcount = 32
        toggle PortC.4 
     
    @    INT_RETURN

    Could this be just down to me using a ceramic resonator @20Mhz (I have no idea what spec these things have, but the discrepancy amount to some 10%?)
    Last edited by HankMcSpank; - 1st October 2010 at 00:36.

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default

    Hi Hank,
    I think you need to account for the time it takes to
    A) Get to the interrupt handler and
    B) Reload the timer.

    DT-Ints are GREAT but it needs to save a lot of variables before actually executing your interrupt code and that takes time. Once you get to actually reload the timer a certain amount of time has passed. If you don't account for that in your reload value you are basically "turning back the time" so to speak.

    Either just tweak the reload value untill you get the desired frequency or try adding the reload value to the current value of TMR1 which should account for any time passed between actual overflow and reload. I think you need to stop the timer, grab its value into a word variable, add your reload value and write it back you TMR1 registers then restart the timer. That means you likely need to tweak the reload value slightly anyway.

    HTH
    /Henrik.

  6. #6
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Hi Henrik,

    That all makes sense....I guess I could slowly add stuff into the interrupt handler & check the scope interrupt frequency (vs Mr E's calculator), I should then be able to account for the overhead of adding each bit in ...and then build the compensation back into the code.

    I'd like to be able to generate the sine wave with a little more accuracy becuase an error of 10% is a little too much.

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