My PWM code to generate 40KHz seems to have a problem? im using ATmega32

Discussion in 'The Projects Forum' started by kris_maher, Apr 27, 2009.

  1. kris_maher

    Thread Starter Active Member

    Apr 24, 2009
    90
    0
    Hi,

    I wrote code to use ATmega32's "Phase and Frequency Correct" PWM mode. The clock speed is set to 8MHz and I wrote the code so that it generates a 40KHz square wave on the PD5 output pin. This is basically for a Ultrasonic project I'm working on.

    Here's my code:

    Code ( (Unknown Language)):
    1. int PING()
    2. {
    3. // Use this FORMULA for TOP:
    4. /* TOP/ICR1 = Clock_Speed / (2 * Prescaler *
    5. Output_PWM_Frequency) */
    6.  
    7. // Thus ICR1 = 8000000 / (2 * 1 * 40000) = 100
    8.  
    9. // Make PD5 as output pin
    10. DDRD = 0b00100000;
    11. PORTD = 0b00100000;
    12.  
    13. // Turn off PWM while we set it up
    14. TCCR1B |= 0;
    15. TCCR1A |= 0;
    16.  
    17. // Setup the timer --> 16-bit Phase/Frequency Correct PWM mode with Pre-scaler = 1
    18. TCCR1B |= (1 << WGM13);
    19. TCCR1B |= (1 << CS10);
    20.  
    21. // Setup the Compare Output to be set to toggle mode. See pg.108 in datasheet
    22. TCCR1A |= (1 << COM1A0);
    23.  
    24. // Set ICR1 so the output toggles at 40KHz
    25. ICR1 = 100;
    26.  
    27. // Set the Comparator so we're at 50% duty cycle
    28. OCR1A = ICR1 / 2;
    29.  
    30. }
    When I use my PC Oscilloscope to observe for any waveforms coming out of the Ultrasonic transducer, nothing comes up on the screen.

    Now it could be due to:
    a) Something wrong with my code. Any ideas?:confused:

    OR

    b) A battery that's almost out of steam. :mad:I have a regulator circuit that steps down voltage to 5V, for this, I have a 9V rated battery that measures just over 6V with a multimeter.

    Thanks everyone..
     
    Last edited: Apr 27, 2009
  2. StayatHomeElectronics

    Well-Known Member

    Sep 25, 2008
    864
    40
    Is there any chance you can eliminate b) as a possibility by getting a new battery? Is the voltage on the stepped down side of the regulator still at 5 volts?

    Regulators like 7805s need at over 7 volts to maintain a good 5 volt output.
     
  3. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Since you are assigning a value to ICR1, can I assume you are using the "input capture" mode on TIMER1 as well at the "output compare" mode?

    Also since you have placed the initialization code in your function PING() can I assume you only call this function once?
    Also the function is set to return a value of type integer. I don't see any return(?) statement in the function so I wonder if you would be better off making the function "void" so that no return value is expected.

    Perhaps you can give some additional details regarding the basic operation of your design.

    hgmjr
     
    Last edited: Apr 27, 2009
  4. eblc1388

    Senior Member

    Nov 28, 2008
    1,542
    102
    This is why.

    You have selected mode=8 by setting WGM13=1 and set output to toggle via COM1A0=1.

    However, according to the datasheet, this output pin toggle mode is only available when mode=9 or 14 whereas other modes would result in normal port operation.

    Have you tried mode=9 instead with the top value placed into OCR1A instead of ICR1?

    If you just simply want to generate a 40KHz square ware, then may be you should also consider using the CTC mode instead which toggle the output at 80KHz giving you a perfect 50% duty cycle 40KHz square wave.

    [​IMG]
     
  5. kris_maher

    Thread Starter Active Member

    Apr 24, 2009
    90
    0
    Hi,

    I've included the change, it's now on Mode 9. And i've added the return 0() at the end (I can't believe I forgot that...)

    OCR1A is now on:
    // Set the Comparator so we're at 50% duty cycle
    OCR1A = 100/50;

    And using Mode 9:
    // Setup the timer --> 16-bit Phase/Frequency Correct PWM mode with Pre-scaler = 1 (Using Mode 9)
    TCCR1B |= (1 << WGM13);
    TCCR1A |= (1 << WGM10);
    TCCR1B |= (1 << CS10);
    --------------------------------------------
    And it kind of works. However it doesn't appear to be a square wave and it doesn't appear to be oscillating at 80,000Hz at all (to make it 40KHz via %50 duty cycle).

    here's the screen shot from the pc oscilloscope:
    [​IMG]

    Any ideas?

    BTW thanks everyone for the suggestions and the advice..

    PS: I'm now using fresh 9V batteries.
     
  6. StayatHomeElectronics

    Well-Known Member

    Sep 25, 2008
    864
    40
    The output looks more like noise than anything else. Given that you want a output frequency of 40 kHz, period of 1/40000 is 0.025 ms, you may wish to reduce the ms/div to the lowest setting.

    Do you know what the bandwidth is of the pc oscilloscope? Remember you need at least twice the bandwidth of the signal you are trying to measure, and that doesn't give a very nice visual representation. It is always nice to have five or ten times the bandwidth on the oscope especially when you are trying to see square waves.
     
  7. eblc1388

    Senior Member

    Nov 28, 2008
    1,542
    102
    Setting OCR1A to 2 ??? :confused:

    OCR1A = Fclk/(Ftoggle*2*prescaler)
    = 8MHz/(80KHz*2*1)
    =50

    You'll need the OC1A pin to toggle at 80KHz to get a 40KHz 50% duty cycle square wave output.

    The value of 2 in your case is too low.
     
  8. kris_maher

    Thread Starter Active Member

    Apr 24, 2009
    90
    0
    [​IMG]
    It's 96KHz. It can also output at 96KHz sampling frequency.

    Oh btw it is on 'OCR1A = 100/2'. That 50 was a typo when I was copying the code from my laptop to my desktop machine that has net access.

    Would Fast PWM have much difference? And does the code seem correct to you guys? Since I've been playing around with PWM/Timers and timers seem much easier to work with than PWM's more advanced settings...

    Also btw if I switchover to 'timer with CTC' that's now with formula:
    Target Timer Count = (Input Frequency / Prescale) / Target Frequency

    And since I'll still use the 16-bit timer 1, it will still be:
    = (8000000/1) / 80000 = 100
    So in code, nothing has changed much in terms of the formula:
    OCR1A = 100/2 /* %50 duty cycle */
     
  9. eblc1388

    Senior Member

    Nov 28, 2008
    1,542
    102
    OK.

    Please check your AVR output again with a real instrument like CRO or frequency counter and report back the result.

    The output could be already at 40KHz right now, one never knows unless a proper instrument indicates otherwise.

    Incidentally, you can also use mode=8 with TOP value in ICR1 but you will need to setup the output correctly by setting COM1A1 to HIGH or both COM1A0 and COM1A1 to high instead of just COM1A0 to high.

    Code ( (Unknown Language)):
    1.  
    2. // Setup the Compare Output to be set to PWM mode
    3. // If value OCR1A = TOP/2 then PWM output will be 50% square wave
    4.  
    5. TCCR1A |= (1 << [COLOR=Red][B]COM1A1[/B][/COLOR]);  // or set both COM1A0 and COM1A1 to high
    6.                           // if an inverted output is desired  
    7.  
    8. // Set ICR1 so the output toggles at 40KHz
    9. ICR1 = 100;
    10.  
    11. // Set the Comparator so we're at 50% duty cycle
    12.  
    13. OCR1A = ICR1 / 2;
    14.  
    15. // Setting OCR1B & COM1Bx will enable user to generate a same frequency  
    16. // but different duty cycle waveform at OC1B too
    17.  
    18.  
    In short, there are different ways to get the same result.
     
    Last edited: Apr 28, 2009
Loading...