Jonathan Thomson's web journal

Project Ouroboros Update February 20, 2019

 

I reworked the code and the article for Project Ouroboros. You can see the update by clicking here. When I originally wrote the article in 2011 a USBasp programmer was around $6 on eBay, but now you can buy one in 2019 for about $1.50; pretty amazing.

 

Here’s some code I wrote for the USBasp programmer board I played around with in Project Ouroboros. A bit surprisingly I had no trouble powering a WS2812B strip with just 3.3V. If you run this code on a 5V board you should change LED_STRIP_VOLTAGE to 5, although it’s not strictly necessary because that number doesn’t actually control the voltage. If you do change it to 5 then the power allotted to the LEDs will increase and they will get brighter. I tested the board with 100mW for the LEDs and I had no problems.

 


#include 

#define NUM_LEDS 8
#define DATA_PIN 12 // MISO pin
#define FRAMES_PER_SECOND  125
#define LED_STRIP_VOLTAGE 3.3
#define LED_STRIP_MILLIAMPS 20

CRGB leds[NUM_LEDS];

void setup() { 
    FastLED.setMaxPowerInVoltsAndMilliamps(LED_STRIP_VOLTAGE, LED_STRIP_MILLIAMPS);
    FastLED.setCorrection(TypicalSMD5050);
    FastLED.addLeds(leds, NUM_LEDS);

    pinMode(14, OUTPUT);  // green LED, LOW == ON
    digitalWrite(14, HIGH);  // turn green LED off
}


void blink() {
    static uint8_t i = 0;
    uint8_t brightness_bool = i++/128;
    digitalWrite(14, !brightness_bool);   // green on board LED, LOW is ON
    leds[0] = CHSV(0, 255, 255*brightness_bool);
}


void breathing() {
    const uint8_t min_brightness = 2;
    static uint8_t delta = 0; // goes up to 255 then overflows back to 0

    // for the LEDs in the current state setting the brightness higher than max_brightness will not actually increase the brightness displayed
    uint8_t max_brightness = calculate_max_brightness_for_power_vmA(leds, NUM_LEDS, 255, LED_STRIP_VOLTAGE, LED_STRIP_MILLIAMPS);
    uint8_t b = scale8(triwave8(delta), max_brightness-min_brightness)+min_brightness;

    FastLED.setBrightness(b);

    delta++;
}


void loop() {
    static uint8_t dynamic_hue = 0;

    //blink();
    //fill_solid(leds, NUM_LEDS, CHSV(dynamic_hue, 255, 255));
    fill_rainbow(leds, NUM_LEDS, dynamic_hue, 21);

    //breathing();  // breathing isn't meant to be run by itself. combine it with one of the functions above.
    
    EVERY_N_MILLISECONDS(100) { dynamic_hue+=6; }
    FastLED.delay(1000/FRAMES_PER_SECOND);
}

 

Code
Project Ouroboros on GitHub

Advertisements
 

A smooth breathing effect while using FastLED’s power management February 6, 2019

Filed under: Electronics — jethomson @ 9:01 pm
Tags: , , , ,

If using a FastLED function (e.g. FastLED.setMaxPowerInVoltsAndMilliamps()) to manage how much power your LEDs use FastLED limits the maximum brightness that can be set to a value that does not exceed the requested power draw. So if FastLED determines your power limited maximum brightness is M then calling setBrightness() with a value greater than M will result in FastLED setting the brightness to exactly M.

A breathing effect ramps the brightness up until it reaches the maximum brightness then ramps the brightness back down to a minimum brightness then starts the whole cycle over again. A naive approach would be to use a triangle wave that goes from 0 to 255 and back down to 0 as the input for setBrightness(), but if the power limited maximum brightness M is less than 255 then the brightness will plateau at M, and the brightness will remain fixed until the triangle wave input falls below M again. My breathing() function achieves a continually changing brightness by setting the peak of the triangle wave to M. However, M changes based on the number of LEDs currently lit and their colors, so breathing() recalculates M before setting a new brightness value.

 
Snippet from the breathing code example available on GitHub:

void breathing(uint16_t interval) {
    const uint8_t min_brightness = 2;
    static uint8_t delta = 0; // goes up to 255 then overflows back to 0

    static uint32_t pm = 0; // previous millis
    if ( (millis() - pm) > interval ) {
        pm = millis();

        // for the LEDs in the current state setting the brightness higher than max_brightness will not actually increase the brightness displayed
        uint8_t max_brightness = calculate_max_brightness_for_power_vmA(leds, NUM_LEDS, 255, LED_STRIP_VOLTAGE, LED_STRIP_MILLIAMPS);
        uint8_t b = scale8(triwave8(delta), max_brightness-min_brightness)+min_brightness;

        FastLED.setBrightness(b);

        delta++;
    }
}

 
 
You may have read that you need to apply gamma correction or convert luminance to brightness so that the LEDs have a linear response. That is what I tried first, I never had success with that approach because of the clamping effect FastLED’s power management. After I figured out I had to determine the maximum brightness possible under power management conditions I found that the output of the LEDs looked linear to me using just a triangle wave, so I didn’t try to apply a correction curve. A point that confuses me is whether setBrightness() is actually controlling the brightness or the luminance. I couldn’t find a correction curve being applied when looking through the FastLED code.

 

The function calculate_max_brightness_for_power_mW returns the same value as calculate_max_brightness_for_power_vmA so I’m mentioning it in this write-up to help people find info on it too.
 
 
My example breathing code on GitHub
FastLED’s notes on power management
Power management functions documentation
LED Brightness to your eye, Gamma correction – No!