Esp-idf: problem with MCPWM below 15 Hz frequency (IDFGH-1371)

Created on 2 Aug 2018  路  10Comments  路  Source: espressif/esp-idf

INSTRUCTIONS

Before submitting a new issue, please follow the checklist and try to find the answer.

  • [x] I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • [ ] I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.(i dont know how to do it in arduino)
  • [x] I have searched the issue tracker for a similar issue and not found a similar issue.

Environment

  • Development Kit: [ESP32-DevKit]
  • Kit version (ESP32 DevKit): [v1]
  • Core (if using chip or module): [ESP-WROOM32]
  • IDF version (git rev-parse --short HEAD to get the commit id.): i dont have any idea how to get that in arduino
    //bd6ea4393c7d2f059fc4decc70f1ec3eb3597268
  • Development Env: [Arduino IDE]
  • Operating System: [Windows]
  • Power Supply: [USB]

Problem Description

I used mcpwm example inside arduino and it worked perfectly until I changed the frequency below 15 Hz and output is weird I got different frequencies I set it to 1 and then output got 58 Hz I changed it to 15 then it got 815 Hz .
I need frequency 1 and 2 Hz how can i solve this problem( I used MCPWM_UNIT_0, MCPWM0 both channel A and B)
//Detailed problem description goes here.

Expected Behavior

PWM frequency must be 1 Hz

Actual Behavior

PWM is something near 60 Hz

Steps to repropduce

  1. prepare arduino environment as this link
    https://www.instructables.com/id/IOT-Made-Simple-Playing-With-the-ESP32-on-Arduino-/
    2.then compile minimal code below

// It helps if you attach a picture of your setup/wiring here.
no need wiring

Code to reproduce this issue

// the code should be wrapped in the ```cpp tag so that it will be displayed better.
#include "driver/mcpwm.h"
#include "esp_log.h"
#define GPIO_PWM0A_OUT 13   //Set GPIO 19 as PWM0A
#define GPIO_PWM0B_OUT 12   //Set GPIO 18 as PWM0B

void setup() {
  // put your setup code here, to run once:
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT);
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT);
  mcpwm_config_t pwm_config;
  pwm_config.frequency = 1;    //frequency = 1000Hz
  pwm_config.cmpr_a = 50.0;       //duty cycle of PWMxA = 60.0%
  pwm_config.cmpr_b = 50.0;       //duty cycle of PWMxb = 50.0%
  pwm_config.counter_mode = MCPWM_UP_COUNTER;
  pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
  mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);   //Configure PWM0A & PWM0B with above settings
  mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, MCPWM_DUTY_MODE_0);
  mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B, MCPWM_DUTY_MODE_1);
  mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_0);

}

void loop() {

  // put your main code here, to run repeatedly:

}

Debug Logs

no debug produced since module is working but if you need i can provide you 
i think the program is very minimal

Other items if possible

  • [ ] sdkconfig file (attach the sdkconfig file from your project folder)
  • [ ] elf file in the build folder (note this may contain all the code details and symbols of your project.)
  • [ ] coredump (This provides stacks of tasks.)

All 10 comments

You will have to change hardcoded prescale values because tick is 1mhz and period register is 16 bit so 1mhz/65535 = 15hz.

@negativekelvin Thank for your quick reply. How can I change hardcoded prescale value in arduino ?
Which file do i have to change?

You can't so you will have to make your own version of mcpwm_set_frequency function

@negativekelvin you were totally right. i created a folder inside arduino library and put mcpwm.c and mcpwm.h in that folder then changed the name of these two files to MCPWM1.c and MCPWM1.h then in .c file i changed #include "driver/mcpwm.h "#include "MCPWM1.h" and

define MCPWM_CLK_PRESCL 159 //MCPWM clock prescale

define TIMER_CLK_PRESCALE 99 //MCPWM timer prescales

everything now working like a charm

Maybe keep this open because the driver should either dynamically calculate prescale values or let the user change them and report an error if it cannot produce the requested frequency.

Also related https://github.com/espressif/esp-idf/issues/1101

Hi,

I tried to do the same to generate the frequency of 1Hz but I could not clearly understand where should I have to add the:

define MCPWM_CLK_PRESCL 159 //MCPWM clock prescale

define TIMER_CLK_PRESCALE 99 //MCPWM timer prescales

I was not also able to find the mcpwm.c file in neither my arduino library nor in my ESP32 library. When I add them into my code and also just copied the mcpwm.h code to my ESP32 libraries nothing changes and the frequency is still 60Hz instead of 1 Hz.

@mehdina94rm
You can find this two register MCPWM[mcpwm_num]->clk_cfg.prescale and MCPWM[mcpwm_num]->timer[timer_num].period.prescale, both these two register is used to configure the clock divider. MCPWM_CLK_PRESCL is used set to set the register clk_cfg.prescale, and the TIMER_CLK_PRESCALE is used to set the register period.prescale.

Thanks for your comment, I have changed my code to configure the clock divider but nothing happens when I upload this code in my ESP32:

include "MCPWM1.h"

include "esp_log.h"

define GPIO_PWM0A_OUT 19 //Set GPIO 19 as PWM0A

define GPIO_PWM0B_OUT 18 //Set GPIO 18 as PWM0B

define MCPWM_CLK_PRESCL 159 //MCPWM clock prescale

define TIMER_CLK_PRESCALE 99 //MCPWM timer prescales

void setup() {
// put your setup code here, to run once:
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT);
mcpwm_config_t pwm_config;
pwm_config.frequency = 1; //frequency = 1000Hz

pwm_config.cmpr_a = 30.0; //duty cycle of PWMxA = 60.0%
pwm_config.cmpr_b = 50.0; //duty cycle of PWMxb = 50.0%
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Configure PWM0A & PWM0B with above settings
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, MCPWM_DUTY_MODE_0);
delay(5000);
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B, MCPWM_DUTY_MODE_1);
mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_0);

}

void loop() {

// put your main code here, to run repeatedly:

}

You have to do it as stated above, copy from here https://github.com/espressif/esp-idf/blob/v3.2/components/driver/mcpwm.c

Hello, mcpwm_set_frequency function overrides MCPWM[mcpwm_num]->clk_cfg.prescale and MCPWM[mcpwm_num]->timer[timer_num].period.prescale, can that function calculate values of prescale inside it??? Like ledc.
This is a very good function to control an AC motor (frequency converters works around 0-320Hz).

Was this page helpful?
0 / 5 - 0 ratings