ATTiny dice
@ 0x4C4A | Saturday, Apr 11, 2015 | 5minuteRead | Update at Saturday, Apr 11, 2015

I was approached and asked to make something for a soldering workshop during the RTU Open Door day on April 11, this is what I ended up planning and producing.

The short version is that it’s an Atmel ATTiny 24A based charlieplexed LED dice, fed by a CR2032 coin-cell.

The device requires very few parts and is quick and reasonably easy to solder. Even though some newcomers are intimidated by SMD parts, this board should prove to be very easy to finish, provided adequate pincers and a good soldering iron.

Assembly instructions

  • D1-D9: LEDs. The dot denotes the cathode (the pin which has the lower voltage, when the LED is lit).
  • R1: 10k resistor
  • R2-R8: 100R resistor
  • C1,C2: 100nF capacitor
  • ATTiny: The microcontroller’s first pin is denoted by the dot on the copper layer.
  • Button: Any SMD button with a compatible footprint will work. Just make sure it commutates the right pins.
  • The dots: The six dots you might have noticed, are for programming with pogo-pins. The copper circles are for drilling alignment holes for a pogo-pin programmer.
Gerber image


Schematic image

Bill of materials

  • 1x ATTiny 24A SOT14
  • 9x 1206 LEDs (Blue LEDs might not work due to too big of a voltage drop)
  • 7x 1206 100R Resistor - The nominal depends on the LED colour (voltage), however 100R should work pretty good with any colour (should be a high brightness LED though).
  • 1x 10k 1206 Resistor
  • 2x 100nF 0805 Ceramic capacitor
  • 1x 6*6mm surface mount pushbutton
  • ~27*50mm Etchable copper board


The device is a basic state machine, which has 4 states:

  1. Deep Sleep (Power Down in the ATTiny datasheet)- Almost everything is off, except for the pin change interrupt.
  2. Waiting - Both timers are working. Upon entering this mode Timer1 starts counting down 10 seconds, after which it’ll switch the device to Deep Sleep unless a button is pushed.
  3. Rolling - Activated by pushing a button in Waiting or Slowing states, resets Timer1 period to ~1 millisecond and starts “rolling” the die. Exited by releasing the button.
  4. Slowing - Activated upon releasing the button in Rolling state. Increases the Timer1 period on every capture-compare match, therefore slowing the roll. Upon reaching a threshold, stops the roll (making sure to be exactly on a dice “face”), saves the value and goes to the Waiting state.
State machine image

Timer0 handles the charlieplexing of the LEDs. Since this is a single layer board, charlieplexing seemed like a great way of simplifying the design of the board. The timer calls it’s interrupt at around 4kHz(SysClk/256) and iterates through all nine LEDs, giving each the same amount of time to be on(or off). Since the time-per-LED doesn’t change depending on the displayed pattern, the LEDs maintain a constant brightness.

Timer1 handles the timing operations. It’s always on a SysClk/1024 divider, so one cycle takes around a millisecond. While rolling or slowing, it constantly rolls the dice face. Additionally when slowing, it raises it’s capture-compare threshold steadily, when rolling it sets the capture-compare threshold to 1 and when starting to wait, it sets the cc threshold to 10s and upon reaching it, it’ll switch off both timers, turn off any LED still on and go to deep sleep.

The button interrupt transitions between states and turns on the timers, when returning from deep sleep.

Schematic, PCB, Code

Available in the GitHub repository.

Some comments

The power consumption in the deep sleep mode is incredible - I measured it to be 0.14uA, so this device, with limited use, can remain functional for years.

During the initialisation, both of the timers are turned on, however this isn’t technically necessary. The reason why it still is in the code - the device didn’t wake up from deep sleep properly unless the timers were enabled during the initialisation. To be honest, this was just me not being willing to spend time searching for a mysterious reason and focusing on more important things. Also, I could’ve not stopped the timers, when going to deep sleep, because every peripheral except for the GPIO interrupts is off during deep-sleep anyway, however it seemed more tidy to switch off the timers like that.

The dice faces are stored in an array and are stored together, so that the dice just scrolls through them, to create more of a rolling effect. This means that firmware-wise the amount of faces can be extended to whatever the user desires. Here’s an excerpt from the code to illustrate:

/* Frames describing the LED patterns to be shown
 * 0x04 - first LED, 0x02 - second LED, 0x01 - third LED
 * 0x04 + 0x02 = 0x06 : first and second LED etc. */
uint8_t frames[FULL_FRAME_COUNT] = {
    /* One */
    0x00,   /* --- */
    0x02,   /* -X- */
    0x00,   /* --- */
    /* Two */
    0x04,   /* X-- */
    0x00,   /* --- */
    0x01,   /* --X */
    /* Three */
    0x01,   /* --X */
    0x02,   /* -X- */
    0x04,   /* X-- */
    /* Four */
    0x05,   /* X-X */
    0x00,   /* --- */
    0x05,   /* X-X */
    /* Five */
    0x05,   /* X-X */
    0x02,   /* -X- */
    0x05,   /* X-X */
    /* Six */
    0x05,   /* X-X */
    0x05,   /* X-X */
    0x05,   /* X-X */
    /* One - duplicate, so that looping is easier */
    0x00,   /* --- */
    0x02,   /* -X- */
    0x00    /* --- */

About me

I’m an electronics engineer with experience in software development. I enjoy building things from the bare metal up to the software UI. My interests include music, audio synthesis and manufacturing (wood/metalworking, 3D printing etc.).

Social Links