1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

12 simultaneous & unique frequencies (PWM)

Discussion in 'AVR' started by wip, Mar 20, 2014.

  1. wip

    wip Member

    Joined:
    Nov 20, 2013
    Messages:
    38
    Likes:
    2
    Location:
    Montreal, Canada
    Hi everyone,

    What I am trying to do
    Outputting 12 simultaneous & unique frequencies (ie: 220hz, 440hz + 10 others).

    What I am using
    Atmega640
    2x 8-bit timers
    4x 16-bit timers
    12 PWM channels

    Problem 1) 8-bit timers
    In "Fast PWM" mode, using the 8-bit timers, I cannot set the TOP value (it's fixed at 255). So I can only change the "prescaler" (1024,256,128,64,32,8,1). Doesn't correspond to my frequencies. I was looking at the CTC mode, from what I understand, I could set the compare on match and toggle a pin, but will I be able to use 2 simultaneous & unique value for compare on match?

    Problem 2) 16-bit timers
    With the 16-bit timers, I can set the TOP value in a register, but this value is shared for both channels (A/B). It won't be possible to have 2 simultaneous & unique frequency for each channel?

    Any suggestion or info would be much appreciated,
    Thanks!
     
  2. alec_t

    alec_t Well-Known Member Most Helpful Member

    Joined:
    Jul 10, 2011
    Messages:
    9,325
    Likes:
    1,231
    Location:
    Cardiff, Wales
    Do your frequencies have to be very specific ones, or is it sufficient that they are just different from each other (which might simplify the code)?
     
  3. wip

    wip Member

    Joined:
    Nov 20, 2013
    Messages:
    38
    Likes:
    2
    Location:
    Montreal, Canada
    Very specific for example:
    207.652, 220.000, 233.082, 246.942, 261.626, 277.183 hz

    I do understand that I won't be able to have that precision, but for example 207hz will be fine.
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. ClydeCrashKop

    ClydeCrashKop Well-Known Member

    Joined:
    Apr 28, 2005
    Messages:
    1,044
    Likes:
    175
    Location:
    Florida

    To get 220hz, just output every other pulse from the 440hz. Are there any other multiples you can do that with?
     
  6. wip

    wip Member

    Joined:
    Nov 20, 2013
    Messages:
    38
    Likes:
    2
    Location:
    Montreal, Canada
    Sadly it won't work, I am trying to have a basic polyphonic (12 voices) midi synth:
    pitch 36 is 207.652
    pitch 37 is 220.000
    pitch 38 is 233.082
    pitch 39 is 246.942
    pitch 40 is 261.626
    pitch 41 is 277.183
    pitch 42 is 293.665
    pitch 43 is 311.127
    pitch 44 is 329.628
    pitch 45 is 349.228
    pitch 46 is 369.994
    pitch 47 is 391.995

    I think the way to go is to use the CTC mode to toggle the pin (compare match), but I am not sure, will I be able to output those frequencies at the same time on 12 pins?
     
  7. NorthGuy

    NorthGuy Well-Known Member

    Joined:
    Sep 8, 2013
    Messages:
    1,218
    Likes:
    206
    Location:
    Northern Canada
    I'm afraid you will have to do it with CPU. Have I high frequency timer interrupt, say every 10us, have 12 independent software counters (one for each frequency). Decrement all counters in each timer interrupt and when a counter goes to zero, flip the corresponding output and re-set the counter to the desired value. I'm not sure if your MCU is fast enough for that. You might need to upgrade.
     
  8. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    Watch lectures from 13 to 16.. if you are impatient, then lecture 15 will get your motivation up to watch the others.
    https://www.youtube.com/playlist?list=PLD7F7ED1F3505D8D5

    You can skip the first 16 minutes. From that on it is all you want to know. Rest of the lectures add more theory and details.
    Lecture 15: Noise generator, Direct Digital Synthesis, PWM


    After that go to lecture 16.. it is all about implementation.. that is code.
     
    Last edited: Mar 20, 2014
  9. wip

    wip Member

    Joined:
    Nov 20, 2013
    Messages:
    38
    Likes:
    2
    Location:
    Montreal, Canada
    Ok looks like it is impossible to output 12 unique & simultaneous frequencies using an Atmage640 (12 pwm channels - 6 timers: 2x 8-bit, 4x 16-bit). I tried the CTC mode & Fast PWM but in both case the channel B is always related to channel A is some ways.

    So right now the only solution I have is the one recommended by NorthGuy. I tried it, I can only get down to 136us before my USB disconnect (I am using V-USB). Is this will be enough to have precision over the 12 frequencies? I didn't really tested out, but 136us is 7352.94hz which is enough for my needs but maybe I will not be able to set the desire frequency with the decremented variable (let's say 23 vs 24 is too much of a big frequency step - ie: 432hz - 459hz)?

    Someone on irc #avr said:
    "or using 6 pwm and 6 bitbang"?
     
    Last edited: Mar 21, 2014
  10. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    Why you need to output the frequencies to 12 different output channels.. aren't you going to mix them together anyway? All you need is one pwm channel. Mix the 12 channels in software.
     
    Last edited: Mar 21, 2014
  11. wip

    wip Member

    Joined:
    Nov 20, 2013
    Messages:
    38
    Likes:
    2
    Location:
    Montreal, Canada
    I wish I could :)
    I have to control 12 independant speakers.

    My conclusion:
    Using an Atmage640 at 16mhz with V-USB and 12 ADC channels = impossible to output 12 simultaneous and unique frequencies (with enough precision ie: 430hz, 422hz).

    My current idea:
    Use many Attiny with ISP communication. I really want to avoid this ($, time).
     
  12. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    Can I ask why?

    Maybe one AVR that is dedicated to software pwm and one that gives it commands (duty cycles for each channel).
     
  13. wip

    wip Member

    Joined:
    Nov 20, 2013
    Messages:
    38
    Likes:
    2
    Location:
    Montreal, Canada
    Will need to test if 12 software PWM is doable (with enough precision) on AtmegaX with 20mhz & ISP. Someone on the #AVR channel suggested using binary pwm?!

    I feel ashamed by the above statement:
    Apollo 11 had a 2.048 MHz CPU...

    /me hiding
     
    Last edited: Mar 21, 2014
  14. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    That is doable.. it depends how much processor time you need to do some other "intelligent" stuff. I would do all 12 channels in software to simplify the design. That is a really efficient loop..

    Code (C):

    interrupt routine that is ececuted at constant intervall {
        counter++;
        (channel[0] > counter) ? (PIN0_HIGH) : (PIN0_LOW);
        (channel[1] > counter) ? (PIN1_HIGH) : (PIN1_LOW);
        (channel[2] > counter) ? (PIN2_HIGH) : (PIN2_LOW);
        (channel[3] > counter) ? (PIN3_HIGH) : (PIN3_LOW);
        (channel[4] > counter) ? (PIN4_HIGH) : (PIN4_LOW);
        (channel[5] > counter) ? (PIN5_HIGH) : (PIN5_LOW);
        (channel[6] > counter) ? (PIN6_HIGH) : (PIN6_LOW);
        (channel[7] > counter) ? (PIN7_HIGH) : (PIN7_LOW);
        (channel[8] > counter) ? (PIN8_HIGH) : (PIN8_LOW);
        (channel[9] > counter) ? (PIN9_HIGH) : (PIN9_LOW);
        (channel[10] > counter) ? (PIN10_HIGH) : (PIN10_LOW);
        (channel[11] > counter) ? (PIN11_HIGH) : (PIN11_LOW);
    }
     
    I think you can get good frequency out of that. Even higher pwm frequency if you put that in your main loop, but then it is difficult to keep freq constant.
     
    Last edited: Mar 21, 2014
  15. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    Actually I think I got confused there.. are you trying to generate sine frequencies between 200 and 400 Hz?
     
  16. wip

    wip Member

    Joined:
    Nov 20, 2013
    Messages:
    38
    Likes:
    2
    Location:
    Montreal, Canada
    Very nice of you, you even took the time to code for me, we need more of you and less of me :)

    I am trying to output squarewave from 207.652hz to 440hz - 12 notes at the same time
     
  17. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    Which one of these frequencies you do not need?
    .. actually, could you list the actual frequencies you need..

    207.65
    220.00
    233.08
    246.94
    261.63
    277.18
    293.66
    311.13
    329.63
    349.23
    369.99
    392.00
    415.30
    440.00

    I don't know anything about music.. My source for that list: http://www.phy.mtu.edu/~suits/notefreqs.html

    EDIT: Apparently you do not need the two upper frequencies, because they are the same note as the two lower ones. right?
     
    Last edited: Mar 21, 2014
  18. kubeek

    kubeek Well-Known Member

    Joined:
    Mar 11, 2006
    Messages:
    1,510
    Likes:
    189
    Location:
    Prague, Czechia (not Chechnya)
    I think you could use a single 16-bit counter, and set the top value to a new one each time the counter triggers. I.e. on each trigger you calculate how long you need to count till the next output changes state, and which of the outputs it should be. Not really sure right now on how to calculate it, but if you start with just two signals and draw it on a piece of paper I am sure you will get there. Something along the way of adding the periods of all the sines and finding the next change, and some counting in modulo I guess.
     
  19. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    Ok, I think this is the way to go if you want a software pwm (or square wave frequency generator).

    3-channel example:
    Code (C):

    /* set up counters */
    uint16_t f1_counter = 0;
    uint16_t f2_counter = 0;
    uint16_t f3_counter = 0;

    uint16_t f1_increment = calculate correct increment to get the frequency you want;
    uint16_t f2_increment = calculate correct increment to get the frequency you want;
    uint16_t f3_increment = calculate correct increment to get the frequency you want;

    interrupt routine that is executed at constant interval {
        (f1_counter & 0x8000) ? (PIN1_HIGH) : (PIN1_LOW);
        (f2_counter & 0x8000) ? (PIN2_HIGH) : (PIN2_LOW);
        (f3_counter & 0x8000) ? (PIN3_HIGH) : (PIN3_LOW);

        f1_counter += f1_increment;
        f2_counter += f2_increment;
        f3_counter += f3_increment;
    }
     
    The fx_counter variable is tested if the last bit is set or not and the output is set high or low accordingly. The frequency is controlled by the amount of the fx_increment and the loop (interrupt) frequency. You can play with the values. 8bit counters gives you more speed, but less resolution (accuracy) etc. Loop frequency sets the resolution.

    This scheme also lets you to go higher and higher.. I mean from 220 Hz to 440 Hz.
    Instead of testing the last bit (bit 15).. test the bit before that (bit 14) and you double the frequency. Is that the same as going one octave up? sorry I'm really bad in music theory.
    Anyway, if that is true, then you get that kind of control almost free.

    Actually you have nice control of the accuracy of the frequency if you play with the increment value and what bit you are testing. I can't do the math now.. too drunk.

    The math is:

    Not sure if this is correct:
    loopf / ((2^n)*increment)

    loopf: the loop frequency that you execute the thing.
    n: the bit you are testing if it is 1 or 0
    increment: the counter increment

    You want the loop frequency to be as fast as possible and then you have two variables to play with.
     
    Last edited: Mar 21, 2014
    • Thanks Thanks x 1
  20. wip

    wip Member

    Joined:
    Nov 20, 2013
    Messages:
    38
    Likes:
    2
    Location:
    Montreal, Canada
    Will test this very soon! I think I will end up with your solution, that is: 1 uc for USB - ADC - ... / 1 uc for software PWM (communication with ISP). That way, I will be able to run the timer at +-10us or lower and have good precision over the frequencies. Will report back!

    Cheers!
     
  21. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    I did some calculations and it looks like with the method I came up with it is really hard to get all 12 frequencies with decent accuracy. I thin you need to dedicate one or more microcontrollers just to generate the signals. You need really fast loop to get enough resolution.

    .. and there are problems with my code.. It does not work as I first thought. Sorry about that. I'll re-think that tomorrow.
     
    Last edited: Mar 21, 2014

Share This Page