XIAO LED Driver Board & RGB LED Strip

Looking at pictures at the Products I have some confusion regarding the integration of the XIAO LED Driver Board and an RGB LED strip (e.g. 24 LED Ring). If I connect the LED strip through the sole Grove port on the Driver Board then I am led to believe that I should use the following settings in my sketch:

  • DATA_PIN D5
  • CLOCK_PIN D4
  • NUM_LEDS 24
  • BOARD_TYPE WS2813

I used the FastLED library and nothing worked. Some LEDs light up but not all. Except for some minor but consistent flickering of the LEDs (changing BRIGHTNESS has no effect). And FastLED.clear() does not work either.

I’ve changed the DATA_PIN & CLOCK_PIN values (through personal ignorance) but no setting has a different effect on the LEDs. In other words, the XIAO MCU (ESP32-S3 Sense in my case) is not sending any data to the LED strip.

Also, I understand that the Grove port on this LED Driver Board is not intended to be used for I2C purposes but that is only a red herring in my situation, I believe.

Can anyone share a Hello World sketch that illustrates control of the LED strip through a sketch? Thanks.

Regards.

P.S.
I do have the barrel connector power supply to the LED Driver Board but, again, turning it on or off has no effect on the discrete number of LEDs that randomly chose to illuminate themselves during Upload.

Hi there,

So, I have on here a post with Demo and some cde , showing the S3 with a B2B more i/o board and attached to it is a Neopixel stick , (ringis the same) I have one of those on here too but ??
In the video I show how it’s connected and the code, I can paste what have if it would help.

HTH
GL :slight_smile: PJ :v:

Hi there,

Here is the KIT addition dual Strips…code
and the Ring, a.k.a. SUN :+1:
:grin:

// =============== Dual NeoPixel Test (Balanced, Sequential) ==================
// ESP32-S3 (BSP 2.0.17)
// Strip A: GPIO 38, 8px
// Strip B: GPIO 2,  8px
// Self-test: Strip A then Strip B, each pixel R->G->B (1s each)
// Patterns (low-stress): For each color, run KITT on A (B off), then KITT on B (A off),
// then Barber on A (B off), then Barber on B (A off), repeat through color list.
// ============================================================================

#include <Arduino.h>
#include <Adafruit_NeoPixel.h>

// --- Pins & sizes ---
#define PIN_A              38
#define PIN_B               2
#define PIXELS_A            8
#define PIXELS_B            8

// --- Global brightness & timing ---
#define BRIGHTNESS         96     // raise cautiously if power allows
#define STEP_DELAY_MS      55
#define RUN_MS_PER_COLOR   3000   // per strip, per pattern
#define TEST_HOLD_MS      1000    // self-test: 1s per color per LED

// --- Color balance (pull R/G down so blue matches) ---
#define RED_CORR          150
#define GREEN_CORR        150
#define BLUE_CORR         255

Adafruit_NeoPixel stripA(PIXELS_A, PIN_A, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel stripB(PIXELS_B, PIN_B, NEO_GRB + NEO_KHZ800);

// ---------- Helpers ----------
static inline uint32_t balancedColor(uint8_t r, uint8_t g, uint8_t b) {
  uint16_t rr = (uint16_t)r * RED_CORR   / 255;
  uint16_t gg = (uint16_t)g * GREEN_CORR / 255;
  uint16_t bb = (uint16_t)b * BLUE_CORR  / 255;
  if (rr > 255) rr = 255;
  if (gg > 255) gg = 255;
  if (bb > 255) bb = 255;
  return Adafruit_NeoPixel::Color((uint8_t)rr, (uint8_t)gg, (uint8_t)bb);
}

static inline uint32_t scaleColor(uint32_t c, uint8_t s) {
  uint8_t r = (c >> 16) & 0xFF, g = (c >> 8) & 0xFF, b = c & 0xFF;
  r = (uint16_t(r) * s) >> 8;
  g = (uint16_t(g) * s) >> 8;
  b = (uint16_t(b) * s) >> 8;
  return Adafruit_NeoPixel::Color(r, g, b);
}

static inline void allOff(Adafruit_NeoPixel &s) { s.clear(); s.show(); }
static inline void bothOff() { allOff(stripA); allOff(stripB); }

// ---------- Self-test: per-pixel R->G->B (1s each) ----------
void selfTestStrip(Adafruit_NeoPixel &s, int nPixels) {
  for (int i = 0; i < nPixels; i++) {
    s.clear();
    s.setPixelColor(i, balancedColor(255, 0, 0)); s.show(); delay(TEST_HOLD_MS);
    s.setPixelColor(i, balancedColor(0, 255, 0)); s.show(); delay(TEST_HOLD_MS);
    s.setPixelColor(i, balancedColor(0, 0, 255)); s.show(); delay(TEST_HOLD_MS);
  }
  allOff(s);
}

// ---------- KITT scanner for a single strip ----------
void runKITT(Adafruit_NeoPixel &s, int nPixels, uint32_t color, uint32_t runMs) {
  uint32_t t0 = millis();
  int pos = 0, dir = 1;
  while (millis() - t0 < runMs) {
    s.clear();
    s.setPixelColor(pos, color);
    int p1 = pos - dir, p2 = pos - 2*dir;
    if (p1 >= 0 && p1 < nPixels) s.setPixelColor(p1, scaleColor(color, 90));  // ~35%
    if (p2 >= 0 && p2 < nPixels) s.setPixelColor(p2, scaleColor(color, 40));  // ~15%
    s.show();
    delay(STEP_DELAY_MS);
    pos += dir;
    if (pos <= 0 || pos >= nPixels - 1) dir = -dir;
  }
}

// ---------- Barber pole for a single strip ----------
void runBarber(Adafruit_NeoPixel &s, int nPixels, uint32_t color, uint32_t runMs) {
  uint32_t t0 = millis();
  uint8_t phase = 0;
  uint32_t dim = scaleColor(color, 80); // ~31%
  while (millis() - t0 < runMs) {
    for (int i = 0; i < nPixels; i++) {
      bool on = ((i + phase) & 0x01) == 0;
      s.setPixelColor(i, on ? color : dim);
    }
    s.show();
    delay(STEP_DELAY_MS);
    phase++;
  }
}

// ---------- Color list (balanced) ----------
uint32_t COLORS[] = {
  balancedColor(255,   0,   0), // Red
  balancedColor(  0, 255,   0), // Green
  balancedColor(  0,   0, 255), // Blue (balanced)
  balancedColor(255, 255,   0), // Yellow
  balancedColor(  0, 255, 255), // Cyan
  balancedColor(255,   0, 255), // Magenta
  balancedColor(255, 255, 255)  // White
};
const int NUM_COLORS = sizeof(COLORS) / sizeof(COLORS[0]);

void setup() {
  Serial.begin(115200);
  delay(200);
  Serial.println("\nDual NeoPixel (GPIO38 & GPIO2) — Seq Self-Test + KITT/Barber");

  stripA.begin(); stripA.setBrightness(BRIGHTNESS); stripA.show();
  stripB.begin(); stripB.setBrightness(BRIGHTNESS); stripB.show();

  // Self-test: A then B
  selfTestStrip(stripA, PIXELS_A);
  delay(150);
  selfTestStrip(stripB, PIXELS_B);
  delay(150);
}

void loop() {
  // For each color: run patterns on A while B is off, then on B while A is off
  for (int c = 0; c < NUM_COLORS; c++) {
    uint32_t col = COLORS[c];

    // KITT A, B off
    allOff(stripB);
    runKITT(stripA, PIXELS_A, col, RUN_MS_PER_COLOR);
    allOff(stripA);

    // KITT B, A off
    runKITT(stripB, PIXELS_B, col, RUN_MS_PER_COLOR);
    allOff(stripB);

    // Barber A, B off
    runBarber(stripA, PIXELS_A, col, RUN_MS_PER_COLOR);
    allOff(stripA);

    // Barber B, A off
    runBarber(stripB, PIXELS_B, col, RUN_MS_PER_COLOR);
    allOff(stripB);
  }
}

They can get Bright as the Sun… :sun:

HTH
GL :slight_smile: PJ :v:

If you’re planning to drive an RGB strip directly from the XIAO, there are two main things to watch out for: power and logic levels.

The XIAO’s GPIO pins can only source/sink around 20–40 mA. So if you’re using addressable LEDs like WS2812B / NeoPixels, you definitely shouldn’t power the strip from the XIAO itself. Power the strip’s 5 V and GND directly from your external supply and only connect the data line to the XIAO.

Since the XIAO runs at 3.3 V, some 5 V LED strips will accept the signal, but it can be unreliable. If you see flickering or wrong colors, a simple level shifter (e.g. SN74HCT125) usually fixes it.

From my experience, using a dedicated LED driver board—or at least adding a large bulk capacitor (around 1000 µF) across the power rails—helps a lot with stability. This Adafruit guide explains the power surge and signal timing issues really well:
Adafruit: NeoPixel Overpowering and Protection Guide

Which RGB strip are you using? If it’s a longer strip, we can quickly estimate the current draw and check whether an external supply is needed.

Excellent advice! Thx (since I’ve used 300 LED strip with non-Seed ESP32 chips with 18 AWG cables for dedicated power).

BTW, I do have the Seeed barrel connector to feed power to the board (instead of the 12V terminal).

My simplistic observation is that the -S3 Sense is “so fast” that this particular type of Grove LED strip is overwhelmed. After all, why doesn’t this code snippet have any visible effect?

FastLED.clear();
FastLED.show();

Regards.

Thx, PJ! I know that I’m doing something wrong because parametric changes in BRIGHTNESS have zero visible effect. (Yeah, I keep the value below 60 for the reasons you describe in your note!)

@cgwaltney, I guess my English language skills leave a lot to be desired since English is not even my third language. I was seeking a specific technical response not an extract from the Seeed Catalog that I can access autonomously.

Thanks.

Regards.

Keep talking like that and you will be looking at a blank screen

Hi there,

SO , Help is help right, :+1:
I think he’s just letting you know there are some other options as well.

Try adding the delay and see if the LED turns OFF
FastLED.clear();
FastLED.show();
delay(1000); // Wait for 1 second to confirm the effect

Look here for more info.
https://forum.arduino.cc/t/fast-led-clear-command-strange-results-with-delay/682385#:~:text=I’m%20using%20the%20Fast,clear%20command%20instead%20of%20after.

HTH
GL :slight_smile: PJ :v:

Thanks a bunch, again, @PJ_Glasso. Your advice is spot on because in other sketches I’ve found the -S3 Sense to be faster than what I’m accustomed too in these nominal tests. The side effects of speed and current (I’m not an EE because my grades weren’t good enough 60 years ago to qualify) are very educational for me right now.

I’ll get back to working on this shortly. In the interim, I’m trying to evaluate RTC on the expansion board to behave nicely with the SAMD21 chip.

Regards.

Hi there ,

Awesome :+1:
SO ,:grin: LOL compared to the SAMD21 It’s a Ferrari vs. a Volkswagen.
Main advice would be , ALWAYS leave a 25-50 ms delay in Loop();
so the Bootloader can catch Programming hook, without needing to manually go into bootloader mode with the Buttons. :crossed_fingers:

Pay attention to the NOTEs on the Xiao Development board, It was designed for the Sam and Nrf parts , the ESP32 parts compatibility was an after though and came on scene later.
Pogo’s for example and other Port related differences. READ everything to avoid not getting tripped up.

Crystal ball time

:crystal_ball:
I’m betting in this year they REFRESH the Xiao DEV Board. It’s really time!
I think users would even PAY more :money_mouth_face: if they add all the Bells and whistles with a few extras.

Several of us on here have an Idea of what is needed, Hopefully we can pull together a list or Post a Thread that encompasses the needs and the wants. :+1:

HTH
GL :slight_smile: PJ :v:

1 Like

The case is the real game changer… dont skimp on it

That was the original the system was built on so is should work very (JB) smooth

1 Like

My wish is that Seeed will eventually install a RAG user interface to support searches in the forum. There are many, many replies that I wish could be easily be returned through “conversational searches.” Of course, synthesizing search queries is something I do not do very well.

Example: your delay() recommendation with the range values is spot on! It is a small but important step for me now with this knowledge and resulting success. Not knowing what goes on beneath the covers (even though I’m supposedly a “graduate” of Seeed’s first foray into TinyML with the Harvard Prof and Edge Impulse), the thought about the delay is generally not first and foremost since I ration my use of the Serial() functions.

Regards.

HI there,

So Glad the Input was useful, We have a forum “excellent solutions” when fixes are identified, The "Search " generally works well for getting you into the info, IMO the RAG front end , albeit a good Idea would return more but still require some filtering.

It is great to have tech that is easily accessible, and Seeed does that in spades. The documentation ALWAYS lags, it’s just how it is. No-one writes a how to and then go’s and does it. It’s almost always the other way around. Seems to me. :grin:

HTH
GL :slight_smile: PJ :v:

1 Like

Hello @cgwaltney,

Have you noticed why Seeed never illustrates the use of the case with the display functioning? No prizes if you’ve seen the results. (Of course, Seeed cannot please everyone). Since I have the pair (expansion board + case), let us call the case V0.1. Also, no edges in the lowest shelf to prevent the LiPo from sliding over. (Of course, to Seeed’s credit, they did a good job explaining the selection of the LiPo capacity). The RTC is a winner for me.

Of course, then there are the other expansion boards too as you know very well.

Anyhow, back to Onshape to embellish the expansion board case with some minor adjustments for my use.

Thanks for the suggestions, nevertheless.

Regards.

Yes, RAG (for Seeed users) has to be conversational. Cannot be a one-shot response, IMHO.

1 Like