How to change the PWM frequency on ATmega 328p to 16Khz.

I am wondering if someone would be so kind as to gently guide me through changing the PWM frequency of the ATmega328p to 16Khz or some value very close to that.

Yes I have searched, yes I have found tons of information, but I understand very little to none of it. I have basically a nonexistent computer programming background.

I have at my disposal an Arduino UNO r2, and a breadboarded ATmega 328p connected to a pc with a FTDI usb adapter( that seems to be working ) if this helps.

And because I want to experiment with motor control, and would like to eliminate audible noise.

Cheers!

you will need to use timer registers directly and not use analogWrite. use the code from this post http://forum.arduino.cc/index.php?topic=196815.msg1454187#msg1454187 set ICR1=500 to get a period of 62.5us (16khz) set OCR1A to any value from 0 to 500 (you got a 500 resolution pwm).

the code is for mega, I think it should work on 328, but check if pwm pin for timer 1 is same PB5 for 328.

Hi, Thanks for your time. So I cut and paste the code that you linked into a new sketch, but change the line "ICR1=4000;" to "ICR1=500;"? And then the value that follows "OCR1A=" will determine the duty cycle, and can be a range of 0 to 500? But then, how do I implement this? I mean, if I do not use analog.Write, then how do I drive....say pin 9 on an UNO at 50% duty cycle?

To get the most out of this, you must read the atmega328 datasheet timer chapter.

The code I gave is for mega, and is not intended for you to cut and paste. you need to read up so you can figure out how to modify it to suit your requirements.

for the frequency you need, you can only use timer1 (16 bit). Hence only pins PB1 and PB2 (digital pin 9 and 10) can be used on the atmega328.

you will need to change PB5 in the code to PB1 in the code and use digital pin 9 for the output.

pin11 is connected to timer2 which is an 8 bit timer.

once you setup the registers, all you need to do to change the duty cycle is assign a value between 0 and 500 to OCR1A. OCR1A=250 will give you 50% duty cycle PWM @16khz on digital pin 9

BTW, since the code altered the clock divider for timer1, you cannot use analogWrite on pin10 anymore. You can however setup timer1 register B to do PWM similar to what was done to register A in my code example.

Hi, thanks for the info. It is honestly more than I can comprehend. For me to try and understand any part of the datasheet, would be equivalent to opening a book written in a foreign language and expect to be able to read it. I say this because I have looked at it before. I am not afraid or unwilling to learn something, quite the contrary. I am just realistic about my background level regarding these things. I cannot ask the datasheet to explain itself!

So any chance this can be "dumbed" down even more, I know it is asking a lot? Otherwise, I do indeed appreciate your efforts nonetheless!

cheers,

Assuming you don't care about the specific frequency, but just want it out of the audible range, you can easily get 31 kHz PWM on pin 9 and 10 (controlled by Timer1) and / or 11 and 3 (controlled by Timer2).

void setup() {
  // Set PWM frequency to 31 kHz for pin 9 and 10
  TCCR1B = TCCR1B & 0b11111000 | 1;
}

void loop() {
  analogWrite(10, somevalue);
}

See the PWM cheat sheet page for other settings: http://playground.arduino.cc/Main/TimerPWMCheatsheet

Thanks, So would I be able to cut and paste your code? And would somevalue also be 0 to 255?

But I would prefer to keep closer to 16khz as I think MOSFET switching losses go up with higher frequency.

Is there any reason that this has not been suggested: http://forum.arduino.cc/index.php?PHPSESSID=bhgtskrvmre11qbvslrhfdqql1&topic=117425.0

.......seems like exactly what I am wanting, unless I am missing something.

cheers,

billcat: Hi, thanks for the info. It is honestly more than I can comprehend. For me to try and understand any part of the datasheet, would be equivalent to opening a book written in a foreign language and expect to be able to read it. I say this because I have looked at it before. I am not afraid or unwilling to learn something, quite the contrary. I am just realistic about my background level regarding these things. I cannot ask the datasheet to explain itself!

So any chance this can be "dumbed" down even more, I know it is asking a lot? Otherwise, I do indeed appreciate your efforts nonetheless!

cheers,

don't sell yourself short, it's really easier than it looks. I started in the same situation you are.

just think of it this way.

you start with a 16mhz clock.

you have a timer (8 or 16 bit). which will increment once per clock cycle.

so say you want 16000 hz, that is 1/16= 0.0625ms or 62.5us.

one cycle of the pwm is when counter starts from 0, counts to top (255 for 8 bit, 65536 for 16 bit, or can be user specified), then back down to 0.

so you need to divide 62.5us by either 512 (256*2 due to upcount then downcount), 65536*2, or a custom value.

62.5/512=0.122us. per timer increment using 8 bit.

now the arduino clock of 16mhz can be divided by 1,8,64,256,1024. if we use divided by 1, 1/16 = 0.0625us, which is too fast to get 16khz if divided by 8. 16mhz/8=2mhz, 1/2 = 0.5us per timer increment. we cannot get the exact 16khz freq using the standard 8bit or 16bit top, so we must use a custom counter top (top is the number where the timer switch direction and counts downwards)

lets use the divided by 1 value of 0.0625us per count. so we divide 62.5/0.0625 =1000 this means if timer increments once every 0.0625us, after 1000 increments/decrements, 62.5us has elapsed, exactly the time period for 16khz! Since we need 1000 count, 8 bit timers are out.

since the counter counts up then down, divided 1000 by2 to get the 500 for TOP.

Now you got all the values, just figure where in the timer registers to set these. TCCR1A, TCCR1B for setting the clock divider, wave generation mode ICR1 for the TOP OCR1A for the duty cycle.

wave generation mode 10 is whats needed here. it clears the pin low on match to OCR1A value on counting up, and sets the pin high on OCR1A match on the way down.

say you set OCR1A to 125. counter start from 0, count to 500, back down to 0. lets start from the top, from 500, the pin is low. when it decrements down to 125, it will set the pin high, once it hits 0, it start incrementing, and when it reaches 125, it set the pin low.

so the pin is high from 125 to 0 to 125 for a total of 250 clock cycles out of 1000 or exactly 25% duty cycle.

all these info can be found in atmega328 datasheet chapter 15. study section 15.11 carefully for the register description. and you can see in my code how I arrived at the values to set the registers to.

you can use that pwm library, but it won't hurt to understand how this works.

doughboy: ....... won't hurt to understand how this works.

Are you sure? My head is aching something fierce. :D But seriously, I agree , that's why I am here. Understanding Arduino is a goal I have had for a good while.

Thanks so much for the in depth explanation. I tried to follow as best I could but may take a little time to absorb. And I will try again to get something from the datasheet. I follow your math decently, but hit a wall when terms like timer, register,TCCR1, OCR1,ICR1, hex, etc. come up. These are not things I understand the meaning of yet.

cheers!

Sorry for intruding, but I have a similar problem. I need 21 kHz on 8-bit timer (ATTiny doesnt have 16-bit timer) to drive a motor. Now I don't know how much precision I will lose as I don't know how to calculate that (I might even not notice the loss of precision in my application, which is swinging bells with smooth pulls, where pwm duty cycle means how high they will swing) - very important, but doesn't need to be 100% accurate). I just want to verify if my calculation is correct before I go buying ATTinys:

I set ATTiny clock to 16 Mhz (or might 8 Mhz be better for this?)

1/21kHz = 0.04762ms = 47.62us 47.62us/512 = 0.093us per timer step

div 1: 47.62/0.0625 = 761.92 761.92/2 = 380.96

div 8: 47.62/0.5 = 95.24 95.24/2 = 47.62

Probably too much precision is lost if div is 8, right? And div 1 is too much for 8-bit timer :(

If I use 8 MHz clock on the other hand....

div 1: 47.62/0.125 = 380.96 380.96/2 = 190,48

Sounds genuine?

I would also require locked antiphase, but its probably not possible while using custom frequency, if I read the guide to Arduino PWM right.