A controller for a WS2812 LED strip mounted behind the back of my sofa. It uses a STM32F1 microcontroller (on a BluePill dev board) programmed using libopencm3.
The LED strip should display slowly changing light patterns and give some indirect lighting to my living room by shining on the wall behind the sofa.
The patterns it displays consist of “sprites”. Sprites are generated at random intervals and random positions. It starts small and dim, gets brighter, lingers around for a while, then expands and gets gradually dimmer until it disappears. Sprites will always stay the same color throughout their whole lifetime.
There’s a rotary encoder which lets you access a kind of menu to configure the color choices of the sprites. Saturation and brightness can be set globally, so I can control whether I want more white light or more colorful animations. The choice of colors can also be influenced to favor some colors over others.
Pushing down on the knob cycles through the following modes:
- Select saturation. Lower saturation means brighter, more white-ish light, higher saturation makes the animation more colorful.
- Select brightness.
- Select hue bump range start. Normally the color generator cycles through all hues equally The “bump” makes a section of the hue space larger or smaller.
- Select hue bump range end. Parameter two is the end of the bump.
- Select hue bump steepness. Having selected a range, you can either make it steeper, meaning more of the hue range is compressed into this range, or flatter, which means there are less colors in this range. The three hue bump parameters can be used to make the generator prefer certain colors, by including them in a very flat bump range, or excluting them from a very steep one.
- Cycle speed. How fast does the color generator cycle through colors. Making the generator faster makes a more colorful animation, while a slow generator will generate more uniform patterns which change over time.
When using the menu, the current settings of the color generator are previewed over the whole LED strip, with flashing LEDs indicating the start end end of the “bump range”.
Calculating the sprites is rather compute intensive for that little STM32F1. To keep a steady frame rate, while the current frame is being pumped out using DMA, the next frame is already being computed. The timing is still a bit tight, and in order to get all the sprites summed up quickly enough, I need to make use of the ARM’s saturated add (usat
) command. For some reason, gcc doesn’t generate this command for the STM32F1 (for the STM32F4, it does!) - so there’s a little bit of inline assembler needed for adding the RGB color structs together.