PFM 0-50Hz, how to?

Hi

I want to generate a 0-50Hz PFM (pulse frequency modulation) on an output pin, on an ESP32.

PFM is similar to PWM, but the the duty cycle is fixed at 50% and the frequency is varied instead.

I tried the ledc lib, but it doesn't go below 130Hz.

Does anyone have a code example of how to accomplish this in a good and effective way?

Thanks!

Many ways. It would help if you described what other responsibilities the processor will have, and how and where from the current value of the PFM is coming.

And pretty much anything else you can share.

Just synthesizing the PFM at such low frequencies is relatively straight forward. It's the context that will (or won't) colmpicate things.

a7

Also 0Hz isn't a frequency, so we need to know what your actual lowest frequency is.

Hi,
which feature do you want to use to vary frequency?
Potentiometer, serial input, etc.......

Hi,
in this code I wrote, the "ledcInit()" function allows the
frequency varies from 1 Hz to 40 MHz, just vary the value of the "oscillator" variable and call the routine only when modifying the frequency value.


#include "driver/ledc.h"
#define LEDC_HS_CH0_CHANNEL   LEDC_CHANNEL_0                    // LEDC no canal 0
#define LEDC_HS_CH0_GPIO      GPIO_NUM_25                       // Saida do ledc gerador de pulsos

uint32_t        oscilator     = 2;                              // Frequencia em Hz
uint32_t        mDuty         = 0;                              // Valor calculado do duty
uint32_t        resolution    = 0;                              // Valor calculado da resolucao
//----------------------------------------------------------------------------
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Hello, ESP32!");
  ledcInit ();
}
//----------------------------------------------------------------------------
void loop() {
  delay(10); // this speeds up the simulation
}
//----------------------------------------------------------------------------
void ledcInit ()
{
  resolution = log((80000000 / oscilator) + 1) / log(2);          // Calculo da resolucao para ledc
  if (resolution > 20) resolution = 20;                           // Maxima resolucao é 20
  //  Serial.println(resolution);                                 // Print
  mDuty = (pow(2, resolution)) / 2;                               // Calculo do duty para ledc 50%
  //Serial.println(mDuty);                                          // Print

  ledc_timer_config_t ledc_timer = {};                            // Instancia a configuracao do timer do ledc

  // ledc_timer.duty_resolution =  resolucao;                     // Configura resolucao
  ledc_timer.duty_resolution = (ledc_timer_bit_t) + resolution;   // Configura resolucao
  ledc_timer.freq_hz    = oscilator;                              // Frequencia de oscilacao
  ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;                   // Mode de operacao em high speed
  ledc_timer.timer_num = LEDC_TIMER_0;                            // Usar timer0 do ledc
  ledc_timer_config(&ledc_timer);                                 // Configurar o timer do ledc

  ledc_channel_config_t ledc_channel = {};                        // Instancia a configuracao canal do ledc

  ledc_channel.channel    = LEDC_HS_CH0_CHANNEL;                  // Configura canal0
  ledc_channel.duty       = mDuty;                                // Valor calculado do duty em %
  ledc_channel.gpio_num   = LEDC_HS_CH0_GPIO;                     // Saida no GPIO defino no inicio
  ledc_channel.intr_type  = LEDC_INTR_DISABLE;                    // Desabilita interrupt de ledc
  ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;                 // Mode de operacao do canal em high speed
  ledc_channel.timer_sel  = LEDC_TIMER_0;                         // Usar timer0 do ledc

  ledc_channel_config(&ledc_channel);                             // Configurar o canal do ledc
}

Given the very low maximum frequency, I would think a bit-banged output triggered by a timer interrupt might well be the way to go. But it depends on the required precision, which, like other key specifications, is currently completely unspecified.

@ruilviana, perfect, thank you. I'll give this a try!

And success may be had with the ESP32's Motor Control Pulse Width Modulator (MCPWM) - ESP32 - — ESP-IDF Programming Guide latest documentation

The ESP32's High Resolution Timer (ESP Timer) - ESP32 - — ESP-IDF Programming Guide latest documentation can be stopped, a 0.

Wrong. With PFM, the duty cycle varies, as a result of the frequency changing but the pulse width remaining constant.

https://en.wikipedia.org/wiki/Pulse-frequency_modulation

What you are describing, is merely FM.

1 Like

@anon57585045, actually you are the one in error here.

PWM vs. PFM
PWM is not the only technique for regulating the output of a switching converter. Instead of modifying the duty cycle of a fixed-frequency square wave to regulate the output of a power supply, it is also possible to use a constant duty cycle and then modulate the square wave’s frequency (PFM) to achieve regulation. DC/DC voltage converters equipped with constant-on-time or constant-off-time control are typical examples of PFM architecture.

Now please stick to the topic!

Thanks! I will have a look at these!

I believe it is the article that is in error. By "constant duty cycle" they undoubtedly meant "constant pulse width".

As far as sticking to the topic, we are discussing PFM, right? You haven't mentioned at all what this pulse train will be driving. If it results in an integration of the pulses by means of low pass filtering, your interpretation will produce a constant, invariable signal.

If you don't believe me, look at fig. 1 in the article you linked. It illustrates PFM. All the pulses are a constant length, it is not a constant duty cycle.

image

I don't just post stuff without any thought. If "the topic" is actually crucially related to some circuit you are driving, then you need to post all the information about that.

I agree, and think it is simply a typo, as the very next sentence makes clear.

it is also possible to use a constant duty cycle and then modulate the square wave’s frequency (PFM) to achieve regulation. DC/DC voltage converters equipped with constant-on-time or constant-off-time control are typical examples of PFM architecture.

In that case Wikipedia is also wrong because it also states a fixed 50% duty cycle is also possible.

From Wikipedia:

PFM mode operation allows the switching frequency to be reduced and for a control method that prevents the inductor current from dropping below zero during light loads. Rather than applying square pulses of varying widths to the inductor, square pulse trains with a fixed 50% duty cycle are used to charge the inductor to a predefined current limit then discharge the inductor current to, but not below, zero. The frequency of these pulse trains is then varied to produce the desired output voltage with the aid of the output filter capacitor.

Or, perhaps, both Wikipedia and Digikey, and I, are correct, fixed duty cycle is a PMF mode ...

The Wikipedia article describes a reasonable pulse train to control current through a conductor, but is obviously not the sort of PFM discussed in the DC/DC switching article with the unfortunate and confusing typo.

You are most welcome to generate a 50% duty cycle, variable frequency signal, so just get on with your project.

How about opening a new topic on the conceptual discussion of the term PFM ?
And in this topic focus on meeting your need.
I understand that your need is a 50% fixed duty pulse train with the possibility of varying the frequency.
Right?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.