PWM high pitch sound

I’m using a Baby O and Motordriver 18v15 to control speed and direction of a 6 V. Faulhaber motor.
It’s working, but after trying all different frequencies in Fast PWM and Phase Correct PWM I can’t get ridd of a high pitch sound. It’s worst at low rpm.
Here’s the code for the Phase corrrect PWM I’m using:

int main(void)
{
  unsigned char i=0;
  
  // Initial PORT Used
  DDRD = 0b11111111;     // Set PORTD: Output
  PORTD = 0x00;
  
  // Initial TIMER0 Phase Correct PWM
  // Phase Correct Frequency = fclk / (N * 510), Where N is the Prescaler
  // f_PWM = 20 000 000 / (8 * 510) = 4.9 kHz
  TCCR0A = 0b10100001; // Phase Correct PWM 8 Bit, Clear OCA0/OCB0 on Compare Match, Set on TOP
  TCCR0B = 0b00000010; // Used 8 Prescaler

For my application it’s crucial that I can minimize this sound.
Is there a solution to this problem, am I doing something wrong?

-Jos

Typically, you’ll want “fast PWM” rather than “phase correct PWM.”

The key to removing PWM sound is to run the PWM at a high enough frequency that you don’t hear it. Aim for 20 kHz.
This assumes that your motor controller can keep up at that speed. If not, chances are you’ll blow it out.
The specification for the 18v15 driver says:

How can I get this PWM of 20 kHz.?
I’ve tried to use prescaler 1, this gives a lower wine at low rpm but makes the motor act erratic at higher rpm’s.
I also tried to change the clock frequency, but this doesn’t seem to have any effect.
I’m a newbie on this, so you have to lead me every step of the way…

-Jos

Where did you get the code you are currently using? Do you understand it well enough to modify it?

One easy way to get to 20 kHz is to take the 5 kHz phase-correct PWM you have now and set the TOP to be 63 (a quarter of what it is now). Alternatively, you could use a fast PWM with a TOP value of 127 (keeping the timer 0 prescaler at 8).

- Ben

I got this code from http://www.ermicro.com/blog/?p=1971
It has a thorough explanation, so I understand how to modify it.

Faulhaber uses up to 70 kHz. to run its motors. So I think I have to use the maximum of 40 kHz. that my motor driver can handle.
How can I change this TOP value?

-Jos

That blog post you linked to has examples of how to set the TOP, but you might just want to look at the ATmega328p datasheet. I think you should be using timer 1 instead of timer 0, since the Baby Orangutan uses timer 0 for its own motor driver (are you using the Baby Orangutan motor driver outputs as inputs for your high power motor driver?). Also, I suggest you shoot for a PWM frequency of 20 kHz to minimize switching losses. 20 kHz will be just as quiet as 40 kHz. If there is something you don’t understand in the datasheet, please let me know.

- Ben

Happy newyear Ben!

Thank’s for your reply.
I’ve been looking both at the blog I send you and the datasheet. It’s hard to understand for me, but I’ve been trying the following code, where I changed from pin PD5 to PB1 and use different coding to set the registers:

int main (void) 
{
	unsigned char i=0;
	
	DDRB |= _BV(PB1);		//Set Pin PB1 as output
											//Fast PWM, 8-bit, Prescaling (N = 8)
	TCCR1A |= _BV(COM1A1) | _BV(WGM10);		// Fast PWM Frequency = fclk / (N * 127), Where N is the Prescaler
	TCCR1B |= _BV(CS11) | _BV(WGM12);		// f_PWM = 20 000 000 / (8 * 127) = 19,7 kHz	
	
	ICR1H = 0x7FFF;		//Set TOP to 127 (16 bit register)
	ICR1L = 0x7FFF;
	
	for(;;)
	{
		//Fade up
		for(i=0; i<127;i++){
			OCR1A = i;        //Set new duty cycle value
			delay(10);		//delay a litle bit
		}
		
		//Fade down
		for(i=127; i>0;i--)
		{
			OCR1A = i;        //Set new duty cycle value
			delay(10);		//delay a litle bit
		}
	}

	return 0;	        // Standard Return Code
}

I assume that if I lower the TOP to 127 that I have to lower “i” to 127 as well. This gives me only half the motor speed. It works well with “i” set to 255, so I’m not sure if the motor is running on 20 kHz.

-Jos

There are a few problems with what you’re doing. As a first step, let’s figure out what you want. It sounds like you want to use a non-inverted fast PWM on timer 1 with a configurable top. If you look in the ATmega328P datasheet on pages 132-138, you can figure out what register values give you these settings:

non-inverted fast PWM on PB1 (OC1A): COM1A1 = 1, COM1A0 = 0
fast PWM with configurable top (ICR1): WGM13 = 1, WGM12 = 1, WGM11 = 1, WGM10 = 0

The frequency of a fast PWM is given by f = F_CPU/prescaler/(TOP + 1)

If we know we want a frequency of 20 kHz and F_CPU is 20 MHz, we get that:

TOP = 1000/prescaler - 1

Timer 1 is a 16-bit register, which means that 999 is an acceptable value and we can use a prescaler of 1 (the timer ticks at the full rate of 20 MHz). If we were using an 8-bit timer, we would pick a prescaler to get the biggest TOP value under 256.

prescaler of 1: CS12 = 0, CS11 = 0, CS10 = 1

So this means we want to set:

TCCR1A = _BV(COM1A1) | _BV(WGM11); // equivalent to 10000010, or 0x82
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // equivalent to 00011001, or 0x19
ICR1 = 999; // set TOP to 999 for a 20 kHz PWM

To control the duty cycle, you would set OCR1A. If you make OCR1A = 500, you will get a 50% duty cycle. This means that your ramp-up and ramp-down code will need to change to loop from 0 to 999 instead of 127, and you will probably want to decrease the length of your delay so that it still takes the same amount of time.

- Ben

Thank’s Ben, that works beautifull!!
No high pitch sound, and perfect speed control…

- Jos

If you have a dog, he/she might not agree :slight_smile:

I’m always a bit nervous about posting untested code; I’m glad to hear that it worked as expected! Thanks for letting me know.

- Ben

Hah!