Increase PWM Frequency

I am doing a project, with an Infineon brand Shield to control a BLCD motor.

I have been doing tests, with an arduino UNO R3 and an arduino R4 Miminna

On the arduino R3, increase the frequency to 32kHz, it works well but since the PWM only regulates from 0 to 255, I jump

On the Arduino I can better regulate the use of that PWM (it is regulated in percent, but with decimals), but I need to raise the frequency above 460HZ. (the engine whistles)

I can't find information on what the maximum frequency would be.

I have found information, and I have studied the PWM.h library

#include "pwm.h"
PwmOut pwm11(D11);
PwmOut pwm10(D10);
PwmOut pwm9(D9);

  pwm9.begin(20000.0f, 0.0f);
  pwm10.begin(20000.0f, 0.0f);
  pwm11.begin(20000.0f, 0.0f);

   pwm9.pulse_perc(0);
   pwm10.pulse_perc(0);
   pwm11.pulse_perc(0);

I use the PWM outputs with:
pwm11.pulse_perc(curren22);

The engine response is the same. If the frequency has changed, it is not appreciated

In the PWM.h library, it gives 2 options:

 `bool begin(float freq_hz, float duty_perc);`

bool begin(uint32_t period_usec, uint32_t pulse_usec, bool raw = false, timer_source_div_t sd = TIMER_SOURCE_DIV_1);

 /* with raw = false then period and pulse are supposed to be in micro second
    with raw = true then period_usec and pulse_usec will be user as raw value to be used directly in micro registers
    Pay attention that in case of raw use the possible divider are
    TIMER_SOURCE_DIV_1
    TIMER_SOURCE_DIV_4
    TIMER_SOURCE_DIV_16
    TIMER_SOURCE_DIV_64
    TIMER_SOURCE_DIV_256
    TIMER_SOURCE_DIV_1024 */

I have tried the second option......but with the same results

How can I increase the frequency on an arduino R4? Up to what frequency?

Thank you very much to all

All the best

Using Arduino UNOR3 and its TC1, you can achieve frequency from 0.23 Hz to 16 MHz.

I am not sure if this thread will help or not:
How can I increase the PWM frequency i.e. at PIN 6? - UNO R4 / UNO R4 WiFi - Arduino Forum

Thank you so much.
I try to use a more powerful Arduino (if I can).
I don't want to throw in the towel so quickly.

You probably already figured this out, but Arduino UNO R4 has the api:
analogWriteResolution, which allows you to set up to 12 bits. So you can have more than 256 steps:
Arduino UNO R4 WiFi Cheat Sheet | Arduino Documentation

How high of a frequency are you needing?

Thank you so much.

Your contribution, along with a page that mentions Wawa in that post, is the only information I have found on the internet on this topic.

I studied your code, but it left me baffled:

First you define the Pwm, as the PWM.h library says at 1026Hz and you set the Pwm to 50%

Then you define
pinMode(LED_BUILTIN, OUTPUT);

I don't know where that "LED_BUILTIN" comes from.

Then you use the PWM with analogWrite(), what little I have read, and if I have understood correctly, when you define with PWM.h, pulse_perc() should be used.

I admit that I have not tried it. (It only goes up to 1kHz, to eliminate the engine whistling it is usually not enough)

Let's see if anyone has tinkered more with the PWM.h library and managed to make it work better than it did for me.

Anyway, thank you very much for your help.

You are welcome,

Note: I have not done anything with my UNO R4 boards in a while now... I am back to my normal distractions of playing with teensy boards (pjrc.com).

A high percentage of Arduino boards have a constant defined for this, as mentioned in the Arduino reference:
LED_BUILTIN - Arduino Reference

Often times it is defined in one of the header files associated the Arduino Variant.

In this case it is in: variants\MINIMA\pins_arduino.h

// LEDs
// ----
#define PIN_LED     (13u)
#define LED_BUILTIN PIN_LED
#define LED_TX      (21u)
#define LED_RX      (22u)

And shown on the Pin out page

Good luck

You never can achieve 16 MHz freq on MCU with 16 MHz clock. The maximum is 8 MHz

Thank you, teacher.

I have looked at the page pjrc.com. It looks very good, but right now it's too big for me. I wish I had time to dedicate to it.

LED_BUILTIN:
You're right, Arduino has it specified, and I think I read it at the time, but since the R3 version has the LED associated with pin 13, it seemed like unnecessary information to me. You are right that on the Arduino R4, it makes sense, since the Led is associated with an independent output.

Now I understand that in the program you turn on the LED flashing, to indicate that the frequency tests have finished.

What frequency is interesting for my project:
Approximately 30kHz.

I have tested the motor with an R3, and it increases to 32kHz and no noise is heard.

I have been reading about PWM generators, which have a name in Ranesas, which have dividers.... but that manual is too big for me.

Thank you very much for your help

For the heck of it, I did some quick and dirty program to play with:

#include <pwm.h>
PwmOut pwm5(5);

uint32_t frequency = 50;
uint32_t duty = 2048;

void setup() {
  while (!Serial) {};
  Serial.begin(115200);
  Serial.print("Quick and dirty PWM Test");

  analogWriteResolution(12);
  pwm5.begin(1000000 / frequency, 0);
  analogWrite(5, duty);   //GTIOC2B
  analogWrite(6, 2048);  // GTIOC0B
  analogWrite(4, 2048);  // GTIOC2A

}

void loop() {
  Serial.println("Enter new frequency and duty:");
  while (!Serial.available()) {};

  uint32_t new_freq = 0;
  uint32_t new_duty = 0;
  int ch;

  for (;;) {
    ch = Serial.read();
    if ((ch < '0') || (ch > '9')) break;
    new_freq = new_freq * 10 + ch - '0';
  }
  while (ch == ' ') ch = Serial.read();
  for (;;) {
    if ((ch < '0') || (ch > '9')) break;
    new_duty = new_duty * 10 + ch - '0';
    ch = Serial.read();
  }
  while (Serial.read() != -1) {}

  uint32_t period_us = 1000000 / new_freq;
  Serial.print("New freq: ");
  Serial.print(new_freq);
  Serial.print(" period: ");
  Serial.println(period_us);
  pwm5.begin(period_us, 0);

  Serial.print("duty: ");
  Serial.println(new_duty);
  analogWrite(5, new_duty);
}

It is more complicated than it needs to be... Was just curious about a few things.
This went off of the earlier test sketch I had using analogWrite to update the duty cycle.
It allows me to type in a desired frequency and value to pass into analogWrite.
I have set analogWriteResolution to 12, so 0-4095

I also setup pins 4, 5, 6 as PWM output. pins 4 and 5 are on the same underlying timer.
And looked at the three pins using Logic analyzer...
I typed in: 32000 512
Which in debug showed:

Quick and dirty PWM TestEnter new frequency and duty:
New freq: 32000 period: 31
duty: 512

Enter new frequency and duty:


Which you can see in this image, that the frequency was more or less 32K
You will also notice that it wiped out the PWM on pin 4 when it changed.

And for what it is worth, I typed in: 1000000 2048 and


So with this API, it appears like you can go up to 1mhz

1 Like

Congratulations KurtE.
Thank you very much for the quick response, and for the time you have dedicated to it.

Your code works perfectly.
Indeed. I have borrowed an oscilloscope, and I have managed to raise the Hz on all the outputs at the same time. (All 32kHz).

The test I have done is the same frequency and period in all of them, and in all of them I have obtained 32kHZ (It doesn't matter if they are PWM or not, in all of them)
(I have not tried different frequencies on each output)

I have to check my program to see why it doesn't work.

Thank you very much to all. I'll leave the thread open for a couple of days, in case anyone has anything to contribute (and if I do some more tests, I'll give you my experience), and then I'll consider it resolved.

1 Like

Hello everyone
I'm going to share my experience with you, in case it helps someone:

I have entered the following code:

//KurtE's original code, modified by Jose555

#include <pwm.h>
PwmOut pwm0(0);
PwmOut pwm1(1);
PwmOut pwm2(2);
PwmOut pwm3(3);
PwmOut pwm4(4);
PwmOut pwm5(5);
PwmOut pwm6(6);
PwmOut pwm7(7);
PwmOut pwm8(8);
PwmOut pwm9(9);
PwmOut pwm10(10);
PwmOut pwm11(11);
PwmOut pwm12(12);
PwmOut pwm13(13);


uint32_t frequency = 50;
uint32_t duty = 2048;

