[SOLVED]: Does multiple calls to analogWrite may lead to weird behavior?

Post here first, or if you can't find a relevant section!
Post Reply
Step73
Posts: 27
Joined: Tue Jan 14, 2020 2:55 pm

[SOLVED]: Does multiple calls to analogWrite may lead to weird behavior?

Post by Step73 »

I wrote a simple fade function. I would like to use my own because I'm going to extend with some specific features.
Here how it should work:

Code: Select all

typedef struct
{
  unsigned long refTime;
  int pin;
  float m;
  float q;
  float current;
  float duration;
  bool ended;
} Led_t;
Led_t led;

void led_fade(float target, float duration) 
{
  if (target < 0.0) target = 0.0;
  target = target * 255.0 / 100.0;
  if (target > 255.0) target = 255.0;

  if (duration < 0) duration = 0;
  _led.refTime = millis();
  _led.duration = duration;
  _led.ended = false;        
  _led.m = (target - _led.current) / duration;
  _led.q = _led.current;
}

void process_led()
{
  unsigned long currTime = millis();
  float t = ((float)currTime - _led.refTime) / 1000.0;

  if (t < _led.duration)
  {
      _led[i].current = _led.m * t + _led.q;
      analogWrite(_led.pin, _led.current);
  }
  else
  {
      if (!_led.ended)
      {
        _led.ended = true;
      }
  }
}
Usage:

Code: Select all

void setup()
{
    unsigned long currTime = millis();

  _led.refTime = currTime;
  _led.current = 0;
  _led.pin = LED_PIN;
  _led.ended = true;
  analogWrite(_led.pin, _led.current);
}

void loop()
{
  process_led();

  //when some conditions met:
  led_fade(100.0, 5.0);
It works, but during the transitions, the PWM signal is not good at all. With the oscilloscope I see another high-frequency PWM signal during the high level cycles. It goes away until I reach a stead-state. Are there any problems to call so frequently the `analogWrite()` function?

I may use the HardwareTimer but this is just a simple example.
In the real code, I have all the 20 pins pwm-ready for Nucleo F429ZI board and the user may select at run-time how many of them control in PWM.
Or I can pass any "pwm" pin to `setPWM` function?
Last edited by Step73 on Wed Jan 15, 2020 8:18 pm, edited 1 time in total.
User avatar
fpiSTM
Posts: 1723
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: Does multiple calls to analogWrite may lead to weird behavior?

Post by fpiSTM »

analogWrite() do all required init on each call so this is not efficient.
Step73
Posts: 27
Joined: Tue Jan 14, 2020 2:55 pm

Re: Does multiple calls to analogWrite may lead to weird behavior?

Post by Step73 »

fpiSTM wrote: Wed Jan 15, 2020 3:11 pm analogWrite() do all required init on each call so this is not efficient.
Got it.
I'm trying to use hardware timers. The frequency setting is incredible precise!
But I still have the weird behavior: when fading I see a 32 kHz square wave super-imposed on the actual PWM.
Here a minimal but complete sketch:

Code: Select all

#define PWM_FREQ  1000
#define PWM_PIN   PA0

typedef struct
{
  unsigned long refTime;
  int pin;
  uint32_t channel;
  HardwareTimer *timer;
  float m;
  float q;
  float current;
  float duration;
} Led_t;
Led_t _led;

void setup() 
{
  _led.current = 0;
  _led.pin = PWM_PIN;
  TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(_led.pin), PinMap_PWM);
  _led.channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(_led.pin), PinMap_PWM));
  _led.timer = new HardwareTimer(Instance);
  _led.timer->setPWM(_led.channel, _led.pin, PWM_FREQ, 0);

  // start fade to 80% in 10 s
  _led.refTime = millis();
  _led.duration = 10.0;
  _led.m = (80.0 - _led.current) / _led.duration;
  _led.q = _led.current;
}

void loop() 
{
  unsigned long currTime = millis();
  float t = ((float)currTime - _led.refTime) / 1000.0;

  if (t < _led.duration)
  {
      _led.current = _led.m * t + _led.q;
      _led.timer->setPWM(_led.channel, _led.pin, PWM_FREQ, _led.current);
  }
}
I attach some pictures: two taken during fading (where you can see the "noise") and another at the end (good PWM).

Image Image Image

What am I missing this time?
Step73
Posts: 27
Joined: Tue Jan 14, 2020 2:55 pm

Re: Does multiple calls to analogWrite may lead to weird behavior?

Post by Step73 »

Solved using:

Code: Select all

_led.timer->setCaptureCompare(_led.channel, _led.current, PERCENT_COMPARE_FORMAT);
Post Reply

Return to “General discussion”