PWM 40KHz pulse doesn't seem to work right. included pic

Go To Last Post
21 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I've used PWM to generate 40KHz, at the output pin for it to oscillate at 80,000 times per second with a %50 duty cycle to make it 40KHz. This is being sent to a Ultrasonic Transducer.

The ATmega32 chip is running at 8MHz.

The confusion is that:
a) The square wave doesn't seem to be created properly
b) The 80,000 oscillations for the 40KHz pulse doesn't appear to be generated.

I've included my code:

int PING()
{

/* Should I add some sort of a delay here to have the function wait a certain 
amount of time before transmitting again on an interval basis!? */

// 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 (Using Mode 9)
TCCR1B |= (1 << WGM13);
TCCR1A |= (1 << WGM10);
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 = 100/50;

return 0;

}

My fall back plan appears to be just to use the timer in CTC mode but I wish to try and get it working under PWM.

Well I was hoping if someone could shed some light on this if its not too much trouble.

Thanks again..

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try reducing frequency to 4 kHz first. Audio cards are not supposed to sample 80 (and even 40) kHz signal.

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The program and my sound system supports up to 96KHz input/output sampling.

TrueRTA program calibrated itself to use my sound system's settings at input/output at 48KHz. It detected
so it can support 40KHz.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

The program and my sound system supports up to 96KHz input/output sampling.

As you say, Nyquist would tell you that at 96kHz samples you could resolve a 48kHz signal - in theory. But only if it were a perfect square wave. If the wave has some "shape" then you need to sample it FAR faster than 2 * frequency to get a proper picture of the wave shape. For scopes you'd usually figure on needing at least 10 times sampling. So for a 40kHz signal you really need to be sampling at 400kHz and no audio card is ever going to do that.

So the advice to reduce the 40kHz above is very wise. Maybe go up one step of pre-scaler for an effective divide by 8 (to 5kHz). If everything works at that speed and all you then change is the pre-scaler to do a *8 there's a pretty strong hope it will be working at 40kHz too even if your PC scope cannot resolve it.

Soundcard scopes are all very well for checking out things like UART up to 9600baud or SPI going very slowly but that's about it

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay I'll try it at 4KHz.

Or should I just opt for a simple 8-bit timer 2 with CTC? In any case the value of OCR1A will still be calculated to 100. Which is well under the 255 or even the 65536 limit for 16-bit timer 1.

Also does the code at least look correct for a 8MHz processor to generate 40KHz (via %50 duty cycle) off PD5??

Just so I know that my past 2hrs or so fiddling around wasn't for nothing after all...

I don't see how I could do a prescaler divide of 8 if OCR1A calculates in the end to 100. Or perhaps I did something wrong here?

Last Edited: Tue. Apr 28, 2009 - 02:46 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just some notes:

TCCRN |= 0 does >>Nothing<< Try TCCRN = 0
Had you checked your fuses settings? If not properly setted, you will have 1MHz as main clock frequency.
I will begin also with 4KHz instead of 40KHz, just to see a clear waveform on your 'scope.

Guillem.
"Common sense is the least common of the senses" Anonymous.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My clock fuses are at 8Mhz. I fixed that problem last week after some searching on these forums :)

Okay so if I now do 4KHz as a test...then OCR1A should become if my thinking is right hopefully::

= (8000000/1) / 4000 = 2000

And 2000 is well under the 2^16 limit for 16-bit timer 1.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

My fall back plan appears to be just to use the timer in CTC mode but I wish to try and get it working under PWM.

For a simple square wave, whoy >>wouldn't<< you want to use the simpler CTC?
Quote:

// Setup the timer --> 16-bit Phase/Frequency Correct PWM mode with Pre-scaler = 1 (Using Mode 9)

Why not use a much simpler PWM mode?

Quote:

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

You mean 100/2 no doubt.

Quote:

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

No, you want inverted or non-inverted PWM.

I've never [needed to] used the phase-correct modes and the up-down counting, but I think you are correct that you still want the OCR to be 1/2 of ICR to get 50% duty. In CTC mode, you need to subtract 1 'cause 0 and TOP are counted. You'll need to double-check the counting sequence to see if you need to do that in that mode.

CodeVision Wizard might generate:

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 8000.000 kHz
// Mode: Ph. & fr. cor. PWM top=ICR1
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x80;
TCCR1B=0x11;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x64;
OCR1AH=0x00;
OCR1AL=0x32;
OCR1BH=0x00;
OCR1BL=0x00;

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay here's the CTC code I wrote (help from tutes)...anyways:

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

	TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC. Page.114 datasheet

	TCCR1B |= (1 << CS10);  // Start timer at prescaler = 1
	OCR1A = 2000/2; // Set CTC. 50% duty cycle with prescaler of 1

	for (;;)
	{
	  /* The CTC flag is located in the interrupt flag register, TIFR.
	  Check if CTC flag is set due to overflow. Checking for an CTC event
	  involves the OCF1A flag found in TIFR. */
	  if(TIFR & (1 << OCF1A))
	  	{
	   		PORTD ^= 0b00100000; // Toggle 
			
      // Clear CTC flag. Writing a logic one clears the CTC overflow flag
	        TIFR = (1 << OCF1A);
	    }


	}

I've included the 4KHz waveform, does it look correct to you?

This is the sharpest I can get it I guess...it's not perfect square wave but what do you guys think??

PS: I got the 2000 for the OCR1A from:
OCR1A = (8000000/1) / 4000 = 2000

Attachment(s): 

Last Edited: Tue. Apr 28, 2009 - 05:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I simply changed the line in the Timer CTC code:
OCR1A = 2000/2; // Set CTC. 2KHz at 50% duty cycle

To:
OCR1A = 100/2; // Set CTC. 40KHz at 50% duty cycle.

I'll try to have a look on a "real" oscilloscope tomorrow since yes its true, my PC Oscilloscope is showing nothing but junk at this high frequency (80KHz down to 40KHz with 50% Duty Cycle).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks good to me. At 0.2ms/div a wave at 4kHz (0.25ms) should last about 1 and 1/4 divisions which looks pretty close to me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, you >>could<< do that. But why bother? -- let the AVR do it for you with no CPU cycles.

However, if you are doing ultrasonic then you want to count a certain number of pulses for a burst. It will be marginally more efficient to poll it as you are doing, but I always did it in an ISR--40kHz is pretty slow in AVR-speak and there is probably not much else going on anyway.

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 8000.000 kHz
// Mode: CTC top=ICR1
// OC1A output: Toggle
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x40;
TCCR1B=0x19;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x31;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Well, you >>could<< do that. But why bother? -- let the AVR do it for you with no CPU cycles.

However, if you are doing ultrasonic then you want to count a certain number of pulses for a burst. It will be marginally more efficient to poll it as you are doing,


You mean a certain amount of delay between each 'square wave burst'?

And what do you mean by no CPU cycles?

thanks. BTW I must admit doing it at 4KHz first was a very good idea to figure out if the code works or not.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I must admit doing it at 4KHz first was a very good idea to figure out if the code works or not.

The ultimate version of that (assuming you hadn't even had the sound scope) would have been to do it at 4Hz and pump it out on an LED (that's just about slow enough to be countable!)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

But only if it were a perfect square wave.

It is true but only for perfect SINE wave.

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

And what do you mean by no CPU cycles?

The CTC mode (and PWM modes too) once started as with the code fragments that you and I have posted generate the output waveforms forever, toggling the output pin(s) per spec, with no jitter, and with no further CPU cycles or other intervention.

Your method uses software output toggling, and consumes 100% of the AVR cycles doing it. And there will be a bit of jitter.

For "burst", I don't think you every want to do the 40kHz forever, do you? The ones I've done you do like 10 cycles, stop the output burst, wait the blanking time, then look for the echo.

You can use a secondary timer set to "alarm" after the time of the 10-cycle burst and turn it off. Or you can do as I do and arm the overflow (or compare match) interrupt, count each pulse, and "turn myself off" when the desired number has been reached.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I recommend you to use an 8 bit timer for the burst generator, using the ISR to count halfwaves, and a 16 bit timer to measure your time of flight. Usually ATmega's have some kind of syncronization mechanism to start both timers at once.

My timer0 init routine (for a M64) was:

void timer0init(void)
{
TCCR0 = 0x00;
ASSR = 0x00;
TCNT0 = 0x64;
OCR0 = Freq; //Freq was a #define'd variable at value 100 for an external 8MHz xtal
//TCCR0 = 0x19; //start value
}

and the ISR was:

#pragma interrupt_handler timer0comp:16
void timer0comp(void)
{
HalfWaves--; //here we decrement the half wave counter
OCR0=Freq;
if (!HalfWaves)
TCCR0=0x00;//end reached
}

When you want a pulse, then you update HalfWaves to the desired value (let's say 20), and start the timer. The rest is done by the ISR itself.

I strongly suggest you to use an xtal or ceramic resonator if you want some accuracy, plus a temperature measurement for sound speed correction.

Guillem.
"Common sense is the least common of the senses" Anonymous.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks everyone...

I plan on testing my code at uni tomorrow on a real oscilloscope and then that output should allow me to figure out how much gain I want and the circuit for that and as well as how the received signal (picked up from the receiver transducer) looks like on the CRO.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be warned that receiver amplitude is not the same if you look for an echo than for direct transmission. The former changes with distance at fourth power (plus a 'return factor' depending upon your 'target'), while the later only squared.

Guillem.
"Common sense is the least common of the senses" Anonymous.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I'm at uni using the oscilloscope and 'multi-counter.'

Also I'm still using the same Timer with CTC code as above, however OCR1A is:

OCR1A = 100 /2;

This for my 8MHz chip, for 40KHz output, I calculated this from:
= (8000000/1) / 80000 = 100

Now when I have the '/2' for the 50% duty cycle to get it to 40KHz (from original 80KHz) I get this square wave on the oscilloscope (also on attachment):

This square wave is the exact wave that is being sent to the transducer (i placed probes).

However a problem! When I use the 'Multi-Counter' to actually measure the frequency that is entering the transmitter transducer it says it's 80Khz instead of the 40Khz which I want.

In return, if I connect the receiver transducer (they're a pair) to the oscilloscope right in front of the transmitter I see a lot of fast-moving junk and understandability so since the receiver's sensitivity is best when at 40Khz then it just drops.

The only way to send 40KHz pulse to the transmitter transducer is making:
OCR1A = 100;

That is, without the '/2;' at the end. The multi-counter detects the frequency coming into the transducer as 40KHz. However the oscilloscope not surprisingly shows this as a 'sine wave' and not a 'square wave' as it was before.

Any ideas guys on keeping it at 40Khz but also having a square wave? I'm stumped on this.

Please help, Thanks

EDIT: When you look at the screenshot I posted from the oscilloscope, each division is at 5micro seconds, thus:

F = 1 / T = (1 / 12.5micro-seconds) = 80KHz

The 12.5micro-seconds is the period of the square wave.

However I need a period of 25micro-seconds for it to be at 40KHz.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

nvm it works just fine now.

I found that the furthest 'deal' detectable range as 16cm.

Now I have to determine the appropriate gain for about 2-3 metres.

Attachment(s):