Skip to content

WS2805 RGBCCT flickering at specific brightness/color combinations on ESP32 / WLED 16.0.1 #5877

Open

Description

@jlt24

What happened?

I'm using 168 WS2805 RGB+CCT pixels with a QuinLED Dig-Quad running WLED 0.16.0.1.
I occasionally noticed very brief flashes from white LEDs that should not be illuminated. I was able to narrow this down to particular combinations of master brightness and color/CCT state.
The issue is especially reproducible with master brightness values 126–130 / 255. At brightness 128, a saved preset can reliably reproduce the flickering.
Known flickering state:

{
  "bri":128,
  "seg":[{
    "id":0,
    "bri":255,
    "cct":127,
    "col":[
      [255,206,166,0],
      [8,255,0,0],
      [0,0,0,0]
    ],
    "fx":0
  }]
}

Making a very small adjustment to the Kelvin/temperature slider stops the visible flickering without changing master brightness.
Stable state after that adjustment:

{
  "bri":128,
  "seg":[{
    "id":0,
    "bri":255,
    "cct":127,
    "col":[
      [255,214,177,0],
      [8,255,0,0],
      [0,0,0,0]
    ],
    "fx":0
  }]
}

Reloading the original saved preset causes the flickering to return.

Additional observations:

  • Brightness 126–130 produces the issue most noticeably.
  • Values immediately outside that range appeared stable during short tests.
  • A very small Kelvin/temperature adjustment can eliminate the flicker.
  • Sometimes the expected bad state doesn't immediately flicker, but changing to blue and then back to white causes it to return.
  • The visible flashes appear to come from white emitters that should otherwise be off.
  • This occurs directly from the WLED web interface, independent of Home Assistant/MQTT.
  • Solid effect (fx:0) reproduces it.
  • 168 WS2805 RGB+CCT pixels.
  • GPIO 16.
  • The problem appears related to the combination of brightness and color/CCT rather than brightness alone.
    Possibly related to Flickering - WS2805 - ESP32 C3 mini #5198, although that report is using ESP32-C3 while this setup uses a Dig-Quad/ESP32.

To Reproduce Bug

Hardware:

  • QuinLED Dig-Quad / ESP32
  • 168 WS2805 RGB+CCT pixels
  • WLED 0.16.0.1
  • WS2805 RGBCCT configured as the LED type
  • Data GPIO 16

I can reproduce the flickering using the following steps:

  1. Set the effect to Solid.
  2. Set the master brightness to 128/255.
  3. Set the LEDs to a warm white color.
  4. With the following state, some of the white emitters that should not be illuminated will intermittently flash:
{
  "bri": 128,
  "seg": [{
    "id": 0,
    "bri": 255,
    "cct": 127,
    "col": [
      [255, 206, 166, 0],
      [8, 255, 0, 0],
      [0, 0, 0, 0]
    ],
    "fx": 0
  }]
}

Expected Behavior

No flicker

Install Method

Binary from WLED.me

What version of WLED?

0.16.0.1

Which microcontroller/board are you seeing the problem on?

ESP32

Relevant log/trace output

Anything else?

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Activity

  1. softhack007 commented on Oct 1, 2026

    @softhack007
    Member

    @coderabbitai please review the code paths related to WS2805 RGB+CCT, and check if there are some numerical instabilities or uninitialized value access that could explain the white channel flickering.

  2. changed the title [-]WS2805 RGBCCT flickering at specific brightness/color combinations on ESP32 / WLED 0.16.0.1[/-] [+]WS2805 RGBCCT flickering at specific brightness/color combinations on ESP32 / WLED 16.0.1[/+] on Oct 1, 2026
  3. coderabbitai commented on Oct 1, 2026

    @coderabbitai
    Contributor
    🧩 Analysis chain

    🏁 Script executed:

    #!/bin/bash
    gh issue view 5877 --repo wled/WLED --json title,body,comments
    git rev-parse HEAD
    rg -n -C3 -i 'ws2805' .
    fd -i 'bus|color|platformio|neo' -t f | head -100

    Length of output: 48822


    🏁 Script executed:

    #!/bin/bash
    ast-grep outline wled00/bus_manager.cpp --items all
    ast-grep outline wled00/bus_manager.h --items all
    ast-grep outline wled00/bus_wrapper.h --items all
    ast-grep outline wled00/colors.cpp --items all
    rg -n -C3 'NeoPixelBus|makuna|neopixel|WLED_USE_PARALLEL|RMT' platformio.ini
    rg -n -C4 'calculateCCT|autoWhite|RgbwwColor|restoreColor|setBrightness|setPixelColor|_data|_cct' wled00/bus_manager.cpp | head -260
    rg -n -C3 'RgbwwColor|SetBrightness|SetPixelColor|GetPixelColor|2805_5|restoreColor' wled00/bus_wrapper.h | tail -190
    fd -i 'FX|json|cfg' wled00 -t f
    gh api repos/wled/WLED/tags --paginate --jq '.[].name' | head -35

    Length of output: 50983


    🏁 Script executed:

    #!/bin/bash
    git rev-parse v16.0.1
    git diff v16.0.1 HEAD -- wled00/bus_manager.cpp wled00/bus_wrapper.h wled00/colors.cpp | head -160
    nl -ba wled00/bus_manager.cpp | sed -n '70,180p;196,310p;1450,1475p;1523,1635p'
    nl -ba wled00/bus_manager.h | sed -n '98,128p;202,310p'
    nl -ba wled00/bus_wrapper.h | sed -n '775,915p;1306,1330p;1360,1425p'
    nl -ba wled00/colors.cpp | sed -n '73,105p;597,655p'
    rg -n -C3 'restoreColorLossy|mode_static|setSegmentCCT|gamma32|canAllShow' wled00/FX.cpp wled00/FX_fcn.cpp wled00/colors.h wled00/json.cpp
    ast-grep outline wled00/FX_fcn.cpp --match 'service|setPixelColor|setUp|setCCT|setBrightness|fill' --items all
    ast-grep outline lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h --items all
    ast-grep outline lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp --items all
    gh issue view 5198 --repo wled/WLED --json title,body,comments
    git show v16.0.1:platformio.ini | grep -n -C2 'NeoPixelBus'

    Length of output: 67720


    🏁 Script executed:

    #!/bin/bash
    python - <<'PY'
    import subprocess,json,base64,difflib
    paths=['wled00/bus_manager.cpp','wled00/bus_manager.h','wled00/bus_wrapper.h','wled00/colors.cpp','wled00/FX_fcn.cpp','platformio.ini']
    for p in paths:
        result=subprocess.run(['gh','api',f'repos/wled/WLED/contents/{p}?ref=v16.0.1'],capture_output=True,text=True)
        if result.returncode: print(p,result.stderr);continue
        text=base64.b64decode(json.loads(result.stdout)['content']).decode()
        print('\nRELEASE',p)
        diff=list(difflib.unified_diff(text.splitlines(),open(p).read().splitlines(),fromfile='v16.0.1',tofile='HEAD',n=2))
        if p in paths[:4]: print('\n'.join(diff[:220]))
        if p=='platformio.ini':
            for i,line in enumerate(text.splitlines(),1):
                if 'NeoPixelBus' in line: print(i,line)
        if p=='wled00/FX_fcn.cpp':
            lines=text.splitlines()
            for i,line in enumerate(lines):
                if any(x in line for x in ['void WS2812FX::show(', 'void WS2812FX::service(', 'void Segment::setPixelColor(int','void Segment::fill(', 'setSegmentCCT(', 'Bus::setCCT(', 'bus->setBrightness']):
                    print('\n'.join(f'{j+1}: {lines[j]}' for j in range(max(0,i-3),min(len(lines),i+20))))
    PY
    nl -ba lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h | sed -n '50,181p'
    nl -ba lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp | sed -n '228,327p;362,439p;472,515p'
    nl -ba wled00/FX_fcn.cpp | sed -n '1339,1380p;1740,1825p;1881,1910p'
    rg -n -C3 '_pixelCCT|_pixels =' wled00/FX_fcn.cpp | head -150

    Length of output: 54776


    🏁 Script executed:

    #!/bin/bash
    gh api repos/Makuna/NeoPixelBus/git/trees/1d7ff38f14d04a976f9c6e365c83a232bcba04fc?recursive=1 --jq '.tree[].path' | grep -E 'Rgbww|RgbwColor|5Elements|RmtMethod|I2sMethod|NeoPixelBus.h'
    ast-grep outline wled00/cfg.cpp --items all --match 'deserialize|serialize'
    ast-grep outline wled00/json.cpp --items all --match 'deserialize'
    rg -n -C4 'autoWhite|cctFromRgb|correctWB|cctBlend|milliAmps|driverType|gammaCorrectBri' wled00/cfg.cpp | head -180
    nl -ba wled00/bus_manager.cpp | sed -n '1487,1522p'
    nl -ba wled00/bus_wrapper.h | sed -n '610,628p'
    python - <<'PY'
    import subprocess,json,base64
    for p in ['wled00/colors.h','wled00/FX.cpp','wled00/FX_fcn.cpp','lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h']:
        r=subprocess.run(['gh','api',f'repos/wled/WLED/contents/{p}?ref=v16.0.1'],capture_output=True,text=True)
        if r.returncode: print(r.stderr);continue
        lines=base64.b64decode(json.loads(r.stdout)['content']).decode().splitlines()
        print('\nRELEASE',p)
        if p.endswith('NeoEsp32RmtHIMethod.h'): print('Matches HEAD:', '\n'.join(lines)==open(p).read().rstrip('\n'))
        ranges = {'wled00/colors.h':[(25,51)],'wled00/FX.cpp':[(133,139)],'wled00/FX_fcn.cpp':[(1380,1408),(1430,1465)]}.get(p,[])
        for a,b in ranges: print('\n'.join(f'{i+1}: {lines[i]}' for i in range(a-1,min(b,len(lines)))))
    PY

    Length of output: 16107


    🏁 Script executed:

    #!/bin/bash
    python - <<'PY'
    import subprocess,json,base64,difflib
    ref='1d7ff38f14d04a976f9c6e365c83a232bcba04fc'
    specs={
    'src/internal/features/NeoRgbwwFeatures.h':['class NeoGrbwwFeature','class Neo5','applyPixelColor','retrievePixelColor'],
    'src/internal/colors/RgbwwColor.h':['RgbwwColor(','uint8_t WW','uint8_t CW'],
    'src/NeoPixelBus.h':['void Begin(','void Show(','void SetPixelColor('],
    'src/internal/methods/NeoEsp32RmtMethod.h':['class NeoEsp32RmtSpeedWs2805'],
    'src/internal/methods/NeoEsp32I2sMethod.h':['class NeoEsp32I2sSpeedWs2805']
    }
    for p,patterns in specs.items():
        r=subprocess.run(['gh','api',f'repos/Makuna/NeoPixelBus/contents/{p}?ref={ref}'],capture_output=True,text=True)
        if r.returncode: print(r.stderr);continue
        lines=base64.b64decode(json.loads(r.stdout)['content']).decode().splitlines()
        print('\nDEPENDENCY',p)
        indexes=set()
        for i,l in enumerate(lines):
            if any(k in l for k in patterns): indexes.update(range(max(0,i-2),min(len(lines),i+24)))
        for i in sorted(indexes): print(f'{i+1}: {lines[i]}')
    for p in ['lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h','lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp']:
        r=subprocess.run(['gh','api',f'repos/wled/WLED/contents/{p}?ref=v16.0.1'],capture_output=True,text=True)
        if r.returncode: print(r.stderr);continue
        text=base64.b64decode(json.loads(r.stdout)['content']).decode()
        print('\nRMT RELEASE DIFF',p)
        print('\n'.join(difflib.unified_diff(text.splitlines(),open(p).read().splitlines(),n=2)))
    print('\nIndependent integer-arithmetic checks (not firmware execution)')
    for b in [0,1,126,127,128,129,130,254,255]:
        zero=((0+1)*b)>>8
        print('brightness',b,'zero-white after CCT scaling',zero)
    ww,cw=42,41
    limit=200
    w=max(ww,cw)
    recalc_ww=w*128//255
    recalc_cw=w*127//255
    print('ABL input WW/CW:',(ww,cw),'CCT=127, limit=200')
    print('Current ABL output:',(((recalc_ww+1)*limit)>>8,((recalc_cw+1)*limit)>>8))
    print('Direct channel scaling:',(((ww+1)*limit)>>8,((cw+1)*limit)>>8))
    print('CCT blend denominator bounds: exclusive 1..255, additive 128..255 (configured blend -127..127)')
    PY
    nl -ba wled00/bus_wrapper.h | sed -n '588,605p'
    nl -ba wled00/cfg.cpp | sed -n '218,257p'
    nl -ba wled00/colors.cpp | sed -n '656,673p'
    rg -n -C3 'cct|colors\[|col\[' wled00/json.cpp | head -95

    Length of output: 20705


    @softhack007 I reviewed the v16.0.1 release code, its pinned NeoPixelBus dependency, and the corresponding paths on current HEAD.

    I found an ABL white-channel conversion defect. I did not find an uninitialized read or numerical instability that directly explains the reported intermittent flicker. The ABL defect is a useful suspect if the current limiter activates near the reported brightness.

    1. ABL discards the original WW/CW values

    In BusDigital::applyBriLimit(), Line 234–Line 242 of bus_manager.cpp:

    1. PolyBus::getPixelColor() reduces the two white channels to W = max(WW, CW).
    2. calculateCCT() splits that reduced value into WW/CW again.
    3. The limiter scales the new WW/CW values.

    This applies the CCT split twice instead of scaling the existing channels.

    An independent arithmetic check illustrates the loss:

    Input WW/CW Limiter scale Current calculation Direct channel scaling*
    42 / 41 200 / 255 17 / 16 33 / 32

    *Using the existing CCT brightness-scaling formula.

    There is a second problem. WS2812FX::show() restores the previous global CCT before ABL runs. See Line 1727–Line 1735 of FX_fcn.cpp. Therefore, ABL can use a different CCT from the pixel’s segment CCT. If the restored CCT is -1, ABL derives CCT from the already processed RGB values.

    Expected impact: incorrect white brightness or WW/CW ratio when limiting activates. This can also introduce a discontinuity at the limiting threshold. It does not, by itself, establish why an unchanged Solid state would flicker intermittently.

    The appropriate correction is to scale the existing five output channels directly, without reconstructing and splitting W.

    2. The normal WS2805 path initializes its channel values

    I checked these apparent risks:

    • BusDigital::setPixelColor() initializes cctWW, cctCW, and wwcw.
    • PolyBus::setPixelColor() assigns all RGB fields. Its WS2805 branch constructs RgbwwColor with all five channel values.
    • The frame buffer is cleared before normal segment composition.
    • The per-pixel CCT buffer is initialized to 127.
    • Although the RMT method allocates its buffers with malloc(), the pinned NeoPixelBus::Begin() clears both buffers through SwapBuffers(). The allocation comments alone are misleading.

    I found no uninitialized white-channel read in those paths.

    3. The arithmetic preserves zero white

    For the configured CCT range, the CCT calculations use bounded integer arithmetic with nonzero divisors. approximateKelvinFromRGB() also guards the cases that could otherwise divide by zero.

    The white brightness formula is:

    ((channel + 1) * brightness) >> 8

    When channel == 0, the result remains zero for every brightness from 0 to 255. There is no zero-to-nonzero transition at brightness 128.

    However, preset W = 0 does not guarantee zero WW/CW output. Auto-white modes can generate white from RGB. The two presets do not include that configuration.

    Recommended next checks

    1. Check whether ABL activates in the failing state. Compare both presets with enough current headroom, within the hardware’s safe limits.
    2. Compare RMT and I2S on the Dig-Quad, with all other settings unchanged.
    3. Inspect the final five-channel buffer immediately before transmission. If WW/CW remain zero during a visible flash, investigate transmission timing, signal integrity, or the strip hardware.
    4. Provide the relevant hw.led and light.gc configuration sections. These identify auto-white mode, CCT derivation, white-balance correction, driver selection, and current limits. Omit network credentials.

    This was a source review with independent arithmetic checks, not a firmware or hardware reproduction. #5198 provides driver-related context, but its ESP32-C3 diagnosis does not establish the cause on this ESP32 setup.

    You are interacting with an AI system.

  4. softhack007 commented on Oct 1, 2026

    @softhack007
    Member

    @coderabbitai could the CCT discontinuity identified in #5862 (comment) contribute to the problem, or is it something unrelated?

  5. coderabbitai commented on Oct 1, 2026

    @coderabbitai
    Contributor
    🧩 Analysis chain

    🏁 Script executed:

    #!/bin/bash
    gh api repos/wled/WLED/issues/comments/5756777129 --jq '{body,html_url}'
    gh pr view 5862 --repo wled/WLED --json title,body,state,headRefOid,baseRefName,files
    gh pr diff 5862 --repo wled/WLED
    gh issue view 5877 --repo wled/WLED --json title,body,comments

    Length of output: 45916


    🏁 Script executed:

    #!/bin/bash
    gh api repos/wled/WLED/issues/5862/comments --paginate --jq '.[] | {user: .user.login, url: .html_url, body: .body}' 
    ast-grep outline wled00/bus_manager.cpp --items all --match 'calculateCCT|setPixelColor|show|applyBriLimit'
    rg -n -C5 'void Bus::calculateCCT|void BusDigital::setPixelColor|void BusPwm::setPixelColor' wled00/bus_manager.cpp
    python - <<'PY'
    import subprocess,json,base64
    r=subprocess.run(['gh','api','repos/wled/WLED/contents/wled00/bus_manager.cpp?ref=v16.0.1'],capture_output=True,text=True,check=True)
    lines=base64.b64decode(json.loads(r.stdout)['content']).decode().splitlines()
    for a,b in [(95,180),(196,250),(528,647),(1535,1640)]:
        print('\nRELEASE bus_manager.cpp')
        print('\n'.join(f'{i+1}: {lines[i]}' for i in range(a-1,min(b,len(lines)))))
    PY

    Length of output: 32136


    @softhack007 The specific discontinuity reported in #5862 is unrelated to the WS2805 output path.

    DedeHai’s later comment identifies the cause:

    • On ESP32-C5, LEDC does not carry a PWM pulse across the period boundary when duty + hpoint exceeds maxBri. The hardware cuts the pulse.
    • With PWM dithering, the additional pulse extension can also cross that boundary and temporarily latch the output high.

    That mechanism occurs in BusPwm::show(). WS2805 uses BusDigital and serial transmission through RMT or I2S. It does not use those LEDC duty, phase-shift, or dithering operations. The PWM inside the WS2805 IC is separate from the ESP32 LEDC peripheral.

    What can still be related

    Both bus types use Bus::calculateCCT(). However, the discontinuity in #5862 came from the PWM output stage, not from that shared calculation. My earlier reply on #5862 described the expected CCT curve but did not identify the hardware cause.

    The ABL CCT reconstruction defect from my previous analysis remains a separate suspect. If ABL activates, it can change the WW/CW ratio or brightness incorrectly. It still does not establish a cause for intermittent flashes.

    Also, both presets in #5877 retain cct: 127. The “temperature adjustment” changes RGB from [255,206,166,0] to [255,214,177,0]. Thus, the supplied states do not show the segment CCT crossing a blend boundary. If auto-white or CCT derivation from RGB is enabled, that RGB change can still change the white-channel output.

    The most useful next check remains the transmitted WW/CW values. If those values remain zero during a visible flash, neither the shared CCT calculation nor the ABL reconstruction directly generates that flash. Transmission or strip-side behavior then becomes the main investigation path.

    You are interacting with an AI system.

  6. jlt24 commented on Oct 1, 2026

    @jlt24
    Author

    Here are the requested hw.led and light.gc sections from the configuration that reproduces the issue. I have not changed ABL or the LED driver since reproducing the flicker.

    {
      "hw": {
        "led": {
          "total": 168,
          "maxpwr": 20000,
          "cct": false,
          "cr": true,
          "ic": false,
          "cb": 0,
          "fps": 42,
          "rgbwm": 2,
          "ins": [
            {
              "start": 0,
              "len": 168,
              "pin": [
                16
              ],
              "order": 1,
              "rev": false,
              "skip": 0,
              "type": 32,
              "ref": false,
              "rgbwm": 0,
              "freq": 0,
              "maxpwr": 0,
              "ledma": 83,
              "drv": 0,
              "text": ""
            }
          ]
        }
      },
      "light": {
        "gc": {
          "bri": 1,
          "col": 2.8,
          "val": 2.8
        }
      }
    }
  7. jlt24 commented on Oct 1, 2026

    @jlt24
    Author

    I tested the suggested RMT vs I2S comparison.
    My original configuration was using: "drv": 0

    which is RMT.
    With RMT, the installation generally operates normally. The reported flicker is primarily reproducible with the specific brightness/color state described above (particularly master brightness 126–130).
    I then changed only the LED hardware driver from RMT to I2S, leaving the LED type, GPIO, pixel count and other configuration unchanged.
    With I2S, the behavior becomes dramatically worse. The LEDs flash continuously/severely regardless of the preset, selected color, or brightness. I was unable to obtain stable output with I2S.
    I switched back to RMT afterward.

    I also checked /json/info while the original RMT flickering condition was actively occurring. WLED reported:

    "leds": {
      "count": 168,
      "pwr": 831,
      "fps": 43,
      "maxpwr": 20000
    }
  8. softhack007 commented on Oct 2, 2026

    @softhack007
    Member

    @coderabbitai the last comments by the user point more into the direction of LED timing issues #5264, that will (hopefully) be resolved when #5704 is ready to get merged into 17.0.0-dev.

  9. coderabbitai commented on Oct 2, 2026

    @coderabbitai
    Contributor
    🧩 Analysis chain

    🏁 Script executed:

    #!/bin/bash
    gh issue view 5264 --repo wled/WLED --json title,body,state,comments
    gh pr view 5704 --repo wled/WLED --json title,body,state,isDraft,mergedAt,baseRefName,files

    Length of output: 25575


    @softhack007 Thanks for the guidance. The new results make output timing or signal integrity the leading hypothesis for #5877.

    • Changing only RMT to I2S makes the flashing much worse. This points toward the output driver or transmitted waveform rather than the shared CCT calculation.
    • WLED reports an estimated 831 mA against a 20000 mA limit. This makes ABL activation unlikely in the reported state. The ABL conversion defect remains a separate issue, but it is now a weaker explanation for this flicker.
    • A narrow brightness/color trigger can still fit a transmission problem. Different channel values produce different serial bit patterns. This does not prove a timing fault, but it does not require an arithmetic discontinuity.

    #5264 documents driver-dependent flicker and differences between RMT and I2S timing. Its published timing measurements concern WS281x, so they do not establish the correct timing for this WS2805 strip.

    #5704 is a relevant test path, not yet a confirmed fix. It remains open and unmerged. It replaces NeoPixelBus with WLED Pixel Bus and provides timing adjustment from −30% to +30% in 10% steps.

    When a suitable test build is available, compare the same failing state with the new driver at default timing first. Then vary only the timing setting. A repeatable change in flicker would strengthen the timing hypothesis. A waveform capture at the strip input would help distinguish driver timing from signal distortion.


    ✏️ Learnings added
    Learnt from: softhack007
    URL: https://github.com/wled/WLED/issues/5877
    
    Timestamp: 2026-10-02T11:24:09.284Z
    Learning: For WLED issue #5877, the WS2805 RGB+CCT installation has 168 pixels on GPIO 16. The reporter observes narrow brightness/color-dependent flicker with RMT, but severe continuous flashing after changing only the driver to I2S. During RMT flicker, /json/info reports estimated power of 831 mA against a 20000 mA limit, making ABL activation unlikely in that state. Treat output timing or signal integrity as the leading hypothesis, not a confirmed cause. softhack007 identifies #5264 as relevant context and #5704 (WLED Pixel Bus replacement with adjustable timing) as a prospective test/fix path for 17.0.0-dev, not a proven resolution.
    

    Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

    You are interacting with an AI system.

  10. softhack007 commented on Oct 2, 2026

    @softhack007
    Member

    @jlt24 can you check if "off refresh" (LEDs settings) makes a difference for you? There are some strips that need continuous refresh, even when the effect looks static.

  11. softhack007 commented on Oct 2, 2026

    @softhack007
    Member

    @coderabbitai please check the neoPixelBus repo https://github.com/Makuna/NeoPixelBus for any hints about timing problems with WS2805 type chips.

  12. coderabbitai commented on Oct 2, 2026

    @coderabbitai
    Contributor
    🧩 Analysis chain

    🏁 Script executed:

    #!/bin/bash
    set -euo pipefail
    gh api 'search/issues?q=repo%3AMakuna%2FNeoPixelBus+WS2805&per_page=100' --jq '.items[] | {number,title,state,html_url,body}'
    gh api repos/Makuna/NeoPixelBus --jq '{default_branch,html_url}'
    gh api 'repos/Makuna/NeoPixelBus/git/trees/master?recursive=1' --jq '.tree[].path' | grep -Ei '2805|RmtMethod|I2sMethod|Esp32.*Method|timing'
    gh api 'repos/Makuna/NeoPixelBus/commits?path=src/internal/methods/NeoEsp32RmtMethod.h&per_page=15' --jq '.[] | {sha,message:.commit.message}'

    Length of output: 9440


    🏁 Script executed:

    #!/bin/bash
    set -euo pipefail
    for n in 764 782 791 794 806 865 795; do
      echo "=== DISCUSSION $n ==="
      gh api "repos/Makuna/NeoPixelBus/issues/$n/comments?per_page=100" --jq '.[] | {user:.user.login,html_url,body}'
    done
    for n in 794 806; do
      echo "=== PR $n ==="
      gh pr view "$n" --repo Makuna/NeoPixelBus --json mergedAt,body,files
    done
    python - <<'PY'
    import subprocess,json,base64,tempfile,os
    for ref in ['1d7ff38f14d04a976f9c6e365c83a232bcba04fc','master']:
        for path in ['src/internal/methods/NeoEsp32RmtMethod.h','src/internal/methods/NeoEsp32I2sMethod.h','src/internal/methods/NeoEsp32I2sXMethod.h']:
            r=subprocess.run(['gh','api',f'repos/Makuna/NeoPixelBus/contents/{path}?ref={ref}'],capture_output=True,text=True)
            if r.returncode:
                print(r.stderr);continue
            text=base64.b64decode(json.loads(r.stdout)['content']).decode()
            f=tempfile.NamedTemporaryFile(suffix='.h',delete=False,mode='w')
            f.write(text);f.close()
            print('\n===',ref,path,'===')
            subprocess.run(['ast-grep','outline',f.name,'--items','all','--match','Ws2805|Ws2814|Ws2812|I2sSpeed','--view','expanded'])
            lines=text.splitlines()
            selected=set()
            for i,line in enumerate(lines):
                if 'Ws2805' in line or ('I2s' in path and any(k in line for k in ['DmaBit','BitsPer','BitSend','I2S_BITS','SampleRate'])):
                    selected.update(range(max(0,i-4),min(len(lines),i+38)))
            for i in sorted(selected): print(f'{i+1}: {lines[i]}')
            os.unlink(f.name)
    PY

    Length of output: 195755


    🏁 Script executed:

    #!/bin/bash
    set -euo pipefail
    gh pr diff 794 --repo Makuna/NeoPixelBus | head -230
    python - <<'PY'
    import subprocess,json,base64,tempfile,os
    def api(endpoint):
        return json.loads(subprocess.check_output(['gh','api',endpoint],text=True))
    tree=api('repos/Makuna/NeoPixelBus/git/trees/master?recursive=1')['tree']
    paths=[x['path'] for x in tree if 'Bits' in x['path'] and x['path'].endswith('.h')]
    print('Candidate timing files:',paths)
    specs=[]
    for ref in ['1d7ff38f14d04a976f9c6e365c83a232bcba04fc','master']:
        specs += [('Makuna/NeoPixelBus',p,ref,['class NeoBitsSpeedWs2805']) for p in paths]
    specs += [('wled/WLED',p,'v16.0.1',patterns) for p,patterns in [
    ('lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h',['Ws2805','WS2805']),
    ('wled00/bus_wrapper.h',['NeoEsp32RmtNWs2805','NeoEsp32I2s','NeoEsp32RmtSpeedWs2805']),
    ('platformio.ini',['NPB_CONF_4STEP_CADENCE'])]]
    for repo,path,ref,patterns in specs:
        try: text=base64.b64decode(api(f'repos/{repo}/contents/{path}?ref={ref}')['content']).decode()
        except subprocess.CalledProcessError: continue
        lines=text.splitlines()
        hits=[i for i,l in enumerate(lines) if any(p in l for p in patterns)]
        if not hits: continue
        f=tempfile.NamedTemporaryFile(suffix='.hpp',delete=False,mode='w')
        f.write(text);f.close()
        print('\n===',repo,ref,path,'===')
        subprocess.run(['ast-grep','outline',f.name,'--items','all','--match','Ws2805'])
        indexes=set()
        for i in hits:
            # Limit bus wrapper output to WS2805 definitions and nearby routing.
            if path=='wled00/bus_wrapper.h' and 'Ws2805' not in lines[i]: continue
            indexes.update(range(max(0,i-3),min(len(lines),i+24)))
        for i in sorted(indexes): print(f'{i+1}: {lines[i]}')
        os.unlink(f.name)
    PY

    Length of output: 46531


    @softhack007 Yes. NeoPixelBus contains relevant timing hints. The strongest code-level hint is that its WS2805 RMT and I2S methods use different pulse widths. I found no confirmed upstream fix for the exact symptoms in #5877.

    1. RMT and I2S do not produce the same WS2805 waveform

    These definitions are unchanged between WLED’s pinned NeoPixelBus commit 1d7ff38… and the upstream master inspected:

    Method T0H T0L T1H T1L Reset
    RMT timing constants 300 ns 790 ns 790 ns 300 ns 300 µs
    I2S, default three-step encoding 375 ns 750 ns 750 ns 375 ns 300 µs
    I2S, optional four-step encoding ≈281 ns ≈844 ns ≈844 ns ≈281 ns 300 µs

    Sources: NeoEsp32RmtMethod.h, NeoBits.h, and NeoEsp32I2sMethod.h.

    The I2S values are calculated from its requested 1125 ns bit period and encoding proportions. They are not measured values. Hardware clock quantization can change the actual widths. RMT also quantizes its timing constants.

    WLED’s custom RMT method uses NeoEsp32RmtSpeedWs2805, so the upstream constants are relevant to this installation.

    This difference could explain why changing to I2S makes the fault much worse. It does not prove that either waveform violates the requirements of this particular strip.

    2. The maintainer explicitly reports WS2805 speed sensitivity

    In NeoPixelBus #865, Makuna states:

    “The WS2805 chip is a little particular about its speed”

    Makuna recommends checking individual zero/one pulse widths and the frame reset interval. Makuna also highlights signal-level and pulse-shape problems.

    However, that report concerned possibly proprietary lights. The reporter eventually obtained working output with WLED’s SM16825 RGBCW selection. It is not evidence that standard WS2805 requires inter-byte gaps or that this selection would help #5877.

    3. The early “600 kbit/s” advice was corrected

    The initial discussion in NeoPixelBus #764 suggested slower timing.

    Makuna later identified a datasheet translation error. NeoPixelBus PR #794 updated the WS2805 methods and aliased WS2814 to them.

    Therefore, the old 600 kbit/s comment is not a sufficient reason to slow down all WS2805 output.

    Implication for #5877

    The upstream evidence strengthens the timing hypothesis. It does not establish a continuous-refresh requirement.

    Your “off refresh” comparison remains useful. If it changes the result, capture the actual frame spacing as well as the bit timing. A refresh-dependent result alone would not distinguish a strip refresh requirement from periodic correction of corrupted data.

    The most useful waveform comparison is at the first strip input, using the same failing state:

    • Measure T0H, T0L, T1H, and T1L.
    • Measure the reset-low interval and frame spacing.
    • Check signal amplitude, ringing, and edge shape.
    • Compare RMT with I2S.

    For testing #5704, preserve the five-channel format and vary only timing. The upstream findings support that test, but do not yet establish #5704 as a fix.

    You are interacting with an AI system.

  13. DedeHai commented on Oct 2, 2026

    @DedeHai
    Collaborator

    @jlt24 does disabling the brightness limiter change anything? If not this is probably a wiring issue. My new driver may fix it as it lets you fine tune the hardware timing

  14. jlt24 commented on Oct 3, 2026

    @jlt24
    Author

    Using the same known-failing state with the RMT driver, I compared the behavior with Off Refresh disabled and enabled.
    Result: No observable difference. The flickering still occurs with Off Refresh enabled.
    I also confirmed that disabling the brightness/current limiter does not change the behavior.
    Current results so far:

    • RMT: generally works, but the known brightness/color combination produces intermittent flickering.
    • I2S: severe/continuous flashing regardless of preset, color, or brightness.
    • Brightness/current limiter disabled: no change to the RMT flicker.
    • Off Refresh enabled: no change to the RMT flicker.
      I'm happy to test the new driver/timing adjustments from New LED hardware driver: WLED Pixel Bus #5704 when an appropriate build is available.
  15. DedeHai commented on Oct 3, 2026

    @DedeHai
    Collaborator

    I'm happy to test the new driver/timing adjustments from New LED hardware driver: WLED Pixel Bus #5704 when an appropriate build is available

    There are, either the artifacts from the PR or the ones from my branch.

  16. sammccants commented on Oct 5, 2026

    @sammccants

    I'm experiencing what appears to be a very similar issue with WS2805 RGBCCT strips on WLED 0.16.0.1, although I'm using an Athom ESP32-C3 controller rather than a Dig-Quad.

    My setup is 200 WS2805 pixels (12V, 60 LEDs/m / 20 pixels/m). I see very brief flashes of corrupted colours affecting variable portions of the strip. It can occur at any colour/brightness and still happens with power injection disconnected and with the strip shortened to only 80 pixels.

    Interestingly, the flickering is strongly correlated with activity in the WLED web UI. Changing colour/brightness frequently triggers it, navigating between settings pages can trigger it, and simply viewing the Pin Info page causes almost continuous flickering.

    The affected position isn't fixed — sometimes only later pixels are corrupted, while other times corruption starts near the beginning.

  17. softhack007 commented on Oct 5, 2026

    @softhack007
    Member

    the flickering is strongly correlated with activity in the WLED web UI. Changing colour/brightness frequently triggers it, navigating between settings pages can trigger it, and simply viewing the Pin Info page causes almost continuous flickering.

    @sammccants this is a different, well-known bug that mainly affects esp32-C3. It's an interrupt latency problem, and the only solution unfortunately is a complete re-write of the NeoPixelBus driver. See #5704, or #5690 for a minimal workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions