Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Change PWM frequency per channel/pin #2642

Closed
JHthe4 opened this issue Apr 23, 2022 · 18 comments
Closed

Feature request: Change PWM frequency per channel/pin #2642

JHthe4 opened this issue Apr 23, 2022 · 18 comments
Labels
enhancement fixed in source This issue is unsolved in the latest release but fixed in master workaround The issue contains a workaround

Comments

@JHthe4
Copy link

JHthe4 commented Apr 23, 2022

Hi,

I'm trying to mod an Aukey desk lamp using an ESP8266 board and WLED. I've found a teardown of my exact lamp, and someone has been kind enough to document what type of signals the onboard IC that I would have to replace is putting out:

Pin 5 of U2 has a 20 kHz PWM signal on it. As the brightness changes, it cycles through 20, 60, and 100 % duty cycle. When the LED is to be off, the pin is held low.
Pins 2, 3, and 7 have a 2 kHz PWM signal, with duty cycle correlating to the following:
Pin 2: Blue PWM
Pin 3: Red PWM
Pin 7: Green PWM

Since I want to control all four channels, I need a way to set the PWM frequency differently for the white channel than for the color channels. Would this be possible? Thanks!

@blazoncek
Copy link
Collaborator

It would but you would need to modify source to your needs.
Look into bus_manager.h, BurPwm class.

@blazoncek
Copy link
Collaborator

Thinking of it if these are analog LEDs they really don't care about PWM frequency.
Advantage of 20kHz PWM frequency is that flickering on camera is less noticeable.
You may be fine with using WLED OOB on these LEDs.

@JHthe4
Copy link
Author

JHthe4 commented Apr 23, 2022

Thanks for your feedback! I guess I'll try first just like this and if not then look into the function.
I agree that it shouldn't make a difference to the LEDs themselves, but I'm not sure what the surrounding circuitry is like so I'd prefer to emulate the IC I'm replacing exactly if that's possible. It does seem like ESP8266 PWM is just done in software, so theoretically different clocks on different pins should be possible, and in fact I've found documentation in the NodeMCU SDK that supports it. Seems like it's doable.

@Laver
Copy link

Laver commented Jul 8, 2022

I believe with LEDC on the ESP32 lower PWM frequency results in a higher gray-scale bit-depth. 20kHz only has 4096 steps, Whereas 2.4kHz has 32768 steps. At least for ESPHome, this higher bit-depth results in much smoother dimming transitions.

Reference: https://esphome.io/components/output/ledc.html#recommended-frequencies

@softhack007
Copy link
Collaborator

There is some ongoing discussion about using higher PWM frequency and improved PWM resolution: #2868.

ewoudwijma added a commit to MoonModules/WLED that referenced this issue Jan 27, 2023
FX_2Dfcn.cpp.setUpMatrix:
- move upstream code to reset==true
- temp table for ledmaps (Idea by By @troyAircoookie#2642)

FX_2Dfcn.cpp: init loadedLedmap
@Jojo-A
Copy link

Jojo-A commented Jan 4, 2024

Hi,
I'd also like to have the possibility to change pwn frequency because when I am sitting next to my led strips I can hear this very high peeping sound. And this is really annoying.
I can imagine that it could be difficult to make this separately for all channels if the white correction math is based on that.
So I would propose the compromise that the frequency can be set in a defined range (or to several predefined values) for all channels together. This would simplify the math.

@blazoncek
Copy link
Collaborator

You can compile your own version with modified/changed frequency. There is no need to modify source files for that.
Until such thing is added to configuration.

@Jojo-A
Copy link

Jojo-A commented Jan 4, 2024

You can compile your own version with modified/changed frequency. There is no need to modify source files for that. Until such thing is added to configuration.

Thank you for pointing that out.
Apart from the option to compile a version by myself I do not yet fully agree with your argumentation. You talk about "no need". But who defines what is "needed"? Nobody "needs" WLED in the first place - although I really love it and appreciate it!
Now I raise something that could be improved because there are people like my who are sensible to high audible frequencies.
I partially agree that the noise is of course totally irrelevant for the main purpose of WLED to create beautiful lights.
But please don't reject improvements only because they are "not needed".

Considering that PWM is generated by software I like to ask the following:

  1. is there a specific reason to choose exactly that PWM frequency (like resolution or so)?
    if yes: please describe the reason and I am immediately willing to accept that
    if no:
  2. what will be the highest possible frequency without running into trouble (like loss of resolution)?

Again, if there is a good reason for something I will definitely accept that. But if things can be improved with relatively low effort without noticeable disadvantages, why not adapting them?

Cheers

@softhack007
Copy link
Collaborator

softhack007 commented Jan 4, 2024

  1. is there a reason to choose exactly that 880 Hz as PWM frequency (like resolution or so)?

In fact, there is a reason - if you are using 8266. The chip cannot run 8bit PWM at higher frequencies than ~900hz.
ESP32 on the other side defaults to 19.5Khz PWM, which is also close to the max capabilities of the chip.

Edit: The LED strip usually does not create any sound - PWM is a pure electrical thing. But some Power Supply Units will not work well with PWM - these may beep, its called "coil whining". Sometimes it helps to choose a higher quality PSU.

@Jojo-A
Copy link

Jojo-A commented Jan 4, 2024

In fact, there is a reason - if you are using 8266. The chip cannot run 8bit PWM at higher frequencies than ~900hz.
ESP32 on the other side defaults to 19.5Khz PWM, which is also close to the max capabilities of the chip

Okay, thats interesting. From other projects like tasmota or esphome I know that one can set somehow higher frequencies for soft-PWM. But anyway, maybe they they just deal with the fact that resolution gets down as a compromise. For one of my tasmota lights I set the frequency DOWN to 200 Hz which still causes some flicker if I move my eyes really fast, but now it does not peep anymore...

Edit: in fact the strip usually does not create any sound - PWM is a pure electrical thing. But some Power Supply Units will not work well with PWM - these may beep, its called "coil whining". Sometimes it helps to choose a higher quality PSU.

That is only partially true. Of course coil ringing occurs in many application, no doubt about that. Because also in these applications the coil is pulsed by some kind of signal - in many cases a PWM.
But the effect to produce a sound by pulsed current is in no way limited to "coil". It might occur in any kind of conductor that has the possibility to swing (part of my daily business in power electronics R&D).
I can prove the audibility of the PWM signal by at least three things:

  1. the noise can by located at the lamp and not the PSU (which is a few meters away).
  2. the noise is more or less exactly at 3520 Hz - what is basically that I would expect in an application with four channels at 880 Hz. (of course they do not just sum up - what I hear is the fourth harmonic because of overlay)
  3. the noise is loudest at 50% and virtually disappears at 100% (as to expect)
    So please lets finish the point to try to prove me wrong in what my ears hear ;) .

If we can't get higher in frequency because of loss of resolution or anything else: what about the option to go DOWN? Of course you might have to deal with flicker effects at some point. We all know this. But why not leaving this up to the user by providing this option? Then one can choose whatever fits best to the users requirements.

@softhack007
Copy link
Collaborator

softhack007 commented Jan 4, 2024

@Jojo-A I'm not interested to prove you wrong, especially I'm not going to argue about what you hear.
If 880hz on 8266 is hurting your ears, why not simply use an esp32 ?

btw, below is the source code responsible for setting PWM frequency.
As you can see, the PWM frequency can be defined with -DWLED_PWM_FREQ=xxx, so feel free to experiment with that.
We rely on standard analogWrite() or ledcWrite() for PWM output. No idea what tasmota or other software does for PWM.

If you have a clever idea on how make PWM faster, please feel free to create a PR

WLED/wled00/const.h

Lines 433 to 440 in 51b3d7c

// PWM settings
#ifndef WLED_PWM_FREQ
#ifdef ESP8266
#define WLED_PWM_FREQ 880 //PWM frequency proven as good for LEDs
#else
#define WLED_PWM_FREQ 19531
#endif
#endif

WLED/wled00/bus_manager.cpp

Lines 390 to 394 in 51b3d7c

#ifdef ESP8266
analogWrite(_pins[i], scaled);
#else
ledcWrite(_ledcStart + i, scaled);
#endif

WLED/wled00/bus_manager.cpp

Lines 291 to 323 in 51b3d7c

