Skip to content
This repository has been archived by the owner on Feb 4, 2023. It is now read-only.

Changing Duty Cycle Dynamically Creates Runt PWM pulse #10

Closed
RockingYProductions opened this issue Oct 14, 2022 · 4 comments
Closed

Changing Duty Cycle Dynamically Creates Runt PWM pulse #10

RockingYProductions opened this issue Oct 14, 2022 · 4 comments
Labels
enhancement New feature or request

Comments

@RockingYProductions
Copy link

RockingYProductions commented Oct 14, 2022

Arduino IDE version 1.8.13
RP2040 Core Version arduino-pico core v2.5.2
RP2040 Board type RASPBERRY_PI_PICO
Using OSX 12.6

Contextual information

There was observed to be a runt or glitch generated when switching the duty cycle, that lasted only the cycle the update occurred at. This runt/glitch is detectable by our receiver, and although it only lasts one cycle, it causes jitter issues.

Is there a way to switch Duty Cycle precisely between the last complete cycle of the current PWM cycle and the next complete cycle of the new PWM duty cycle value.

Simplest possible steps to reproduce (see attached scope shot). You can pick different duty cycles and get the same effect.

const float PWMFREQ           = 100;      // PWM frequency on GPIO pin
const byte GPIO_PIN           = 19;

void setup()
{
  PWM_Instance = new RP2040_PWM(GPIO_PIN, PWMFREQ, 0);
  PWM_Instance->setPWM(GPIO_PIN, PWMFREQ, 0, true);
  ..
}
void loop()
{   
  PWM_Instance->setPWM(GPIO_PIN, 100, 50, true);
  ...
  PWM_Instance->setPWM(GPIO_PIN, 100, 20, true);
  ...
}

Attached Scope Screen Shot where the duty cycle changed.

SDS00007

@khoih-prog
Copy link
Owner

Hi @RockingYProductions

Thanks for the issue report. I'll certainly spend some time soon to investigate and try to fix, depending on the necessity and popularity.

This can be much harder to solve as the library is using fully hardware-based PWM, designed for very high Frequencies.

These purely hardware-based PWM channels can generate from very low (lowest is 7.5Hz) to very high PWM frequencies (in the MHz range, up to 62.5MHz).

Can you post more info about your use-case, such as

  • why runt / glitch is not OK
  • what problem caused by the issue
  • if your test using analogWrite() still shows same issue (I guess so, but haven't tested / measured)

so that we can all learn from the experience.

BTW, if your use-case requires only low frequency ( < 1000Hz ) as you're using 100Hz now, try the ISR-based RP2040_Slow_PWM library, which already fixed the same issue


From RP2040_Slow_PWM v1.2.0

3. DutyCycle to be optionally updated at the end current PWM period instead of immediately

// Default is true, uncomment to false
//#define CHANGING_PWM_END_OF_CYCLE     false

@khoih-prog khoih-prog added the enhancement New feature or request label Oct 14, 2022
khoih-prog added a commit that referenced this issue Oct 15, 2022
### Releases v1.4.0

1. Fix glitch when dynamically changing dutycycle. Check [Changing Duty Cycle Dynamically Creates Runt PWM pulse #10](#10)
2. Adjust `MIN_PWM_FREQUENCY` and `MAX_PWM_FREQUENCY` dynamically according to actual `F_CPU`
3. Update examples
khoih-prog added a commit that referenced this issue Oct 15, 2022
### Releases v1.4.0

1. Fix glitch when dynamically changing dutycycle. Check [Changing Duty Cycle Dynamically Creates Runt PWM pulse #10](#10)
2. Adjust `MIN_PWM_FREQUENCY` and `MAX_PWM_FREQUENCY` dynamically according to actual `F_CPU`
3. Update examples
@khoih-prog
Copy link
Owner

Hi @RockingYProductions

The new RP2040_PWM v1.4.0 has just been published. Your contribution, by requesting good enhancement, is noted in Contributions and Thanks

Please test and report if there is any more issue.

Be sure to modify your code as follows by not using phase_correct == true

#define _PWM_LOGLEVEL_        1
#include "RP2040_PWM.h"

//creates pwm instance
RP2040_PWM* PWM_Instance;

const float PWMFREQ           = 100;            // PWM frequency on GPIO pin
const byte GPIO_PIN           = 19;

float dutyCycle;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  delay(100);

  Serial.print(F("\nStarting PWM_Glitch on ")); Serial.println(BOARD_NAME);
  Serial.println(RP2040_PWM_VERSION);
  
  PWM_Instance = new RP2040_PWM(GPIO_PIN, PWMFREQ, 0);
  PWM_Instance->setPWM(GPIO_PIN, PWMFREQ, 0);
}

void loop()
{   
  dutyCycle = 50;
  
  PWM_Instance->setPWM(GPIO_PIN, PWMFREQ, dutyCycle);
  
  delay(100);

  dutyCycle = 20;
  
  PWM_Instance->setPWM(GPIO_PIN, PWMFREQ, dutyCycle);
 
  delay(100);
}

Releases v1.4.0

  1. Fix glitch when dynamically changing dutycycle. Check Changing Duty Cycle Dynamically Creates Runt PWM pulse #10
  2. Adjust MIN_PWM_FREQUENCY and MAX_PWM_FREQUENCY dynamically according to actual F_CPU
  3. Update examples

@RockingYProductions
Copy link
Author

Confirmed that Release v1.4.0 removes the observed glitch when changing duty cycles and verified by scope. Excellent!

In our use case, a system was wired such that it had one GPIO pin between the RPI PICO (buffered to 5v) and an Arduino UNO input pin. This generated a simple logic signal that triggered the Arduino to start a mechanical assembly. Later, it was required to have four (possibly more) trigger signals. We cannot add/move additional signals in the design.

By using the PWM output of the PICO, 10 PWM frequencies (duty cycle 0%, 10%, etc,) where chosen to represent 10 trigger outputs. The Arduino UNO used pin-change IRQ's to measure the pulse width (or lack of at 0% and 100%). 100Hz was chosen to minimize the IRQ service overhead on the UNO. The PICO can now transmit 10 (or more) 'trigger' outputs and it was acceptable that only one trigger output at a time was required.

We observed that when the PWM runt/glitch was received, the UNO would measure the pulse and create an incorrect trigger output, then create the correct trigger after the next cycle. A work around was to 'debounce' the received PWM for two consecutive PWM values, but this was adding IRQ overhead. Now we can successfully transmit may triggers without any PCB changes or IRQ overhead. Thank you very much!

@khoih-prog
Copy link
Owner

Great to know it's working for you now. We can all learn from your use-case and experience.

The library is better and better thanks to contributing users like you.

Best Regards,

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants