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

Thread Starter

kris_maher

Joined Apr 24, 2009
90
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:

Rich (BB code):
int PING()
{
// Use this FORMULA for TOP:
/* TOP/ICR1 = Clock_Speed / (2 * Prescaler *
Output_PWM_Frequency) */

// Thus ICR1 = 8000000 / (2 * 1 * 40000) = 100

// Make PD5 as output pin
DDRD = 0b00100000;
PORTD = 0b00100000;

// Turn off PWM while we set it up
TCCR1B |= 0;
TCCR1A |= 0;

// Setup the timer --> 16-bit Phase/Frequency Correct PWM mode with Pre-scaler = 1
TCCR1B |= (1 << WGM13);
TCCR1B |= (1 << CS10); 

// Setup the Compare Output to be set to toggle mode. See pg.108 in datasheet
TCCR1A |= (1 << COM1A0);

// Set ICR1 so the output toggles at 40KHz
ICR1 = 100;

// Set the Comparator so we're at 50% duty cycle
OCR1A = ICR1 / 2;

}
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:
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.
 

hgmjr

Joined Jan 28, 2005
9,027
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:

eblc1388

Joined Nov 28, 2008
1,542
When I use my PC Oscilloscope to observe for any waveforms coming out of the Ultrasonic transducer, nothing comes up on the screen.
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.

 

Attachments

Thread Starter

kris_maher

Joined Apr 24, 2009
90
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.
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:


Any ideas?

BTW thanks everyone for the suggestions and the advice..

PS: I'm now using fresh 9V batteries.
 
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.
 

eblc1388

Joined Nov 28, 2008
1,542
OCR1A is now on:
// Set the Comparator so we're at 50% duty cycle
OCR1A = 100/50;
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.
 

Thread Starter

kris_maher

Joined Apr 24, 2009
90
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.

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 */
 

eblc1388

Joined Nov 28, 2008
1,542
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.

Rich (BB code):
// Setup the Compare Output to be set to PWM mode
// If value OCR1A = TOP/2 then PWM output will be 50% square wave

TCCR1A |= (1 << COM1A1);  // or set both COM1A0 and COM1A1 to high
                          // if an inverted output is desired  

// Set ICR1 so the output toggles at 40KHz
ICR1 = 100;

// Set the Comparator so we're at 50% duty cycle

OCR1A = ICR1 / 2;

// Setting OCR1B & COM1Bx will enable user to generate a same frequency  
// but different duty cycle waveform at OC1B too
In short, there are different ways to get the same result.
 
Last edited:
Top