void setup() {
  while (!Serial) {};
  Serial.begin(115200);
  Serial.print("Quick and dirty PWM Test");

  analogWriteResolution(12);
  pwm5.begin(1000000 / frequency, 0);
  analogWrite(5, duty);   //GTIOC2B
  analogWrite(6, 2048);  // GTIOC0B
  analogWrite(4, 2048);  // GTIOC2A

}

void loop() {
  Serial.println("Enter new frequency and duty:");
  while (!Serial.available()) {};

  uint32_t new_freq = 0;
  uint32_t new_duty = 0;
  int ch;

  for (;;) {
    ch = Serial.read();
    if ((ch < '0') || (ch > '9')) break;
    new_freq = new_freq * 10 + ch - '0';
  }
  while (ch == ' ') ch = Serial.read();
  for (;;) {
    if ((ch < '0') || (ch > '9')) break;
    new_duty = new_duty * 10 + ch - '0';
    ch = Serial.read();
  }
  while (Serial.read() != -1) {}

  uint32_t period_us = 1000000 / new_freq;
  Serial.print("New freq: ");
  Serial.print(new_freq);
  Serial.print(" period: ");
  Serial.println(period_us);
  
  pwm0.begin(period_us, 0);
  period_us = 1000000 / (new_freq-1000);
  pwm1.begin(period_us, 0);
 period_us = 1000000 / (new_freq-2000);
  pwm2.begin(period_us, 0);
 period_us = 1000000 / (new_freq-3000);
 pwm3.begin(period_us, 0);
 period_us = 1000000 / (new_freq-4000);
 pwm4.begin(period_us, 0);
 period_us = 1000000 / (new_freq-5000);
 pwm5.begin(period_us, 0);
 period_us = 1000000 / (new_freq-6000);
 pwm6.begin(period_us, 0);
 period_us = 1000000 / (new_freq-7000);
 pwm7.begin(period_us, 0);
 period_us = 1000000 / (new_freq-8000);
 pwm8.begin(period_us, 0);
 period_us = 1000000 / (new_freq-9000);
 pwm9.begin(period_us, 0);
 period_us = 1000000 / (new_freq-10000);
  pwm10.begin(period_us, 0);
 period_us = 1000000 / (new_freq-11000);
  pwm11.begin(period_us, 0);
 period_us = 1000000 / (new_freq-12000);
  pwm12.begin(period_us, 0);
 period_us = 1000000 / (new_freq-13000);
  pwm13.begin(period_us, 0);
 period_us = 1000000 / (new_freq-14000);


  Serial.print("duty: ");
  Serial.println(new_duty);
  analogWrite(0, new_duty);
  analogWrite(1, new_duty);
  analogWrite(2, new_duty);
  analogWrite(3, new_duty);
  analogWrite(4, new_duty);
  analogWrite(5, new_duty);
  analogWrite(6, new_duty);
  analogWrite(7, new_duty);
  analogWrite(4, new_duty);
  analogWrite(5, new_duty);
  analogWrite(6, new_duty);
  analogWrite(7, new_duty);
  analogWrite(8, new_duty);
  analogWrite(9, new_duty);
  analogWrite(10, new_duty);
  analogWrite(11, new_duty);
  analogWrite(12, new_duty);
  analogWrite(13, new_duty);
}

I write in the serial 40000 300

Only output 5 (35.7kHz) is activated, the rest of the outputs 490hz

I write again 40000 300

It would be expected that at output 1, we would have 40kHz, at 2 - 39kHz, at 3 -38kHz.....
(my oscilloscope is very simple, and probably not very accurate)

Then yes:
I write the measured values:
0 - 40kHz - GTIOC4B
1 - 40kHz - GTIOC4A
2 - 28.5kHz - GTIOC1A
3 - 28.5kHz - GTIOC1B
4 - 80Hz ?? - GTIOC2A
5 - 35.7 kHz - GTIOC2B
6 - 33.3 kHz - GTIOC0B
7 - 33.3 kHz - GTIOC0A
8 - 31.2 kHz - GTIOC7A
9 - 31.2 kHz - GTIOC7B
10 - 27 kHz - GTIOC3B
11 - 28.5 kHz - GTIOC1A
12 - 28.5 kHz - GTIOC1B
13 - 27 kHz - GTIOC3A

Output 4 has strange behavior,
The rest behaves grouped in clocks:
0 and 1
2,3,11 and 12
6 and 7
8 and 9
10 and 13
the 5 alone
and number 4, which has not worked for me in this test

I hope the information is useful to someone

Thank you very much to all