LED Flickering Issue with PicoBuck LED Module

Hi all.

I am building LED controller with PicoBuck LED Module.
(product link : PicoBuck LED Driver - COM-13705 - SparkFun Electronics)

I've almost finished this project, but there's one Issue.
when I apply low duty cycle pwm signal to the LED Module, LED starts to flicker, which is not as I intended.

I want to know why this happens, and how to prevent flickering and maintain constant hue and brightness.

I hope videos and pictures explain my problem better, so here I leave some of them.

[LED Flickering]

-> (edit) it seems like there's problem with LED and Camera interferance.
If seen in my eye,
(1) no flickering at MAX brightness
(2) flickering in color and brightness, as input is slowly changed.
it seems duty cycle below 30 ~ 40% shows this flickering.

[Schematic of LED module and Arduino]

(Edit) Included everything inside this project. this box also sends signal to WS2812B LED Strip, which is 21 LED's long.
If more information is needed, please let me know.

[Prototype]

[arduino sourcecode]

#include <FastLED.h>

#define LED_R 9
#define LED_G 10
#define LED_B 11

#define STRIP_DIN 6
#define STRIP_LED_NUM 21

#define POT_R A0
#define POT_G A1
#define POT_B A2

#define PUSH_1 12
#define PUSH_2 13
#define RELAY 8

CRGB led[STRIP_LED_NUM];
bool push1_pressed_now = false;
bool push1_pressed_before = false;
bool push2_pressed_now = false;
bool push2_pressed_before = false;

bool led_on = false;
bool strip_on = false;

// Timing variables
unsigned long previousMillis = 0;  // Stores the last time LEDs were updated
const long interval = 100;         // Interval at which to update LEDs (in milliseconds)

// Stores previous potentiometer values to detect changes
int prev_R_brightness = 0;
int prev_G_brightness = 0;
int prev_B_brightness = 0;

bool is_button_pressed(int button_no, bool &check_now, bool &check_before);

void setup() {
  pinMode(RELAY, OUTPUT);  
  Serial.begin(9600);
  pinMode(LED_R, OUTPUT);
  pinMode(LED_G, OUTPUT);
  pinMode(LED_B, OUTPUT);

  pinMode(POT_R, INPUT);
  pinMode(POT_G, INPUT);
  pinMode(POT_B, INPUT);

  pinMode(PUSH_1, INPUT_PULLUP);
  pinMode(PUSH_2, INPUT_PULLUP);

  FastLED.addLeds<WS2812B, STRIP_DIN>(led, STRIP_LED_NUM);
  for (int i = 0; i < STRIP_LED_NUM; i++) {
    led[i] = CRGB::White;
    FastLED.show();
    delay(50);
  }
  for (int i = 0; i < STRIP_LED_NUM; i++) {
    led[i] = 0;
    FastLED.show();
    delay(50);
  }
}

void loop() {
  unsigned long currentMillis = millis();  // Get the current time

  // Check for button presses
  if (is_button_pressed(PUSH_1, push1_pressed_now, push1_pressed_before)) {
    led_on = !led_on;    
  }
  if (is_button_pressed(PUSH_2, push2_pressed_now, push2_pressed_before)) {
    strip_on = !strip_on;
  }

  // Read potentiometer values
  int pot_R_val = analogRead(POT_R);
  int pot_G_val = analogRead(POT_G);
  int pot_B_val = analogRead(POT_B);

  // decide threshold, 0 ~ 34
  int R_brightness = pot_R_val/30;  
  int G_brightness = pot_G_val/30;
  int B_brightness = pot_B_val/30;

  // Apply threshold. if less than 90, turn off.
  if (R_brightness < 3) { R_brightness = 0; }
  if (G_brightness < 3) { G_brightness = 0; }
  if (B_brightness < 3) { B_brightness = 0; }

  // Update LED only if brightness changes AND some time passes
  if ((currentMillis - previousMillis >= interval) && 
      (R_brightness != prev_R_brightness ||  G_brightness != prev_G_brightness ||  B_brightness != prev_B_brightness)
      ) 
    {      
    previousMillis = currentMillis; // Update the time

    digitalWrite(RELAY, led_on);

    // Set the individual LED brightness, 0 ~ 34 -> 0 ~ 205
    analogWrite(LED_R, led_on * 6 * R_brightness);
    analogWrite(LED_G, led_on * 6 * G_brightness);
    analogWrite(LED_B, led_on * 6 * B_brightness);

    // Set the LED strip colors, 0 ~ 34 -> 0 ~ 255
    for (int i = 0; i < STRIP_LED_NUM; i++) {
      led[i].setRGB(strip_on *7.4* G_brightness, strip_on *7.4* B_brightness, strip_on *7.4* R_brightness);
      // Swapping RGB channels to match the interpretation of the LED strip
    }

    FastLED.show();
    Serial.print(" R : ");Serial.print(R_brightness); 
    Serial.print(" G : ");Serial.print(G_brightness); 
    Serial.print(" B : ");Serial.println(B_brightness); 

    // Store the current potentiometer values
    prev_R_brightness = R_brightness;
    prev_G_brightness = G_brightness;
    prev_B_brightness = B_brightness;
  }
}

