Read duty cycle of pwm signal

What are you developing?
Post Reply
kid_bengala
Posts: 9
Joined: Sun Jan 15, 2023 11:21 pm

Read duty cycle of pwm signal

Post by kid_bengala »

Hello,

I want to read a PWM signal and know its duty cycle, for this I read a digital input and by pulseIn, I get a value that I divide by 10. It has been working, but I have noticed that if I raise the frequency or lower it, the value returned by PulseIn is altered, sometimes unrelated. For example, I have a signal with a frequency and the pulseIn value returns a low value, I increase the frequency and the pulseIn value goes up, I increase the signal even more and the value goes down (I can attach some oscilloscope screenshots to explain better).

I had thought about using some timer or similar to read this value, but I'm new to stm and don't understand the examples very well :oops: .

Any advice on how to get the duty cycle of a signal or zero value in the absence of this without using pulseIn? Thanks.

Regards
GonzoG
Posts: 403
Joined: Wed Jan 15, 2020 11:30 am
Answers: 26
Location: Prudnik, Poland

Re: Read duty cycle of pwm signal

Post by GonzoG »

In STM examples you have example that reads frequency and duty cycle.
kid_bengala
Posts: 9
Joined: Sun Jan 15, 2023 11:21 pm

Re: Read duty cycle of pwm signal

Post by kid_bengala »

GonzoG wrote: Mon Jan 16, 2023 12:08 am In STM examples you have example that reads frequency and duty cycle.
I have tried that example, changing the pin to the pin I use on my board (it was a gift) and it does not work.

Code: Select all

[19:22:28:154] Frequency = 0    Dutycycle = 0
[19:22:29:161] Frequency = 0    Dutycycle = 0
[19:22:30:152] Frequency = 0    Dutycycle = 0
[19:22:31:169] Frequency = 0    Dutycycle = 0
[19:22:32:150] Frequency = 0    Dutycycle = 0
I can read the duty cycle with other Arduino codes but it is not a stable value and changes constantly, and if I change the frequency, it takes seconds to detect the new duty cycle.
doubleaswi wrote: Mon Jan 16, 2023 10:32 am There are a few different ways you could approach measuring the duty cycle of a PWM signal without using the pulseIn() function, which can be affected by changes in frequency.

One approach is to use a timer to capture the rising and falling edges of the PWM signal, and then calculate the duty cycle based on the time between those edges. The attachInterrupt() function can be used to trigger an interrupt when the PWM signal changes state, and the micros() function can be used to get the current time in microseconds.

Another approach could be to use a hardware timer to measure the high and low time of the PWM signal and calculate the duty cycle. This can be done by configuring the timer to count the number of clock cycles during the high and low periods of the PWM signal.

You can also use a library like the Arduino-PWM library which allows you to measure the duty cycle of the signal.

In any case, you'll need to understand the basics of how timers and interrupts work on the STM32 microcontroller. I recommend starting with the official documentation and examples from the STM32 website, as well as searching for tutorials and example code online.

It will also be helpful to have a good understanding of the PWM signal you're working with, such as the frequency and the resolution of the PWM signal.

Finally, you could also use a logic analyzer to monitor the signal, this way you could see the exact time of the high and low states of the signal and calculate the duty cycle accordingly.

I hope this helps and good luck with your project!


_____________________________
https://www.rst.software/blog/chat-app- ... ry-in-2023
I can't use an interrupt, I already detect some pulses with an interrupt and it is possible that it affects this routine (it is more important).

I tried to use a hardware timer, but it affected the use of another interrupt that triggers another timer (the one that triggers the interrupt I mentioned, to disable a few microseconds later an output) and I had to disable it.

I tried the example of reading the PWM signal on an empty sketch, but it didn't work for me.

I have tried several codes that I have found on the internet, that use millis() or micros() to read the states of the input, but only one has worked, but it does not give me stable values, each cycle fluctuates and if I change the working frequency (I am trying with a signal generator), it takes seconds to detect it.

Code: Select all

const int pin = PB0;
unsigned long highDuration = 0;
unsigned long lowDuration = 0;
unsigned long sampleDuration = 10000;
unsigned long prevMicros = 0;
bool prevState = LOW;

void setup() {

  Serial.begin(9600);

  pinMode(pin, INPUT);

  prevMicros = micros();
}

void loop() {
  if (micros() - prevMicros >= sampleDuration) {
    unsigned long currentMicros = micros();
    highDuration += digitalRead(pin) == HIGH ? currentMicros - prevMicros : 0;
    lowDuration += digitalRead(pin) == LOW ? currentMicros - prevMicros : 0;
    prevMicros = currentMicros;
    float totalDuration = highDuration + lowDuration;
    float dutyCycle = 100.0 * highDuration / totalDuration;
    Serial.println(dutyCycle);
  }
  // Other code
  
  delay(25);
}

Thanks!

Regards
GonzoG
Posts: 403
Joined: Wed Jan 15, 2020 11:30 am
Answers: 26
Location: Prudnik, Poland

Re: Read duty cycle of pwm signal

Post by GonzoG »

kid_bengala wrote: Fri Jan 27, 2023 6:36 pm I have tried that example, changing the pin to the pin I use on my board (it was a gift) and it does not work.
Not every pin can be used.
kid_bengala wrote: Fri Jan 27, 2023 6:36 pm I can read the duty cycle with other Arduino codes but it is not a stable value and changes constantly, and if I change the frequency, it takes seconds to detect the new duty cycle.
Most of those use long periods to count pulses, so you get updates every few seconds and you'll get correct reading after second period after change.
kid_bengala wrote: Fri Jan 27, 2023 6:36 pm I can't use an interrupt, I already detect some pulses with an interrupt and it is possible that it affects this routine (it is more important).
If you cannot use interrupts for measuring, then you have to live with that your counter will miss some pulses when other interrupts will trigger and you will get inaccurate measurement.
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: Read duty cycle of pwm signal

Post by dannyf »

if the pulse train isn't too fast, it is not difficult to use pin change interrupts (1-pin or 2 pins)

Code: Select all

  static uint32_t t0=0; //last rising edge
  uint32_t tmp;
  
  tmp = ticks(); //timestamp tmp
  if (pin) {  //rising edge has arrived
    period=tmp - t0; t0=tmp;
  } else {  //falling edge has arrived
    dc = tmp - t0;
  }
kid_bengala
Posts: 9
Joined: Sun Jan 15, 2023 11:21 pm

Re: Read duty cycle of pwm signal

Post by kid_bengala »

Hello

Thanks all for reply.
GonzoG wrote: Fri Jan 27, 2023 9:17 pm Not every pin can be used.
Which pins can I use? I have modified the code by assigning Timer 3 and Timer1, but it still doesn't work.

Code: Select all

HardwareTimer *MyTim = new HardwareTimer(TIM3);


Image
GonzoG wrote: Fri Jan 27, 2023 9:17 pm If you cannot use interrupts for measuring, then you have to live with that your counter will miss some pulses when other interrupts will trigger and you will get inaccurate measurement.
I could use interrupts, but having priority the main function and not this one to count the duty cycle duration.

But I have not found one that works correctly either, it returns incorrect data, even without integrating the main interrupt (this one operates with the duty cycle data and I have tested it by typing the duty cycle values by hand).

Thanks

Regards
kid_bengala
Posts: 9
Joined: Sun Jan 15, 2023 11:21 pm

Re: Read duty cycle of pwm signal

Post by kid_bengala »

Hello

I changed the pin from PB0 to PB3 and the example worked, why was this? I would like to know in order to learn. Thank you.

Regards.
Emilyy34
Posts: 1
Joined: Mon May 29, 2023 1:16 am

Re: Read duty cycle of pwm signal

Post by Emilyy34 »

kid_bengala wrote: Fri Feb 24, 2023 5:33 pm Hello

I changed the pin from PB0 to PB3 and the example worked, why was this? I would like to know in order to learn. Thank you.

Regards.
I'm also quite curious about this, can anyone explain it to me?
kid_bengala
Posts: 9
Joined: Sun Jan 15, 2023 11:21 pm

Re: Read duty cycle of pwm signal

Post by kid_bengala »

Hello

Sorry for the delay in responding, I was sick and could not follow up on this.

I have tested the stm32duino example (https://github.com/stm32duino/STM32Exam ... rement.ino) and as I said, it works on 1 pin and I don't understand the reason.

I chose pin 15 because in STM32Cube it allowed PWM capture configuration, but with stm32duino it doesn't work. If it works with pin 20, which curiously, also allows to configure in STM32Cube for the same operation.

I have put a serial Serial.println in example to know what timer and channels it takes and I get the following result.

PIN 15 (not working)

Code: Select all

[20:06:43:713] TIM1
[20:06:43:729]   channelRising = 1
[20:06:43:745]   channelFalling = 2
[20:06:43:761] Frequency = 0    Dutycycle = 0
[20:06:44:782] Frequency = 0    Dutycycle = 0
PIN 20 (working)

Code: Select all

[20:06:54:205] TIM1
[20:06:54:221]   channelRising = 3
[20:06:54:237]   channelFalling = 4
[20:06:54:253] Frequency = 0    Dutycycle = 0
[20:06:55:274] Frequency = 7995    Dutycycle = 57
[20:06:56:281] Frequency = 7996    Dutycycle = 56
And these are the STM32Cube configurations where you can see the pins that allow this functionality.
PIN 15
Image
PIN 20
Image

I don't know the inner workings of the clocks and similar, therefore, I don't understand where is the failure or how to fix it or modify design or choose another micro.

Surely it is my lack of knowledge and I appreciate if someone can guide me, to know in the future how to choose correctly the pins and micros.

Thank you very much.

Regards.
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: Read duty cycle of pwm signal

Post by dannyf »

that particular piece of code uses the "pin" to decide which timer to use for input capture. so you will need to pick a pin that is mapped to a timer input capture channel.

you will need to see which Dx pin maps to a physical pin and if that physical pin is capable of serving as an input capture channel - the datasheet will tell you that.
Post Reply

Return to “Projects”