Hi, running the ESP8266 to control an RGB LED set via PWM on pins 12, 13, 15 using analogWrite().
When setting very low PWM values (<5), there is occasional flickering of the LEDs (the light turns to full brightness for a noticeable moment). Sometimes this is reinforced by network traffic, sometimes it happens without any apparent activity. The flickering is unrelated to the time when analogWrite() is called.
It helps a little to reduce the PWM frequency from 1KHz to 200Hz, but the flickering still happens from time to time.
I am aware that the PWM is based on a timer IRQ, not a hardware implementation, and I presume this issue is triggered by some other part of the code (wifi? tcp?) disabling interrupts for a short moment, leading to the timer interrupt being missed.
Unfortunately, the code in core_esp8266_wiring_pwm.c is not well documented and it's hard to understand for an outsider what exactly is happening there.
Would it be possible to mitigate the issue in the timer code? Maybe change it from edge- to level triggered or have the ISR called more often?
There is a $15 open bounty on this issue. Add to the bounty at Bountysource.
Timer interrupt is edge triggered — this is part of the chip design and it is not possible to change it in software. I suppose using NMI for PWM would fix this problem because NMI is higher priority than WiFi interrupts.
Would it be possible to try that out with moderate overhead? s/timer1/???/ in the pwm source?
You may try replacing ETS_FRC_TIMER1_INTR_ATTACH(timer1_isr_handler, NULL)
with ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1_isr_handler)
in core_esp8266_timer.c, line 45. Not sure if it will work though.
edit: Most likely there will be issues because ETS_FRC1_INTR_DISABLE will no longer work.
Replacing the regular interrupt with NMI leads to a watchdog reset ~10 seconds after startup:
ets Jan 8 2013,rst cause:4, boot mode:(1,6)
wdt reset
I even tried feeding the (soft) dog with system_soft_wdt_feed from the ISR, to no avail. It seems there is no function to feed the hardware watchdog, though.
Setting the timer to TIM_LOOP doesn't seem to improve the situation either - I hoped that a repeat of the ISR if it was missed will actually lead to some useful results.
I think I'll try the pwm_* functions from the official SDK next; let's hope they have some magic sauce to provide better stability.
As I mentioned, current implementation will have issues with NMI because it relies on a "critical section" implemented using ETS_FRC1_INTR_DISABLE. So the right thing to do would be fix this by disabling the timer or detaching NMI interrupt for the duration of the critical section.
I'm not sure this has to do with the PWM critical section at all. Merely adding a ETS_FRC_TIMER1_NMI_INTR_ATTACH(noop_function); to the code leads to a wdt reset. It rather seems to me that the espressif code is using an Nmi handler internally for watchdog purposes, and as long as we don't know which function was added as the Nmi handler, we can't just override it (without calling into it from our own handler).
I'd like to help out with that, but my knowledge of the platform and the different SDKs is rather limited. I'd be glad to get one or two pointers in the right direction.
P.S: When using the IoT_Demo from 1.3, the PWM is much more smooth and reliable, and it's got a usable value range of ~ 0..22222.
Hmm, I tried this early this weekend, and I found the flickering.
Analyzing the code I saw that we block the interrupt of the timer while we're copying the old values to the new ones (so the timer won't get half-copied info).
Also, I found that flickering is more likely to happen while you're doing heavy operations over the flash.
I think that a good strategy, and probably no NMI needed:
1) Move all the ISR/PWM the code to ICACHE RAM, so there's no issues with caching, and blocked flash.
2) Instead of disabling the interrupt for mutex, I'd do a mutex via a flag.
a) The setter code, waits for the flag to be clear, before trying to set any new values,
b) Set's the new value in a set of structures (mailbox-like),
c) Set's the flag
d) ISR updates PWM with any value it already had (to avoid any jitter)
e) ISR finds the flag, and copies the new values to a final structure it will use.
f) ISR clears the flag.
Does it sound reasonable?
I'm fixing the first part (moving handlers to RAM), commit coming in a few minutes.
Your approach with a flag does sound reasonable, actually it's the right way to go even if we are going to use NMI. I think NMI is necessary because otherwise we have flickering when there is heavy WiFi traffic.
First part pushed, fixing #819.
Wow, this really is a significant improvement! I'm test running the new code now and it looks much more stable.
I'm still experiencing a slight flickering when the PWM values get changed (i.e. when running a color fader), and a more noticeable flickering when one of the PWM values is switching between 0 and non-0, which seems to trigger a longer code path.
I wonder if it would be acceptable to mark all of the routines behind analogWrite as ICACHE_RAM_ATTR to solve the first problem.
I hope the second problem will be addressed with the flag-based ISR rewrite.
I'm experiencing the same issue with GPIO0 and GPIO2. ESP8266 is listening for POST requests and changes the value accordingly so that means that when the change happens, there is some network load. My knowledge is very limited on the ESP8266 so I don't know if I can be of any help troubleshooting this, however I can test the patches.
I'd be glad to help though my knowledge is limited, can you point me where to start and what should be done?
same here.. sketch to reproduce:
const int pin = 13;
void setup() {
pinMode(pin,OUTPUT);
Serial.begin(115200);
}
void loop() {
analogWrite(pin, 1);
delay(10); //to not overload esp8266
}
btw.. same flickering on analog Values >= 1019 as on <=4
edit:
value 5 and 1018 also has flickering.. but very rarely, compared with the other values..
edit2:
value 6 and 1017 also flickering.. but very very rarely... like 2-3 times an hour or so..
Using master branch is a lot better than the releases however some flickering still occur on network trafic, it's blinking once then back to the correct PWM setting.
I am experiencing the same flickering on ESP-03s.
@igrr : I have several ESP-8266 LED faders that have been running for several months with LUA code. I have never seen any glitching there, so I am not so certain if this is really only a HW issue?
My workaround until further will be to make sure the code avoids the sensitive value intervals.
This isn't a hardware issue. @mangelajo described software changes that need to be done pretty accurately.
Can you give more guidance on how to fix that? I'll gladly help but I'm not
sure where to start and what needs to be done.
I found a workaround that seems to work well for me:
The default PWM frequency is 1000 Hz. By reducing to 200 Hz I got rid of the flickering on my module. (I tested step by step until the flickering disappeared).
PWM frequency is set to 200 Hz by this code:
analogWriteFreq(200);
thx a lot for sharing this workaround...
seems to fix the given problem of random flickering..
BUT opens another problem: 200hz seems to be too low to give a smooth output.. no random flickering of different brightnes anymore.. but continue flickering because of too low frequency..
I know 200 Hz is a bit low but on the ESP-03 I use I find the output to be smooth except for the very lowest setting, when the light is anyway almost invisible. So for me, the workaround is fully acceptable and without any noticeable drawback.
i´ll take a look at a low-pass filter for me.. but this is not ideal..
EDIT:
nevermind.. i just tested.. analogwrite value of 1.. with 200hz..
there are still brightnes flicker sometimes...
so.. problem still exists.. also at 200hz
issue still exists, flicker to full o/p when there is network traffic, i notice it when using more than 3 pwm channels, seems ok at 200hz up to 3ch i need 4 channels (rgbw with mqtt) and pca9685 will be over kill although i found it to work great
i have the problem too, i need to control 5 pwm output (3 leds, 2 fans) from mqtt messages, but each wifi transmission flicker all leds (and make the fan noisy during the transmission). i need to use a high pwm frequency for the fan, so workaround are not good for my usage.
I hope somone with a high esp8266/C++ developpement skill will find a solution
i have found cheap pca9685 and i'll be going that route, advantage is that led's remain running on last state even if esp reboots
Good idea to use a PWM driver chip. An alternative is TLC5940, which I used in a previous project. I do not have hands-on experience with the PCA9685.
@krissfr : I think you need a hardware workaround here, so you could take a look at those two chips.
wtf? a workaround with additional hardware in an issue about a softwarebug?
guys.. this is not acceptable
@demlak
+1 and full ack ...
@demlak @tuxedo0801 i agree, it is far from ideal. My SW workaround is to reduce the frequency to 200 Hz and avoid the smallest values. In cases where the reduced frequency do not work, I think a HW workaround is better than very annoying flickering - until some wizard fixes the software bug.
maybe this is acceptable for you.. but not for the issue
Any news on getting access to a NMI timer on arduino? @igrr what/where is this critical section, I could have a stab at coding the workaround you deacribed.
I've been experimenting with getting access to the bare timer but keep getting watchdog resets, code here: https://github.com/larsenglund/esp8266_arduino_nmi_timer
Using it at 20Khz or 15Kkhz or 12Khz and 8-bit PWM I get an ok result for all values except for 254 that is like 0 value (not a good thing (tm) if you are driving a motor's PID). Lowering the freq to 10Khz seems to get back to the right behaviour.
I`ve been experimenting with PWM for fading LEDs. I am using 5 channels and I only experience the flickering when (cross)fading the channels.
It for some reason seems that triggering several analogWrite changes inflicts timer/value issues. For me the flickering appears to be that either the Duty cycle is 0 or 100 - and thus a visible flicker occurs
Do you guys know how the pwm from the ESP SDK is working? Is it even possible to use it as an alternative ?
I'm also experiencing the flickering when doing fading on multiple channels in parallel, and it seems not to be related to small/large values (I did some capping experiments to no avail).
The ESP SDK pwm is rock-solid. It can be used with the IoT_Demo example, which allows very smooth multi-channel fading. Unfortunately, I have no idea how it is realized internally, besides of vague NMI hints.
I have seen severe flickering (bright flashes while fader set to almost zero) with only one channel. After reducing frequency, the light is pulsating when fader set low. Visible but acceptable. I have never seen such issues on my RGBW (4 channels) fader modules running LUA firmware, But programming with Arduino IDE is such a big advantage that I prefer to go in that direction.
Wouldn`t it be possible to create a wrapper around the SDK PWM ? Or will this brake things?
I am researching currently how to include the sdk pwm and use it instead of analogWrite - if anyone has any hints on this?
running the pwm at low values is still an issue for me, since I don't know how to fix this.
https://www.bountysource.com/issues/27026077-pwm-flickering-with-small-analogwrite-values
Somebody said, that the sdk pwm would be very solid, adding that into the core might solve this...
I haven't tried this code, but maybe this works better...
https://github.com/FastLED/FastLED/blob/8412262567e162eebcb9baa07c6ab1312185a92f/platforms/esp/8266/clockless_esp8266.h
@kaeferfreund
The linked part of the FastLED library is for leds driven via spi and not pwm.
I can confirm that utilizing the SDK PWM is solid and I did not experience any of these reported issues here. The downside is - right now I am not able to use SDK PWM with Arduino IDE (see #1654).
I am not too familiar with the Arduino changes/structure/specifics - after including the library files (lpwm) it will compile - yet I can not initialize it - always results in a WDT reset. I gave up trying to solve this with Arduino IDE and switched to SMING - framework compatible to Arduino Functions and most Arduino libraries are also compatible.
yap, I have:
for (uint16_t i = 1; i < brt; i++) {
analogWrite(PIN1, i);
analogWrite(PIN2, i);
yield();
}
But I also have some web sockets-stuff going on, which is a bit slower but still to fast...
Just switched to SDK-pwm, seems like this also is fading a bit slower than arduino-pwm
One more thing:
If revert the changes back to the non-NMI timer settings, the PWM completely stops working...
Even if I redownload the whole esp core and reflash it.
Seems that there is an issue with detaching the timer...
That goes away, if I properly reset the ESP
Change I made, but later reverted:
from ETS_FRC_TIMER1_INTR_ATTACH(timer1_isr_handler, NULL) to
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1_isr_handler)
About watchdog reset thing: If I drag my web sockets brightens slider very slowly, I don`t get a reset.
ESP12-e is running on 160 Mhz CPU, 80 Mhz Flash, QIO which worked like a charm with the "old" PWM. Had over 30 days of stable daily usage
today I've been working a bit on this issue and I found that the second TEIE |= TEIE1; in "core_esp8266_wiring_pwm.c" seems to cause the issue. But since this line enables the edge trigger, without that line, pwm won't work. So that needs to be part of the Interrupt Service Routine...
Does anybody have an idea?
here is an attempt at this: https://github.com/esp8266/Arduino/pull/2299
with default values you get the maximum that the software can do, or:
Thanks A LOT! I will test it when I come home tonight.
Edit:
Although I can't see why this implementation could be slower than the other one, I had the old (non nmi) version running at a range of 19560 and 1khz frequency. Which is close to what espressif claims in their sdk documentation...
just wondering why there is such a huge difference...?
A friend and I are building an LED panel for photographic use and the flickering issue was a significant problem. We've been monitoring this thread and we were excited to see this fix. I went ahead and tried this (via the current git dev master branch) without changing the values we had been using (66Hz and 12 bit resolution, 160MHz CPU) and it works great! We select the LED brightness using the following table:
const uint16_t PWM_duty_cycle [] = {0, 1, 2, 3, 4, 6, 9, 13, 19, 28, 40, 58, 83, 118, 168, 238, 339, 482, 686, 978, 1382, 1996, 2874, 4095};
I'll look at the code now to see what happens with this frequency and resolution value as currently the the light output of index values 1 & 2 are the same as well as 3 & 4. Starting with index value 5 (pwm = 6) each successive increase in value in the table results in the expected 2 stop increase in light output. With virtually no flicker at any index value. So we have some adjustments to do but this fix looks solid and was a huge help.
BIG THANK YOU to @me-no-dev for this fix.
Follow up to Rom3oDelta7's note. Our LED panel dimmer for night photography, while set to 66 Hz and 12-bits (4095), actually measures at a period of 74.6 Hz, and the length of the duty cycle shortens very well all the way down to a duty cycle of 1, with all of the low values working properly. Where the prior code showed frequent jumping up from 4 uS to ~6uS, at a duty cycle of 1, the new code show NO jumping up, and only an occasional very quick dropout, maybe missing one period now and then. This fixes the issue for me! And a BIG Thanks!
@kaeferfreund I can not get the ISR to take less than 100-130 cycles and you have to add time between interrupt and jumps as well, so all in all there is some 2us wasted in code and switching (at 80MHz). With those numbers you can see how the ISR can not be called often enough to actually give you that high of resolution.
@Rom3oDelta7 @dml1333 Thank you for confirming this "fix" :) Glad it's working for you
Okay didnt know that. Thx for the explaination.
How can espressif then claim their sdk pwm has 22.222 range and 1khz frequency?
Am I misunderstanding something here?
Sorry it took me so long to test everything. For now me-no-dev's claims are very accurate. I can't run the pwm any faster than the 1khz at 10 bit resolution.
It's quite surprising, that the non NMI pwm is so much faster. I can run it at 19560 resolution and 1khz frequency with no problems.
I also noticed, that my LEDs are flickering slightly on wifi traffic (I use the async web server lib), which seems similar, maybe even a bit worse than on the non NMI Version. But as far as stability is concerned, things look rather good. No trouble so far.
I'll try to speed up pwm stuff a bit in the upcoming days...
@kaeferfreund how did you test that 1kHz 19560 resolution? Was there any difference between values that are close?
I calculated and constrained the functions to the point where there is actual difference between samples and that they are not too close to cause WDT and other issues.
Also I ran a test here with my scope to see if there is any fluctuation in the pulses and I saw sometimes some nanoseconds being added which will not be really visible or noticeable.
Other than that the pulses were being really steady regardless of the given input value.
Here's a non-LED-related issue.
A silly thing is that in idolpx/mobile-rr#1, the calls to analogWriteFreq() and analogWrite() all work fine _before_ websockets happen. Specifically, when attempting to play the song from a WS console (which is triggered by an event handler), the buzzer does nothing.
I haven't taken a closer look at that port with my bus pirate or xprotolab, though. worth doing?
I tried dumping @me-no-dev 's patch into ~/.platformio/packages/framework-arduinoespressif/cores/esp8266/, cleaned my build, and uploaded the result, but there was no difference--I'm not entirely convinced core_esp8266_wiring_pwm.c actually got recompiled, though...
Are there any documents about the reigsters and the codes? It's hard to understand for an outsider what exactly is happening there.
Hello Guys,
I think that another issue can be connected with this one. I'm speaking about https://github.com/esp8266/Arduino/issues/2477
I faced almost random WDT resets when I used fade of onboard led + WiFi communications. Fade means PWM.
Hi!
I found a code that works extremely well, i tested it for 4 channels ~20KHz and custom wifi pockets for rc remote control. The pwm is very stable with the nmi interrupt mode while the module receiving 1700 pockets/second! Be sure that the wifi is initialized before the pwm or the esp crashes.
Link for the code: https://github.com/StefanBruens/ESP8266_new_pwm
Have fun!
Hello,
I had serious problems with flickering when I fade my LEDs. PWM seems not to flicker when the LEDs are dimmes to a certain value, only when analogWrite is called with changing values.
I completely solved it by disabling interrupts before calling analogWrite and re-enable afterwards. There's my minimal sketch:
void setup() {
analogWriteFreq(1000);
pinMode(D1, OUTPUT);
pinMode(D2, OUTPUT);
pinMode(D3, OUTPUT);
Serial.begin(115200);
Serial.println(PWMRANGE);
}
int value=0;
int delta=1;
void loop() {
value+=delta;
if (value>1023) {
value=1023;
delta=-delta;
} else if (value<0) {
value=0;
delta=-delta;
}
noInterrupts();
analogWrite(D1,value);
analogWrite(D2,value);
analogWrite(D3,value);
interrupts();
delay(1);
}
Without noInterrupts/interrupts it flickers like hell. My guess is that it is a race condition when writing new pwm value while PWM interrupt is executed.
Regards,
Michael.
Update: Flicker occurs again for some reason on my sketch when there's network traffic ;-(
I have switched my sketch to use https://github.com/StefanBruens/ESP8266_new_pwm. I use a period of 5000 which gives me perfect 1kHz pwm. No flicker at all, works like charm.
Only drawback is that the API is not as clean as analogWrite().
IMO you really should replace the current implementation by this one.
@micw Does https://github.com/StefanBruens/ESP8266_new_pwm mean you switch to the ESP8266 SDK?
@simonliu009 no, you can still use arduino ide with esp8266 extensions.
Hi,
I made one sample to use the https://github.com/StefanBruens/ESP8266_new_pwm in Arduino.
See it in: https://github.com/JoaoLopesF/ESP8266-Arduino-PWM-SDK-Sample
Only this works fine to me.
Regards,
Joao
@igrr I see two possibilities here: migrate to the assembly pwm, or finish the original proposal with the flag.
What are your thoughts here?
ESP8266_new_pwn is GPLv2, so we can't use it here, unfortunately.
Fixing the race condition in the existing code should be a feasible option, i think.
@igrr I opened an issue there asking if the license can be changed to the same one in this repo. If so, we can continue that part of the discussion, and maybe contrast the two approaches. If not, so be it, we stick to the original plan.
Does that sound good?
Thanks, that sounds good.
On Fri, Oct 20, 2017 at 12:39 PM, Develo notifications@github.com wrote:
@igrr https://github.com/igrr I opened an issue there asking if the
license can be changed to the same one in this repo. If so, we can continue
that part of the discussion, and maybe contrast the two approaches. If not,
so be it, we stick to the original plan.
Does that sound good?—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/esp8266/Arduino/issues/836#issuecomment-338104236,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AEJcejLbuzvOoUvYXM6OKQ4A6kMOWr4aks5suCQFgaJpZM4GFktw
.
+1s are now and currently needed at @devyte's issue in ESP8266_new_pwn
@earlephilhower does #4640 address this?
@devyte A quick test shows no flickering for a few minutes at 1023/1024 value, but this is something I'd hope someone with a real DSO or logic analyzer could test (set a trigger on a pulse > than 20us and let it run overnight at 123/1024).
const int pin = LED_BUILTIN;
void setup() {
pinMode(pin,OUTPUT);
analogWriteFreq(1000);
analogWriteRange(1024);
}
void loop() {
analogWrite(pin, 1023);
delay(10); //to not overload esp8266
}
Also see PWM was NMI (whereas Tone() and Servo() were not) in the original code. The current waveform generator is not NMI, so can have that ~10us or so jitter under heavy load. Doesn't cause visible changes, but this may be more than the old code was producing since it was guaranteed CPU priority/ It's a 2-line change to go to NMI, but unless we hear of some specific issue I'd rather not use NMI as I don't have enough info on how it would affect the WiFi and other parts of the chip.
@earlephilhower I don't think a DSO is needed to close this issue. The original description talks about visible flickering of an RGB led. I suggest just testing for visible flickering under heavy WiFi load, such as @d-a-v 's stress test, on a board that has an RGB led like the WittyCloud or similar. If no flickering, we're good.
Per discussion with @earlephilhower and his test results, this is not reproducible. Closing.
sorry, It's possible create a pwm with 5 hz frequency to esp8266?
I have the same question of @crywolf87
Anyone have a solution?
sorry, It's possible create a pwm with 5 hz frequency to esp8266?
see the Arduino standard BlinkWithoutDelay example. it is 1 Hz. change the interval to 200 and you get 5 Hz
Most helpful comment
I have switched my sketch to use https://github.com/StefanBruens/ESP8266_new_pwm. I use a period of 5000 which gives me perfect 1kHz pwm. No flicker at all, works like charm.
Only drawback is that the API is not as clean as analogWrite().
IMO you really should replace the current implementation by this one.