// Function to detect if a button is pressed
bool is_button_pressed(int button_no, bool &check_now, bool &check_before) {
  check_now = !digitalRead(button_no);
  if (check_now && !check_before) {
    check_before = check_now;
    return true;
  } else {
    check_before = check_now;
    return false;
  }
}

[Similar Issue with same LED Module]

In your video I mostly see a flicker resulting from interference between your camera's capture frame rate and the PWM frequency of the LED. Other than that, I don't see any obvious problem, but I'll take your word for it that something is going on that's impossible to make out in the video.

There's a lower limit below which LEDs driven by buck topology drivers will start to flicker. This limit depends on mostly hardware design choices. One way of working around this is to reduce the PWM frequency, so that at a low duty cycle, the actual pulse duration is longer.

Where's the rest of the schematic? there's e.g. also a relay somewhere in there. And several pot meters. Please post a complete schematic of your project.

I'd recommend making a sketch that only uses the buck-driven LEDs; remove everything related to the addressable LED strip etc. Use that skeleton sketch to determine the minimum duty cycle that will allow the LEDs to run flicker-free. Post back that duty cycle; it should be <10%. If it's >10%, you may have some kind of hardware problem.


What's the input voltage on the 7805? I bet that thing is getting awfully hot with all three LED channels on.
I'd replace it with a buck converter; the 7805 is a really, really poor choice in this application. Also, 470uF on both input and output is excessive; replace the 470uF at the output with something like 0.1-1uF. But really, just don't use a 7805. It belongs in the 1970s.

I've added informations not clear in my original post.

the flickering occurs 0 ~ 30% duty cycle. like what you said, it seems like some issue with the hardware.

aside the voltage source, (yes, 7805's getting pretty hot after 5 ~ 10 minutes after turning every LED on. I'll buy a buck converter instead of 7805.) what's causing flickering, and how can I do the troubleshooting?

That's a pretty broad range. See if it helps if you reduce the PWM frequency. Google for examples on how to generate a lower frequency PWM than offered by analogWrite() by default. I'd suggest trying a frequency of e.g. 100Hz.

Yes; I suspect it might help to remove C1, C3 and C5 from the PicoBuck: https://cdn.sparkfun.com/assets/d/9/b/2/8/picoBuckv12.pdf
However, this will severely affect EMI behavior (and not in a good way), so there's a penalty if you do this.

See above; also, do you have an oscilloscope?

What is your power supply rating?

Files for WOKWI simulation:

sketch.ino

#include <FastLED.h>

#define LED_R 9
#define LED_G 10
#define LED_B 11

#define STRIP_DIN 6
#define STRIP_LED_NUM 21

#define POT_R A0
#define POT_G A1
#define POT_B A2

#define PUSH_1 12
#define PUSH_2 13
#define RELAY 8

CRGB led[STRIP_LED_NUM];
bool push1_pressed_now = false;
bool push1_pressed_before = false;
bool push2_pressed_now = false;
bool push2_pressed_before = false;

bool led_on = false;
bool strip_on = false;

// Timing variables
unsigned long previousMillis = 0;  // Stores the last time LEDs were updated
const long interval = 100;         // Interval at which to update LEDs (in milliseconds)

// Stores previous potentiometer values to detect changes
int prev_R_brightness = 0;
int prev_G_brightness = 0;
int prev_B_brightness = 0;

bool is_button_pressed(int button_no, bool &check_now, bool &check_before);

void setup() {
  pinMode(RELAY, OUTPUT);
  Serial.begin(9600);
  pinMode(LED_R, OUTPUT);
  pinMode(LED_G, OUTPUT);
  pinMode(LED_B, OUTPUT);

  pinMode(POT_R, INPUT);
  pinMode(POT_G, INPUT);
  pinMode(POT_B, INPUT);

  pinMode(PUSH_1, INPUT_PULLUP);
  pinMode(PUSH_2, INPUT_PULLUP);

  FastLED.addLeds<WS2812B, STRIP_DIN>(led, STRIP_LED_NUM);
  for (int i = 0; i < STRIP_LED_NUM; i++) {
    led[i] = CRGB::White;
    FastLED.show();
    delay(50);
  }
  for (int i = 0; i < STRIP_LED_NUM; i++) {
    led[i] = 0;
    FastLED.show();
    delay(50);
  }
}

void loop() {
  unsigned long currentMillis = millis();  // Get the current time

  // Check for button presses
  if (is_button_pressed(PUSH_1, push1_pressed_now, push1_pressed_before)) {
    led_on = !led_on;
  }
  if (is_button_pressed(PUSH_2, push2_pressed_now, push2_pressed_before)) {
    strip_on = !strip_on;
  }

  // Read potentiometer values
  int pot_R_val = analogRead(POT_R);
  int pot_G_val = analogRead(POT_G);
  int pot_B_val = analogRead(POT_B);

  // decide threshold, 0 ~ 34
  int R_brightness = pot_R_val / 30;
  int G_brightness = pot_G_val / 30;
  int B_brightness = pot_B_val / 30;

  // Apply threshold. if less than 90, turn off.
  if (R_brightness < 3) {
    R_brightness = 0;
  }
  if (G_brightness < 3) {
    G_brightness = 0;
  }
  if (B_brightness < 3) {
    B_brightness = 0;
  }

  // Update LED only if brightness changes AND some time passes
  if ((currentMillis - previousMillis >= interval) &&
      (R_brightness != prev_R_brightness ||  G_brightness != prev_G_brightness ||  B_brightness != prev_B_brightness)
     )
  {
    previousMillis = currentMillis; // Update the time

    digitalWrite(RELAY, led_on);

    // Set the individual LED brightness, 0 ~ 34 -> 0 ~ 205
    analogWrite(LED_R, led_on * 6 * R_brightness);
    analogWrite(LED_G, led_on * 6 * G_brightness);
    analogWrite(LED_B, led_on * 6 * B_brightness);

    // Set the LED strip colors, 0 ~ 34 -> 0 ~ 255
    for (int i = 0; i < STRIP_LED_NUM; i++) {
      led[i].setRGB(strip_on * 7.4 * G_brightness, strip_on * 7.4 * B_brightness, strip_on * 7.4 * R_brightness);
      // Swapping RGB channels to match the interpretation of the LED strip
    }

    FastLED.show();
    Serial.print(" R : "); Serial.print(R_brightness);
    Serial.print(" G : "); Serial.print(G_brightness);
    Serial.print(" B : "); Serial.println(B_brightness);

    // Store the current potentiometer values
    prev_R_brightness = R_brightness;
    prev_G_brightness = G_brightness;
    prev_B_brightness = B_brightness;
  }
}

// Function to detect if a button is pressed
bool is_button_pressed(int button_no, bool &check_now, bool &check_before) {
  check_now = !digitalRead(button_no);
  if (check_now && !check_before) {
    check_before = check_now;
    return true;
  } else {
    check_before = check_now;
    return false;
  }
}

diagram.json
{
  "version": 1,
  "author": "Anonymous maker",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-nano", "id": "nano", "top": -4.8, "left": -0.5, "attrs": {} },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": -58.8,
      "left": 131.4,
      "rotate": 90,
      "attrs": { "color": "red" }
    },
    {
      "type": "wokwi-led",
      "id": "led2",
      "top": -87.6,
      "left": 131.4,
      "rotate": 90,
      "attrs": { "color": "green" }
    },
    {
      "type": "wokwi-led",
      "id": "led3",
      "top": -116.4,
      "left": 131.4,
      "rotate": 90,
      "attrs": { "color": "blue" }
    },
    {
      "type": "wokwi-led-ring",
      "id": "ring1",
      "top": -248.96,
      "left": 1.19,
      "attrs": { "pixels": "16" }
    },
    { "type": "wokwi-potentiometer", "id": "pot1", "top": 8.3, "left": 172.6, "attrs": {} },
    { "type": "wokwi-potentiometer", "id": "pot2", "top": 8.3, "left": 249.4, "attrs": {} },
    { "type": "wokwi-potentiometer", "id": "pot3", "top": 8.3, "left": 326.2, "attrs": {} },
    {
      "type": "wokwi-pushbutton",
      "id": "btn1",
      "top": -51.4,
      "left": -86.4,
      "attrs": { "color": "green" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "btn2",
      "top": 6.2,
      "left": -86.4,
      "attrs": { "color": "green" }
    },
    { "type": "wokwi-relay-module", "id": "relay1", "top": -57.4, "left": 211.2, "attrs": {} }
  ],
  "connections": [
    [ "nano:GND.2", "led1:C", "black", [ "v0" ] ],
    [ "nano:GND.2", "led2:C", "black", [ "v0" ] ],
    [ "nano:GND.2", "led3:C", "black", [ "v0" ] ],
    [ "nano:9", "led1:A", "green", [ "v0" ] ],
    [ "nano:10", "led2:A", "green", [ "v0" ] ],
    [ "nano:11", "led3:A", "green", [ "v0" ] ],
    [ "nano:6", "ring1:DIN", "green", [ "v0" ] ],
    [ "ring1:VCC", "nano:5V", "red", [ "v134.4", "h57.6" ] ],
    [ "nano:GND.2", "ring1:GND", "black", [ "v-38.4", "h-67.2" ] ],
    [ "pot1:GND", "nano:GND.1", "black", [ "v19.2", "h-57.6" ] ],
    [ "pot1:SIG", "nano:A0", "green", [ "v28.8", "h-163.6" ] ],
    [ "pot1:VCC", "nano:5V", "red", [ "v38.4", "h-96.8" ] ],
    [ "pot2:GND", "nano:GND.1", "black", [ "v19.2", "h-124.8" ] ],
    [ "pot2:SIG", "nano:A1", "green", [ "v28.8", "h-221.2" ] ],
    [ "pot3:GND", "nano:GND.1", "black", [ "v19.2", "h-211.2" ] ],
    [ "pot3:SIG", "nano:A2", "green", [ "v28.8", "h-288.4" ] ],
    [ "pot3:VCC", "nano:5V", "red", [ "v38.4", "h-250.4" ] ],
    [ "pot2:VCC", "nano:5V", "red", [ "v38.4", "h-173.6" ] ],
    [ "nano:GND.2", "btn2:1.r", "black", [ "v0" ] ],
    [ "nano:GND.2", "btn1:1.r", "black", [ "v0" ] ],
    [ "nano:12", "btn1:2.r", "green", [ "v0" ] ],
    [ "btn2:2.r", "nano:13", "green", [ "h38.6", "v19.4" ] ],
    [ "relay1:IN", "nano:8", "green", [ "h0" ] ],
    [ "relay1:GND", "nano:GND.1", "black", [ "h0" ] ],
    [ "relay1:VCC", "nano:5V", "red", [ "h0" ] ]
  ],
  "dependencies": {}
}

That's a good question that hasn't been answered.

VCC of the PicoBuck should be connected to that higher voltage (assuming 12volt).
That should fix your 7805 overheating, and maybe the flickering.

I an using similar drivers, and they dim down to less than 1% just fine.
Leo..

Or even 7V, or 24V...anything would do, really as long as it's <40V. Thanks for pointing this out...

thank you all answers. for those who may undergo same issue, the solution was reducing PWM frequency.

I changed PWM frequency like this :
(don't fully understand. helping hand from Chat GPT and little googling.)
and in my eye it looks kind of solved the problem.

  // Adjust PWM frequency to 100 Hz
  // For Timer1 (pins 9, 10), set prescaler to 1024
  // This changes the PWM frequency from 490 Hz to approximately 61 Hz (16MHz / 1024 / 256)
  // To get as close to 100 Hz as possible, use prescaler 256 (approximately 244 Hz)
  TCCR1B = (TCCR1B & 0b11111000) | 0x04; // CS12 = 1, CS11 = 0, CS10 = 0 for prescaler of 256

  // For Timer2 (pins 3, 11), set prescaler to 1024
  // This changes the PWM frequency from 980 Hz to approximately 61 Hz (16MHz / 1024 / 256)
  // To get as close to 100 Hz as possible, use prescaler 256 (approximately 244 Hz)
  TCCR2B = (TCCR2B & 0b11111000) | 0x06; // CS22 = 1, CS21 = 1, CS20 = 0 for prescaler of 256

and Finally, as written in revised schematic, VCC is 12V. I am using 12V + max 20A SMPS for this project. I think this is kind of overwhelming for 10W LED (and else) control. (I chose this large power only because there was remaining one in my garage.)

though I connected LED VCC and 7805 Input in parallel, 7805 heated up like hell. so I used buck converter to reduce 12V VCC to 5V.

Well done, I'm glad to hear it works better now!

Wrong.
A PicoBuck LED driver is a buck converter.
So now you have two buck converters in series.
Leo..

His post is a bit confusing, but I interpreted the new setup as the buck converter being used to make 5V for the Arduino, and 12V Vcc applied directly to the PicoBuck. That's how it should have been done at least, so perhaps I'm just being optimistic in my reading!

@gr_monk can you post an updated schematic, or at least confirm you're running the picobuck directly from 12V? It should not be fed with 5V.

(1) 12V source directly connected to picobuck
(2) also connected to step down module, to power arduino and logic level for buttons and relay.

Do you still need that 100Hz PWM signal when powering the PicoBuck with 12volt?

Did that 100Hz not give too much flicker/strobing with fast moving things.
Leo..

Yes, as seen in original schematic, picobuck was powered with +12V VCC.

Still, low pwm frequency is required to remove flicker.