Page 1 of 1

Marlin FW - Analogwrite for PWM control

Posted: Sat Aug 29, 2020 2:38 pm
by happytoto
Hello,

I am currently playing with my 3D printer to add some LED strip. In the Marlin FW, the RGBW leds are controlled with an Analogwrite function such as in the standard arduino example:

Code: Select all

void loop() {
  // fade in from min to max in increments of 5 points:
  for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
    // sets the value (range from 0 to 255):
    analogWrite(ledPin, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(30);
  }

  // fade out from max to min in increments of 5 points:
  for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
    // sets the value (range from 0 to 255):
    analogWrite(ledPin, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(30);
  }
}
Although this method kind of works, the brightness of the led strip is at max roughly 50% of the max possible (ie connected to +12V). I don't understand why fully (I don't have an oscilloscope to look at the output) but it is what it is.

I tried a small program based on the page
https://github.com/stm32duino/wiki/wiki ... er-library

Code: Select all

void setup() {
  TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(ledPin), PinMap_PWM);
  uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(ledPin), PinMap_PWM));

  // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished.
  HardwareTimer *MyTim = new HardwareTimer(Instance);

  // Configure and start PWM
  // MyTim->setPWM(channel, pin, 5, 10, NULL, NULL); // No callback required, we can simplify the function call
  MyTim->setPWM(channel, ledPin, 5000, 10); 
  delay(5000);

  for (;;){
    for (int fadeValue = 0 ; fadeValue <= 100; fadeValue += 2) {
      MyTim->setPWM(channel, ledPin, 10000, fadeValue);
      delay(100);
    }
    
    for (int fadeValue = 100 ; fadeValue >= 0; fadeValue -= 2) {
      MyTim->setPWM(channel, ledPin, 10000, fadeValue);
      delay(100);
    }
  }
}
In that case, I am getting the full brightness at max.

Without rewriting the Marlin FW, what would you recommend to do?

Optimal solution: analogwrite directly using the PWM hardwaretimer of the STM32

Thank you for your feedback

Re: Marlin FW - Analogwrite for PWM control

Posted: Tue Sep 01, 2020 1:41 pm
by BennehBoy
Is this down to DAC resolution?

Re: Marlin FW - Analogwrite for PWM control

Posted: Tue Sep 01, 2020 2:00 pm
by fpiSTM
Strange, as if the pin has PWM capability then the HardwareTimer is used.
Except if the pin has DAC capabilities then it preferred to the PWM.

Re: Marlin FW - Analogwrite for PWM control

Posted: Wed Sep 02, 2020 9:12 am
by happytoto
Following the first feedback. in the simple arduino example, I added analogWriteResolution(4) and I then got the full brightness range. Tried with a resolution of 8 but didn't get the full brightness for fade value of 0-255. I am not quite sure why.

I am left to ponder what is the right resolution 8, 16 (SMT32 documentation) or 4, 12.
Is the 16 the better one to choose?

Re: Marlin FW - Analogwrite for PWM control

Posted: Wed Sep 02, 2020 9:48 am
by BennehBoy
You'd need to set the fade range from 0-4093 to get full brightness with a 12bit resolution.

You got full brightness with 4 bit, because that has a range of 0-15, so as soon as the fade hit 15 you would be at full brightness.

The resolution just gives you finer increments...

Re: Marlin FW - Analogwrite for PWM control

Posted: Fri Sep 04, 2020 1:17 pm
by happytoto
After trial and error, I think there is a bug (feature?) somewhere.

If I set 12bit resolution, I get the max_brightness for 2^(res+4) or 65535. I am not quite sure why.

here is the simple code to test:

Code: Select all

#include <math.h>

int ledPin = 29;    // LED connected to digital pin 29
int max_fade;
int step_i;
int delay_i;
int res;

void setup() {
  res = 12;
  max_fade = 1 << (res+4);
  step_i = max_fade / 10;
  delay_i = 1000;

  analogWriteResolution(res);
  pinMode(ledPin, OUTPUT);
  // nothing happens in setup
}

void loop() {
  // fade in from min to max in increments of 5 points:
  for (int fadeValue = 0 ; fadeValue <= max_fade; fadeValue += step_i) {
    // sets the value (range from 0 to 255):
    analogWrite(ledPin, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(delay_i);
  }

  // fade out from max to min in increments of 5 points:
  for (int fadeValue = max_fade ; fadeValue >= 0; fadeValue -= step_i) {
    // sets the value (range from 0 to 255):
    analogWrite(ledPin, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(delay_i);
  }
}

Re: Marlin FW - Analogwrite for PWM control

Posted: Fri Sep 04, 2020 2:31 pm
by fpiSTM
Which board ? (mcu)?

Re: Marlin FW - Analogwrite for PWM control

Posted: Fri Sep 04, 2020 9:00 pm
by happytoto

Re: Marlin FW - Analogwrite for PWM control

Posted: Mon Sep 07, 2020 5:17 pm
by fpiSTM
I've tested with a Nucleo F767 using pin PC9 (D29 on the REMRAM) with the same TIM3 CH4 and I see no issue without the +4, I've checked with a analyser.
pwm.png
pwm.png (73.9 KiB) Viewed 6240 times
Anyway your code never reach 100% due to the rounding of the computation ( /10) , the wrong max res value which should be (1<< res ) - 1

Code: Select all


int ledPin = PC9;    // LED connected to digital pin 29

static int step_i = 5;
static int delay_i = 2;
static int res = 8;
static int max_fade = (1 << (res)) - 1;

void setup() {
  analogWriteResolution(res);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // fade in from min to max in increments of 5 points:
  for (int fadeValue = 0 ; fadeValue <= max_fade; fadeValue += step_i) {
    // sets the value (range from 0 to 255):
    analogWrite(ledPin, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(delay_i);
  }

  // fade out from max to min in increments of 5 points:
  for (int fadeValue = max_fade ; fadeValue >= 0; fadeValue -= step_i) {
    // sets the value (range from 0 to 255):
    analogWrite(ledPin, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(delay_i);
  }
}