Hello.
I am making this guide because i haven't found an answer in one simple post on how to change PWM frequency to 20khz on an arduino/stm32 microcontrollers (MCUs) using arduino IDE.
I'm going to make it as short and as simple as possible to avoid confusion.
QUICK SUMMARY: If your h-bridge doesn't support more than 20-25khz pwm frequency, you should be using an STM32 (known as bluepill) instead of an arduino. It is the same price as an arduino nano but is faster. I haven't found a way to set 20khz frequency directly, so I will show you an example using STM32.
How pwm generation works:
You need to know the MCU base clock ant the timer resolution. The timer is responsible for pwm generation. Lets look at an arduino nano pinout board and locate the timers.
Arduino nano has three timers. PWM pins are 3, 11, 5, 6, 9, 10 (the purple ones with a sine wave going to them). Timer0(OC0A,OC0B) covers pins 5,6. Timer1(OC1A,OC1B) covers pins 9,10. Timer2(OC2A,OC2B) covers pins 3,11.
Important: Timer0 is responsible for general program runtime, so I advise not to change the frequency of these pins.
How to quickly change the pwm frequency:
(just copy the wanted frequency change line into void setup)
As far as I know, only these frequencies are available on Arduino and direct 20kHz frequency generation is not available.
Now i suspect for most of you this isn't enough, so lets see at an example using STM32.
I'm using STM32F103C6
You will need to download the board library (http://dan.drown.org/stm32duino/package_STM32duino_index.json)
Also you will need an ST-Link programmer. (they are cheap, just buy one, it will save you loads of time)
Don't forget to download ST-Link drivers. (create a temp email account and download from the official website)
First off, STM32 has 4 timers, each with 4 channels and 16 bit resolution. That means 65535 values. This value is important to us, as the resolution decides how accurately the pwm duty cycle can be generated.
Next, STM32 runs at speeds of 72MHz. That means that we will get 72,000,000/65535 = 1.098 kHz on our PWM pins. This is not enough for us.
We will have to sacrifice a bit of resolution to increase the frequency to 20 kHz. Here's how we can do that:
HardwareTimer pwmtimer4(4);
void setup(){
pwmtimer4.pause();
pwmtimer4.setOverflow(3600);
pwmtimer4.refresh();
pwmtimer4.resume();
}
First we pause the timer.
Then set the overflow value to 3600 instead of 65535.
Refresh the timer.
Resume the timer.
Can you guess why we changed the value to 3600? Lets see how we calculated this value.
We need a pwm frequency of 20 kHz. If we divide the controllers base frequency by the wanted pwm frequency, we will get the overflow value. (72,000,000/20,000=3600).
NOW THE MOST IMPORTANT PART
Since we changed the overflow value, the resolution has changed too. For example, arduino has an 8 bit timer, so the maximum pwm value is 255. Stm32's 16 bit timer has maximum pwm value of 65535. After changing the overflow value, our new maximum pwm value is 3600.
In the code you should be using pwmWrite(pin,value) function instead of analogWrite(). The output pins should be declared as PWM (pinMode(pin, PWM))
We have to scale the current pwm value accordingly.
Let's take my situation: I'm using 8 bit values for my simulator, so I have to scale the pwm values by 3600/255=14.12. So just multiply your generated pwm value by this number.
If you have any questions or hae something to add, feel free to leave a message.
I learned all of this while making a simulator, which can be found here: Showroom - Sharo garazhas - DIY Joyrider with e-bike motors + traction loss