Fluorescence clocks by the coast. Peniche, Portugal.
While living out of a van on the road through the most stunning landscapes on the west coast of Portugal, Frank finds new inspiration for the iconic Fluorescence VFD clocks.
Back in 2021, there were a few features I had always wanted to bring to the Fluorescence VFD clock. Now, while traveling along the Algarve and up Portugal’s wild west coast with Evelyne in our self-converted camper, Humbär, I’ve finally found both the time and inspiration to bring those ideas to life. To all current and future Fluorescence owners—exciting updates have arrived! Here’s what’s new in the latest software release:
✨ Digit Fading
Smooth fade-out to black and fade-in for digit transitions
Direct blending between numbers for an even softer visual effect
🌈 Pulsed Rainbow LED Fade
Beautiful, pulsating fade-to-dark for a more dynamic, ambient glow
🔧 Under-the-Hood Improvements
Function buttons F1–F4 now respond more crisply and reliably to short and long presses
Rare cases of LED flickering and glitching have been resolved
Flickering in LED chase-fade mode has been eliminated
Entering DFU mode for firmware updates is now more robust and dependable
This update brings Fluorescence even closer to what it was always meant to be - refined, expressive, and smooth.
A warm glow in the soft evening light in Portugal.
The new studio on wheels where the clocks are hand-crafted.
Digit Fading
Normally, when the time changes—for example, from 16:19:59 to 16:20:00—the digits that need updating (1, 9, 5, 9) instantly jump to their new values (2, 0, 0, 0). It’s a sharp transition, and while functional, it can feel a bit abrupt.
Digit fading smooths out this change. Instead of instantly switching, the outgoing digits gradually fade to darkness, while the new digits fade in from dark to full brightness. The result is a seamless, elegant transition that gives the clock a more fluid, polished feel.
How is Digit Fading Implemented in Software?
Digit Fading builds on the same core principle as the night-shift & dimming feature introduced in the previous versions of Fluorescence. Back then, dimming allowed the entire VFD display to gradually shift its brightness level.
Now, instead of applying that fading to every digit, Digit Fading applies it selectively to the digits that are changing. When the time updates, only the old digits fade smoothly to black, and the new ones fade in from black to full brightness. The transition is broken down into a series of rapid steps, updating brightness levels frame by frame via PWM control of the grid voltage.
The display is updated using hardware timer TIM16, running at 1200 Hz. To achieve smooth transitions, digit fading is implemented using 16 brightness steps for fading out the old digit and 16 steps for fading in the new one.
Each step modulates how long a digit stays lit within a cycle using PWM (Pulse Width Modulation). For example:
In step 1, the old digit is shown for 15/16 of the PWM cycle.
In step 2, it's shown for 14/16, and so on…
By step 16, it's only on for 1/16 of the cycle before fully disappearing.
Simultaneously, the new digit fades in—starting from 1/16 brightness and increasing until it's fully lit.
Each brightness level is subdivided into 16 PWM pulses, making the full fade process span 2 × 16 × 16 = 512 PWM ticks, or about 426 ms at 1200 Hz.
Pulsed Rainbow LED Fade
Now this is an eye catching innovation to the LED fading patterns of Fluorescence. In the existing smooth and gentle color fading patterns, the pulsed rainbow glow stands out. Given the excellent groundwork of the Fluorescence software this was a quick addition: Unlike conventional LED libraries, the Fluorescence colors are represented in the HSL color space, it’s H for hue - which is the color position in the rainbow, S for saturation - how punchy the color looks and L for lightness - from absolutely dark to fully bright. So wait a sec, doesn’t this make a pulsating glow extremely easy?
struct hsl_t *color = &base->color_1; uint8_t value = self->position & 0x7F; // Extract value (7 lower bits) uint8_t direction = self->position & 0x80; // Extract MSB as direction // If not time to update, increment div_counter if(Time_Event_Update(&self->clock)) { if(direction) { self->position = (value == 0) ? 0 : self->position - 1; } else { self->position = (value == 127) ? self->position | 0x80 : self->position + 1; } color->l = value; } LED_Color_Fader_Next(base);
Yes, you’re right! That’s all of the logic! One timer which updates depending on how fast the heartbeat and one counter which counts up, then down, then up and so on. This counter is the lightness (L).
Debugging button responsiveness in a café. Sitting next to a software developer is mysterious. Sitting next to a hardware developer?
Button Improvements
The clock buttons on Fluorescence long suffered from slight glitches which can get super annoying. In an already complex button navigation system, finally fixing the glitches improve the user experience by a lot. With the new firmware, short and long presses are detected crisp and accurate.
A Flicker Free LED Experience
Especially with a more packed digit fading, slight glitches and flickers on the SK6812 LEDs were apparent in the latest software of Fluorescence. Using in-depth code analysis from ChatGPT, it helped me to identify that the root cause was most likely to be caused by shared use of one DMA channel (DMA1) across the LED PWM interface and the SPI display interface. Now
DMA Channel 1 is exclusively reserved for WS2812B/SK6812 LED PWM communication
DMA Channel 2 is shared between SPI VFD display and USB ADC sensing - which is used very rarely
This way, the LEDs light up 100% glitch-free.