Skip to content

Support for SM16824E and SM167035P3 and help with protocol #1941

Closed

Description

@einlichtvogel

Hey!

First of all, thanks for the great library!

I'm currently working on building a custom controller for a Chinese LED strobe.
The LED board contains 48 RGB pixels, each controlled by its own SM16703P3 IC.

In addition to the 48 RGB pixels, there are 8 white-only LEDs. These are controlled by three SM16824E ICs, where:

Red channel = White Pixel 1

Green channel = White Pixel 2

Blue channel = White Pixel 3
...and so on.

The problem I'm encountering is that there are three SM16824E ICs available for a total of 9 white LEDs, but only 8 are actually connected. So one output channel remains unused.

When I control the strobe using the factory controller, the white LED dimming works perfectly.
However, when I use my custom controller, as soon as I try to increase the brightness of the second-last (in this case led 8, because 9 is not connected) white LED, all the other white LEDs begin to flicker.

So my question is:
Could this be an issue with the library, or is it more likely a hardware problem?
I'm asking because the original factory controller doesn't show this behavior at all.

My current setup looks like this:

FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS); (also tried any other protocol than neopixel, like the SM1670)
Where NUM_LEDS = 48 (RGB ICs) + 3 (White ICs)

Activity

  1. changed the title [-]Support for SM16824E and SM167035P3[/-] [+]Support for SM16824E and SM167035P3 and help with protocol[/+] on Jun 17, 2025
  2. zackees commented on Jun 17, 2025

    @zackees
    Member

    Timing could be off. I'm guessing this is a WS2812 clone.

    Quick solution is to use the overlock feature (see readme and we also have an example).

    Use an overlock factor of .9 or 1.1 and see if the problem goes away. If it does then post the results here and I'll add the controller type.

    The over clock will compress/expand the THO timing, which is critical in the clockless chipset.

  3. einlichtvogel commented on Jun 17, 2025

    @einlichtvogel
    Author

    No, overclocking does not help anything.

    Maybe, because these two types of ICs are on the same data line?

    Also: When LED 8 is at 0, all other LEDs have normal dim behaviour, as soon as led 8 is up, they begin to flicker.

  4. einlichtvogel commented on Jun 17, 2025

    @einlichtvogel
    Author
  5. zackees commented on Jun 17, 2025

    @zackees
    Member

    hmmm having trouble seeing the attachment. github is throwing an error.

    On a high level, I don't believe we actually support that chipset? Can you confirm? I'm on mobile. See the readme to confirm supported chipsets.

  6. zackees commented on Jun 17, 2025

    @zackees
    Member

    I was able to download your vids on desktop.

  7. zackees commented on Jun 17, 2025

    @zackees
    Member

    Yeah it's not one of the supported led chipsets.

    I'm having trouble finding the datasheet for the timings, can you provide it?

    • WS281x Clockless family
      • WS2811 (Old style 400khz & 800khz)
      • WS2812 (NeoPixel)
      • WS2812-V5B (250 uS reset)
      • WS2815
    • APA102 / SK9822 / HD107s (turbo->40mhz) / Adafruit DotStars (SPI)
    • HD107s, same thing as the APA102, but runs at turbo 40 Mhz
    • SmartMatrix panels - needs the SmartMatrix library (https://github.com/pixelmatix/SmartMatrix)
    • TM1809/4 - 3 wire chipset, cheaply available on aliexpress.com
    • TM1803 - 3 wire chipset, sold by RadioShack
    • UCS1903 - another 3-wire LED chipset, cheap
    • GW6205 - another 3-wire LED chipset
    • LPD8806 - SPI-based chipset, very high speed
    • WS2801 - SPI-based chipset, cheap and widely available
    • SM16716 - SPI-based chipset
    • APA102 - SPI-based chipset
      • APA102HD - Same as APA102 but with a high-definition gamma correction function applied at the driver level.
    • P9813 - aka Cool Neon's Total Control Lighting
    • DMX - send rgb data out over DMX using Arduino DMX libraries
    • LPD6803 - SPI-based chipset, chip CMODE pin must be set to 1 (inside oscillator mode)
  8. einlichtvogel commented on Jun 17, 2025

    @einlichtvogel
    Author

    Oh well, I already thought this will be the case.

    This is the only datasheet I found: https://de.scribd.com/document/757938003/SM16824E-zh-CN-en-1

  9. zackees commented on Jun 17, 2025

    @zackees
    Member

    SM16824E

    • T0H: .3
    • T0L: .9
    • T1H: .9
    • T1L: .3
    • TRES: 1.6
    • TRST: 200

    FastLED timings

    • T1: 300
    • T2: 900
    • T3: 0

    Image

  10. einlichtvogel commented on Jun 17, 2025

    @einlichtvogel
    Author

    But then, for reference, if the timing finally would work, I have the case that 2 different ICs are on the same data line.
    What to do about that one?

  11. zackees commented on Jun 17, 2025

    @zackees
    Member

    I added controller SM16824E

    It's now in master.

    You can add it like this:

    FastLED.addLeds<SM16824E, DATA_PIN, RGB>(leds, NUM_LEDS);  // RGB ordering (uses SM16824EController)

    I have the case that 2 different ICs are on the same data line.

    You hope the IC's are close enough in timing that it works.

  12. einlichtvogel commented on Jun 17, 2025

    @einlichtvogel
    Author

    Now, none of the LEDs work anymore.

    Just the first channel of the IC does.

    EDIT: No, it doesn't, just random flickering leds.

  13. zackees commented on Jun 17, 2025

    @zackees
    Member

    Can you edit this

    class SM16824EController : public ClocklessController<DATA_PIN, C_NS(300), C_NS(900), C_NS(0), RGB_ORDER> {};

    With timings until it works?

  14. einlichtvogel commented on Jun 17, 2025

    @einlichtvogel
    Author

    I can try, which of the 3 do I need to change?

  15. zackees commented on Jun 17, 2025

    @zackees
    Member

    All of them. FastLED uses a weird timing code called T0, T1, T3

    T0 is the length of time before a 0, T1 is the additional time before a 1, T3 is the additional time before the next bit is signaled.

    So the total duration will be = T1 + T2 + T3

    You can generate a T1, T2, T3 from T0H...T1L timings using this python script:

    // At T=0 : the line is raised hi to start a bit

  16. 52 remaining items

  17. zackees commented on Jun 15, 2026

    @zackees
    Member

    most likely fail

  18. einlichtvogel commented on Jun 15, 2026

    @einlichtvogel
    Author

    So, running different ICs on one DL is not possible?

  19. zackees commented on Jun 15, 2026

    @zackees
    Member

    it's possible if their protocols are compatible

  20. einlichtvogel commented on Jun 15, 2026

    @einlichtvogel
    Author

    so in this case, it might not be the case, correct?

  21. einlichtvogel commented on Jun 15, 2026

    @einlichtvogel
    Author

    SM16824E seems not to be working, the flickering is still there.

    Tried it with ESP32 Pico D4 (M5Stack Matrix ATOM 1)

    I'll give up, longe have we tried, and thank you for officially implementing it.

    Will contact the manuafacturer, see what they say.

  22. zackees commented on Jun 17, 2026

    @zackees
    Member

    Actually for this specific pair it should work — the SM16824E datasheet you attached specifies T0H=300 / T0L=900 / T1H=900 / T1L=300 ns, which is identical to the SM16703 RZ timing. Both are WS2811-800kHz clones at the wire level.

    The flicker on the shared bus is on us: TIMING_SM16824E in FastLED currently emits T1H=1200 ns / T1L=100 ns, which is out of spec on the SM16703 side (T1H max 1000 ns) and doesn't match your SM16824E datasheet either. The doc comment in src/chipsets.h even contradicts the numbers being clocked out.

    Workaround until that's fixed: drive the whole bus with SM16703 — the SM16824Es will then see waveforms that match their own datasheet.

    FastLED.addLeds<SM16703, DATA_PIN, RGB>(leds, total_slots);

    Tracking the timing fix separately in #3203.

  23. zackees commented on Jun 17, 2026

    @zackees
    Member

    @einlichtvogel — fix is in flight: PR #3204 (tracked in #3203) aligns TIMING_SM16824E with the datasheet you attached. Algorithmically validated via ci/tools/led_timing_conversions.py against both the SM16703P datasheet window and the SM16824E datasheet window — old 300/900/100 emitted T1H=1200 ns / T1L=100 ns (out of spec both ways), new 300/600/300 emits T0H=300 / T0L=900 / T1H=900 / T1L=300 / cycle=1200 ns (in spec for both).

    Once merged you can drive the whole shared bus with either controller:

    // Either of these will now emit a waveform that satisfies
    // both SM16703P and SM16824E datasheets:
    FastLED.addLeds<SM16703,  DATA_PIN, RGB>(leds, total_slots);
    FastLED.addLeds<SM16824E, DATA_PIN, RGB>(leds, total_slots);

    If you'd be willing to confirm the fix on the hardware combo (SM16703 + SM16824E on one data line) once #3204 merges, that would close the loop on this thread.

  24. zackees commented on Jun 17, 2026

    @zackees
    Member

    Resolved by #3204 (merged ba46ef1 → master).

    Summary of the fix:

    • TIMING_SM16824E now emits T0H=300 / T0L=900 / T1H=900 / T1L=300 / cycle=1200 ns — algorithmically verified spec-compliant against both the SM16824E datasheet and the SM16703P datasheet (via ci/tools/led_timing_conversions.py).
    • Because both chips share the same RZ-code profile, you can now drive a mixed SM16703 + SM16824E bus from a single controller — either SM16703 or SM16824E works on the shared data line.

    @einlichtvogel — please feel free to reopen if it doesn't resolve your mixed-bus case on hardware. (The network-induced flicker you saw later in this thread is a separate ESP32 + RMT + WiFi issue and not affected by this fix.)

  25. zackees commented on Jun 18, 2026

    @zackees
    Member

    Oh, one more thing, for flicker during WIFI, you can try out one of the new drivers that we have, like the UART/parlio/lcd (not sure which esp you have or if you have an esp at all). RMT does not have a lot of memory so it can buffer underrun easily. The other drivers have large DMA buffers and are resistant to flicker.

    It's easiest if you use the channels api, as the legacy api for enabling a specific driver is not well documented, but will be soon. See https://github.com/FastLED/FastLED/blob/master/src/fl/channels/README.md

    AI come in shortly and give you more details.

  26. zackees commented on Jun 18, 2026

    @zackees
    Member

    Hi @einlichtvogel — Claude here, following up as @zackees said.

    Your platform

    Pulled from your earlier messages:

    I am running a ESP32-ETH01 with ESP32-WROOM-32

    …and later:

    Tried it with ESP32 Pico D4 (M5Stack Matrix ATOM 1)

    Both are classic ESP32 (the original dual-core LX6 generation, internally FL_IS_ESP_32DEV). That matters for driver choice — the menu of "WiFi-resistant" drivers is not the same set you'd have on an ESP32-S3 or -C6.

    What you can / can't use on classic ESP32

    From src/platforms/esp/32/feature_flags/enabled.h:

    Driver (fl::Bus::X) Classic ESP32 (yours) Notes
    RMT ✅ What you're on today. Small per-channel buffer → underruns under WiFi interrupt load.
    I2S ✅ Recommended. Original ESP32's I2S parallel mode. Large DMA, immune to WiFi jitter, can drive multiple strips in parallel. Disabled on every newer ESP32 variant.
    UART ✅ DMA-backed, one strip per UART peripheral (you have 3). Also WiFi-resistant. Good if you only need one strip.
    SPI (clockless) ✅ (IDF 5.0+) Clockless-over-SPI MOSI, DMA. Useful if I2S/UART pins conflict.
    PARLIO ❌ ESP32-P4 / C6 / H2 / C5 only. Not on classic ESP32.
    LCD_RGB, LCD_SPI, LCD_CLOCKLESS ❌ ESP32-S3 / P4 only.
    I2S_LCD_CAM ❌ ESP32-S3 only.

    So ignore the PARLIO / LCD suggestion — they don't exist on your chip. The two real answers for you are I2S (best) or UART (simpler).

    Option A — quickest fix: keep addLeds<>, pin to I2S at compile time

    This is a one-line change to the code you already have. Every FastLED.addLeds<> variant now accepts an optional trailing fl::Bus template parameter (#2460). Naming fl::Bus::I2S at the call site is what links the I2S driver translation unit, so it actually runs your show().

    #include "FastLED.h"
    // The per-driver bus_traits.h #include is the explicit opt-in that links
    // the driver TU. Without it you'll get
    // "implicit instantiation of undefined template BusTraits<Bus::I2S>".
    #include "platforms/esp/32/drivers/i2s/bus_traits.h"
    
    #define DATA_PIN 4
    #define NUM_LEDS 51   // your existing buffer length
    
    CRGB leds[NUM_LEDS];
    
    void setup() {
        // Trailing fl::Bus::I2S template arg routes show() through the
        // DMA-backed I2S parallel engine instead of RMT.
        FastLED.addLeds<SM16703, DATA_PIN, RGB, fl::Bus::I2S>(leds, NUM_LEDS);
    }
    
    void loop() {
        // your existing code, unchanged
        FastLED.show();
    }

    Use SM16703 (works for both your SM16703 and SM16824E ICs — confirmed in PR #3204 that just merged).

    To try UART instead, swap two things:

    #include "platforms/esp/32/drivers/uart/bus_traits.h"
    // …
    FastLED.addLeds<SM16703, DATA_PIN, RGB, fl::Bus::UART>(leds, NUM_LEDS);

    Option B — the Channels API (runtime bus selection)

    Same outcome, more explicit configuration. Better when you want to change the driver at runtime or have multiple strips with different drivers. Full docs: https://github.com/FastLED/FastLED/blob/master/src/fl/channels/README.md

    #include "FastLED.h"
    #include "fl/channels/channel.h"
    #include "fl/channels/config.h"
    #include "fl/chipsets/led_timing.h"
    
    #define DATA_PIN 4
    #define NUM_LEDS 51
    
    CRGB leds[NUM_LEDS];
    
    void setup() {
        auto timing = fl::makeTimingConfig<fl::TIMING_SM16703>();
    
        fl::ChannelConfig cfg("strip", fl::ClocklessChipset(DATA_PIN, timing),
                              fl::span<CRGB>(leds, NUM_LEDS), RGB);
    
        // Pick the I2S driver at runtime. The non-template FastLED.add(cfg)
        // path auto-enables every driver on the platform; larger binary but
        // no per-driver #include needed.
        cfg.options.mBus = fl::Bus::I2S;
        FastLED.add(cfg);
    }
    
    void loop() {
        FastLED.show();
    }

    Switching to UART is one line: cfg.options.mBus = fl::Bus::UART;.

    What to expect

    • Compile-time path (Option A) keeps your binary small — --gc-sections drops every driver you didn't name.
    • Runtime path (Option B) links every driver on the platform — bigger flash footprint, but you can choose the bus from config/UI without recompiling.
    • Either way, the WiFi-induced flicker you were seeing on RMT should drop dramatically because the I2S/UART DMA engines aren't sensitive to short interrupt bursts the way RMT's per-channel buffer is.

    If I2S doesn't fit (e.g. the ETH01's LAN8720 PHY is using pins you also need), UART is a clean fallback for a single strip. If neither works for layout reasons, ping back and we'll look at clockless-SPI (fl::Bus::SPI).

  27. zackees commented on Jun 18, 2026

    @zackees
    Member

    ... uh you are on the esp32 and not one of the newer ones. I2S may or may not work for you at this point. Esp32 is the final boss before FastLED 4 is released.

  28. einlichtvogel commented on Jun 20, 2026

    @einlichtvogel
    Author

    Will try it in a week, currently on tour.

    I was using the M5Stack Atom1 with the matrix as test in this case. Think it has a ESP32-PICO-D4

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

    area: coreLED drivers, color math, animationsstatus: triageNeeds initial assessmenttype: questionUsage question or clarification

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions