Hi
I wonder if someone might be able to explain to me what is going on with my project.
I'm using an ATTiny85 to control some WS2812 LED strips and at first I thought I had timing issues, since it's a very underpowered chip for controlling addressable LEDS.
But, whenever it was plugged into power the LEDs would all light up white.
The strange I noticed was, that when I remove the GND wire connected to the LED strips, they start cycling their colour pattern and as soon as I plug the GND from the LEDs back in, they freeze at white again. It's not a big LED strip (16 LEDs max) running on a 5v 1A PSU, for both the MCU and LEDs.
It is using the Adafruit NeoPixel library, not that it is really relevant to this as I am almost certain it's some sort of hardware issue.
Does anyone have any idea what might be causing this? And suggest anything to fix it?
Do you think that it might help if you posted your sketch, using code tags when you do, a schematic of your project and details of how it is powered ?
-
Don’t do this as the pixels can back feed to the Arduino output.
-
The strip should be properly connected before powering up.
First command should be to clear the strings... for example, FastLED.clear().
The sketch is the basic strandtest program from the Adafruit NeoPixel examples but I've included it below.
In reply to those who said not to disconnect the GND while the pixels are running, if I don't leave it floating then the whole thing halts and all the LEDs come on maximum white. I would definitely prefer all connections to be made. Floating grounds are not good things, for sure.
I don't have a current resistor on the data pin. Would that make a lot of difference? I did read somewhere that it was optional if you had both the LEDs and MCU running from the same power source, but I can add a resistor if you think it would help.
Right.. here's the sketch..
// A basic everyday NeoPixel strip test program.
// NEOPIXEL BEST PRACTICES for most reliable operation:
// - Add 1000 uF CAPACITOR between NeoPixel strip's + and - connections.
// - MINIMIZE WIRING LENGTH between microcontroller board and first pixel.
// - NeoPixel strip's DATA-IN should pass through a 300-500 OHM RESISTOR.
// - AVOID connecting NeoPixels on a LIVE CIRCUIT. If you must, ALWAYS
// connect GROUND (-) first, then +, then data.
// - When using a 3.3V microcontroller with a 5V-powered NeoPixel strip,
// a LOGIC-LEVEL CONVERTER on the data line is STRONGLY RECOMMENDED.
// (Skipping these may work OK on your workbench but can fail in the field)
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
// Which pin on the Arduino is connected to the NeoPixels?
// On a Trinket or Gemma we suggest changing this to 1:
#define LED_PIN 2
// How many NeoPixels are attached to the Arduino?
#define LED_COUNT 16
// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
void colorWipe(uint32_t color, int wait);
void theaterChase(uint32_t color, int wait);
void rainbow(int wait);
void theaterChaseRainbow(int wait);
// setup() function -- runs once at startup --------------------------------
void setup() {
// These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
// Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
clock_prescale_set(clock_div_1);
#endif
// END of Trinket-specific code.
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
strip.show(); // Turn OFF all pixels ASAP
strip.setBrightness(255); // Set BRIGHTNESS to about 1/5 (max = 255)
}
// loop() function -- runs repeatedly as long as board is on ---------------
void loop() {
// Fill along the length of the strip in various colors...
colorWipe(strip.Color(255, 0, 0), 50); // Red
colorWipe(strip.Color( 0, 255, 0), 50); // Green
colorWipe(strip.Color( 0, 0, 255), 50); // Blue
// Do a theater marquee effect in various colors...
theaterChase(strip.Color(127, 127, 127), 50); // White, half brightness
theaterChase(strip.Color(127, 0, 0), 50); // Red, half brightness
theaterChase(strip.Color( 0, 0, 127), 50); // Blue, half brightness
rainbow(10); // Flowing rainbow cycle along the whole strip
theaterChaseRainbow(50); // Rainbow-enhanced theaterChase variant
}
// Some functions of our own for creating animated effects -----------------
// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
delay(wait); // Pause for a moment
}
}
// Theater-marquee-style chasing lights. Pass in a color (32-bit value,
// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)
// between frames.
void theaterChase(uint32_t color, int wait) {
for(int a=0; a<10; a++) { // Repeat 10 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in steps of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
}
// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
// Hue of first pixel runs 5 complete loops through the color wheel.
// Color wheel has a range of 65536 but it's OK if we roll over, so
// just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
// means we'll make 5*65536/256 = 1280 passes through this loop:
for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
// strip.rainbow() can take a single argument (first pixel hue) or
// optionally a few extras: number of rainbow repetitions (default 1),
// saturation and value (brightness) (both 0-255, similar to the
// ColorHSV() function, default 255), and a true/false flag for whether
// to apply gamma correction to provide 'truer' colors (default true).
strip.rainbow(firstPixelHue);
// Above line is equivalent to:
// strip.rainbow(firstPixelHue, 1, 255, 255, true);
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait) {
int firstPixelHue = 0; // First pixel starts at red (hue 0)
for(int a=0; a<30; a++) { // Repeat 30 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in increments of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
// hue of pixel 'c' is offset by an amount to make one full
// revolution of the color wheel (range 65536) along the length
// of the strip (strip.numPixels() steps):
int hue = firstPixelHue + c * 65536L / strip.numPixels();
uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
}
}
}
Yes. Also, add a 1000uf electrolytic capacitor across power supply + and GND.
That is good. Add your resistor on the data pin and the capacitor across power/ground.
I added a 330R in the data line between the MCU and the WS2812 but that made no difference. The LEDs go full-brightness white when the LED ground is connected. With the resistor added, the lights don't even go through their sequence any more either. They glimmer faintly.
I will try adding a cap across the power lines.
Make the smallest sketch to control one WS2812 (the zeroth element in the pixel array). If you get that working, you will see what you need. Let us know your results.
1000uF across the power lines and 330R resistor on data lines make no difference, although the resistor seems to be reducing the data signal, as the lights aren't coming on properly when I remove the GND wire (yes I know I shouldn't be doing that, but it still shows all bright white when the LED strip ground is connected).
Verify if WS2814, WS2812, WS2811...
any good ways to do that? they aren't marked, but the company I bought them from bill them as WS2812B LED strips, and they've never steered me wrong so far.
That is good for me. WS2812.
Try the "smallest complete sketch"
- What are you doing here exactly ?
The strip is to be connected to the controller and power rails, then you apply power to everything at one go.
Okay, I've done this:
strip.setPixelColor(0, 255, 255, 255);
strip.show();
delay(200);
strip.setPixelColor(0, 0, 0, 0);
strip.show();
delay(200);
in the main loop function.
My original code was working fine on the Arduino uno and I've just tested the code above on the Uno and it works fine.
I just can't get it to work properly on the ATTiny85. It's a shame because the '85 is the only small chip I've got available right now. I've got loads of pro micros, pro minis, esp32/8266s but they are overkill for this and have onboard regulators, etc. which I don't really need for this.
I don't know why the ATTiny acts the way it does. Every time I add the LED ground to the circuit, the whole thing just freezes with all the LEDs on white.
I'll probably give up and try a different MCU/ready-made board but it's very frustrating. I couldn't find a lot of info about programming ATTiny85s with platformio. Most of the articles I read were relating to DigiStump.
I am beginning to wonder if this is some sort of issue with chip fuses for clocking or something like that, but I don't want to spend ridiculous amounts of time trying to troubleshoot it.
Thank you everyone for all your help.
That is exactly what happens. I apply power to everything at once and all the LEDs light up bright white. The same sketch works perfectly on the Uno. The only differences are the way the chip is flashed after the firmware is compiled for the different arch.
It worked briefly at one point when I accidentally removed the ground for the LED strip, which I know is not a good idea.
- Show us good images of the actual wiring.
Did you burn the bootloader ?
I just thought i'd ask, since if the clockspeed of the ATtiny is set incorrectly in the fuses, compared to the uploaded sketch then all bets are off timing wise. And chances are that all zeroes are seen as ones.
And it's the thing noones ahs asked so far. Your hardware should be good, the sketch is nothing special. There may still be the issue of the first led being broken, but if it runs fine on the UNO then that's not it.
Gotta be something with the ATtiny85, now i do have 1 or 2 but i have never used them for ledstrip. I have used ATtiny13a 's since an 85 seems like either overkill or not useful enogh, but maybe for a basic thing it's just what you want.
Anyway, burn the bootloader (again ? ) and let me know.
The weird thing is, I can program the chip with platformio, but trying to do it via Arduino IDE just doesn''t work.
I installed the core, compiled the sketch but Arduino IDE couldn't find the tinyUSB I am using to program the chip, whereas platformio can.
The only thing I can think of regarding the strip working without the ground is that somehow the data pin is creating a return path. I agree with everyone who has said... it... should... not.. work like that!