Hack the Digispark BlinkStick and ATtiny85 Microcontroller into a FadeStick

Digispark BlinkStick USB development board with APA106 LED
Digispark BlinkStick USB development board with APA106 LED

Background

The BlinkStick device came from Kickstarter as an RGB LED connected to a USB port to signal some notification like a new email. With an API you can send it commands to change the LED color and make it, well, blink. The hardware is based off the ATtiny85 8-pin, 8KB AVR microcontroller. Later a company called DigiStump made a similar-but-LEDless USB dongle called Digispark for Arduino development using the same ATtiny85. It was found that by soldering an LED and with some tweaks1 the open-source BlinkStick firmware will run on the Digispark USB development board.

Six years have gone by and the BlinkStick Github repo has gone dormant. The API code repo has also gone cold with only a smattering of forks.

Goal: My project this weekend was to fork both the C firmware and the Java API to make the Digispark do something never done before: execute color patterns on the microcontroller, not the host CPU, in a new device called the FadeStick.

Motivation

My compute cluster has 28 CPUs and each has a USB slot for a status LED. I’m currently using the stock BlinkStick firmware and Digispark clones2.

The problem is that the host CPU must manage the timing and duration of the colors for interesting and colorful patterns. This means my compute cluster is spending many CPU cycles on just looking pretty. My goal is to hack the abandoned firmware to add a mechanism to upload a color pattern so the microcontroller, not the host CPU, executes the color pattern and timings. Let’s push it to its limits.

Tip: If the ATtiny85 chips are bricked, let’s use a high-voltage serial programmer (HVSP) to reset and rescue them.

Hardware

The very first hack is to disable the red power light on the Digispark board. This is an in-circuit light and cannot be disabled with software, but a scalpel does the trick.

Digispark disable the always-on power LED with a scalpel
Digispark disable the always-on power LED with a scalpel

I tested both the APA106 and WS2811 LEDs and the APA106 LEDs were superior in brightness, step, and diffusion. Here is an example distinction between the two at the same brightness.

APA106 vs WS2811 LEDs at same brightness
APA106 vs WS2811 LEDs at same brightness

The completed device looks like this prototype:

Digispark with APA106 RGB LED, 330 ohm resistor, and small capacitor
Digispark with APA106 RGB LED, 330 ohm resistor, and small capacitor

Software progress

To be honest, I failed in my first 23 attempts to hack the C firmware. I didn’t know anything about interrupt vectors, maintaining registers, and how to deal with 8 bits of data transfer at a time – Java has spoiled me so much. Plus, I have no idea how to debug or trace the microcontroller execution, just trial, error, and patience. I encountered race conditions, lock-ups, and many times the computer wouldn’t recognize my Digispark. I was trying to do something new with this firmware so of course it was tedious and fraught with frustration.

Eventually, I figured out how to create a mutex in the microcontroller world, and came up with a strategy to keep the I/O responsive while the color pattern is executing, as well as upload said color pattern. My hope is that these improvements will be useful to others who want to do neat things with the Digispark and BlinkStick firmware.

Github project repos

How it works

A pattern of up to 62 colors and delays can now be uploaded in a single request. In one API call you can flash the LED red a couple of times with the following byte array payload:

To make more sense, let’s group the bytes like so:

Even more clearly:

You may be wondering how “2” signifies a “20 ms” delay. That is because the range of a byte is 0-255, so I made a judgment call to multiply that by 10 in the backend. That means a delay between 0 and 2.5 seconds is possible per color with a resolution of 10 ms. Also, the 62-color limit is due to a 254-byte v-USB transfer limit. Additional routines could be added to extend this limit, but this is good enough!

Main loop

Essentially the main loop iterates over the color pattern buffer to set a color then waits for some delay and continues.

Operation

If the Digispark is idle, it will accept a color pattern to upload and execute it immediately. If it is executing a color pattern, it will accept but ignore any new color patterns until it is idle again. This way the I/O never blocks the host CPU. A color inspection can also be performed anytime meaning the host can query the current color even during a color pattern execution.

Also, the Digispark will turn off the led after 60 seconds of inactivity. The reason is that if the status LED is on and green, then the host goes away, the green status LED will be misleading. I want my LEDs off when the host is idle or shutdown.

Upload

The firmware works best with newer Micronucleus v2.04. Download the main.hex binary from my repo or compile it with make. Then, upload it to the Digistump with:

Brownout-detect (reset) circuit

It turns out that an under-voltage will damage the EEPROMs of the ATtiny85 chips. For example, if the power supply is switched off but it takes a long time for the capacitors to bleed, then the voltage decay will be a gradual descent from 5V to near 0V. During that time the MCU will behave in unexpected ways. For example, here is a snapshot of an EEPROM dump after such an event:

Damaged EEPROM memory
Damaged EEPROM memory

This is the power supply voltage decay after being shut off that caused the EEPROM damage:

Gradual PSU voltage bleed decay
Gradual PSU voltage bleed decay

The solution for this problem is to enable the BOD (brownout detect) circuit which is disabled by default. When enabled, under-voltage causes the MCU to reset so it doesn’t run amok on the insufficient voltage. To enable the BOD, the high fuse can be set to 0xDD to activate the BOD threshold to 2.7V.

Results

Digispark BlinkStick ATtiny85 status LED animation
Digispark BlinkStick ATtiny85 status LED animation
Success: The Digispark now accepts color pattern uploads and can be controlled with the accompanying Java API. Color patterns are now executed on the ATtiny85 thus completely freeing up the host CPU from animation duties. This custom device and firmware together will be referred to as FadeStick.

Application

With twenty-eight of these FadeSticks, I can monitor the system resource usage of the processors in my prototype compute cluster.

Compute cluster using 28 custom Digistump BlinkSticks
Compute cluster using 28 custom Digistump BlinkSticks (now called FadeSticks)

Notes:

  1. Specifically, changing the I/O pin locations in code.
  2. I ordered a handful of seemingly genuine devices from Amazon and it turned out they are clones (rev 3 models do not exist!), unfortunately, but they work perfectly well for 1/8th the price.