BusPwm::BusPwm(BusConfig &bc)
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
{
if (!IS_PWM(bc.type)) return;
uint8_t numPins = NUM_PWM_PINS(bc.type);
_frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ;
#ifdef ESP8266
analogWriteRange(255); //same range as one RGB channel
analogWriteFreq(_frequency);
#else
_ledcStart = pinManager.allocateLedc(numPins);
if (_ledcStart == 255) { //no more free LEDC channels
deallocatePins(); return;
}
#endif
for (uint8_t i = 0; i < numPins; i++) {
uint8_t currentPin = bc.pins[i];
if (!pinManager.allocatePin(currentPin, true, PinOwner::BusPwm)) {
deallocatePins(); return;
}
_pins[i] = currentPin; //store only after allocatePin() succeeds
#ifdef ESP8266
pinMode(_pins[i], OUTPUT);
#else
ledcSetup(_ledcStart + i, _frequency, 8);
ledcAttachPin(_pins[i], _ledcStart + i);
#endif
}
_data = _pwmdata; // avoid malloc() and use stack
_valid = true;
}

@Jojo-A
Copy link

Jojo-A commented Jan 4, 2024

Okay perfect, thank you!
I will definitely try to compile a version with modified frequency. I am currently just reading through the docs how to set up the development environment.

About PR: I will try to compare the way how PWM is generated in different projects. Lets see what I can find.
But in the meantime it might be still worth to think about a way to modify the PWM frequency during runtime in WLED. If this structure exists and works it will be just a matter of ho to define the min and max thresholds for this setting. So I am basically not interested in increasing the frequency at all costs - I am more interested in being able to modify it in general :) .
Cheers

@softhack007
Copy link
Collaborator

👍

To get you started with using the development env (i.e. VSCode+platformIO) look into our KB

@Jojo-A
Copy link

Jojo-A commented Jan 7, 2024

Okay, I've set up a minimal platformio core environment for compiling WLED sources.
That works so far.
To be on the safe side I've added -D WLED_PWM_FREQ=250 to the compile options as well as the pre-processor macro #define WLED_PWM_FREQ 250.
To my surprise: both did not do anything -_o !
So I went into the code and change the line 296 in the file WLED/wled00/bus_manager.cpp to
_frequency = 250;
This led to the desired result to reduce PWM frequency.
This means, that the variable bc.frequency blocks the pre-processor macro for PWM to be used as long as the variable bc.frequency is != 0.
So either I have not understood the logic behind all that (what might definitely be the case ;) ) or it is a bug that prevents the WLED_PWM_FREQ macro to be used because the variable bc.frequency is != 0.
Any idea about that?

Thank you!

By the way: the really annoying peep sound has disappeared now. The flickering is fast enough that it is only noticeable when I move my eyes really fast.

@blazoncek
Copy link
Collaborator

Setting custom PWM frequency is already implemented in WLED but it lacks UI (only available for 2 pin digital LEDs).
Just edit cfg.json and update "freq" field for chosen output to the desired PWM frequency in Hz.

@Jojo-A
Copy link

Jojo-A commented Jan 7, 2024

Setting custom PWM frequency is already implemented in WLED but it lacks UI (only available for 2 pin digital LEDs). Just edit cfg.json and update "freq" field for chosen output to the desired PWM frequency in Hz.

Okay, that was much too easy XD ! Sorry for the irritation caused!
Thanks a ton, that is perfect!

@blazoncek
Copy link
Collaborator

We do have PayPal links if you feel generous. 😉

@blazoncek blazoncek added the workaround The issue contains a workaround label Jan 8, 2024
@blazoncek blazoncek added this to the 0.15.0-alpha candidate milestone Feb 26, 2024
@blazoncek blazoncek added the fixed in source This issue is unsolved in the latest release but fixed in master label Feb 26, 2024
@blazoncek
Copy link
Collaborator

Changing PWM frequency is now possible in 0.15.0 beta 1 or later.
It also includes 12bit PWM duty cycle resolution improving on low brightness dimming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement fixed in source This issue is unsolved in the latest release but fixed in master workaround The issue contains a workaround
Projects
None yet
Development

No branches or pull requests

5 participants