Hardware

See the Parts List for specifics and URLs for the exact parts.

For this project, I had a few hardware goals in mind. I wanted to design and order the printed circuit board (PCB) myself, I wanted to do much of the electrical engineering myself, and I wanted the end circuit to be very power efficient.

Having never designed a PCB before this project, this was an excellent opportunity to learn the entire process from design to manufacturing. I used KiCad for the PCB design and JLCPCB for fabrication. Once I created the schematic in KiCad, transitioning to the PCB layout was pretty straight forward. By watching several YouTube tutorials, I was able to learn the steps and complete the design independently.

I wanted to handle as most of the electrical engineering myself, while still keeping the project's timeline reasonable. To save on time, I made a compromise by using breakout boards for the boost converter and the 7-segment display. If I do a second revision, I plan to design these components myself, which could potentially reduce the cost per unit while also allowing me to have most of the board assembled at the factory.

The main components of the board are an ATtiny84 MCU, a CD4532 8-bit encoder, and an SN74HC595 shift register. Initially, I considered using an ATtiny85, but its limited number of pins made it impractical unless I could use I2C for all peripherals, which wasn’t feasible. The shift register controls the LEDs for the buttons, while the encoder allows the device to support eight buttons using only four MCU pins (three for encoding the value and one for interrupts).

Designing the mechanism for “spinning” the dice was the next major challenge. A Hall effect sensor was an ideal choice for this purpose, but these sensors are notoriously power-hungry, conflicting with my goal of maximizing power efficiency. To address this issue, I powered the sensor through a GPIO pin on the MCU. This approach allowed me to disable the sensor when it wasn’t needed, conserving power during most of the device’s active period.

For the display, I selected an Adafruit breakout board featuring the HT16K33 driver. I used the Adafruit_LEDBackpack library, which also simplified the integration process. However, the library didn’t include commands to put the HT16K33 into sleep mode, which was a necessary feature given its multi-milliamp power consumption. Fortunately, I was able to manually send sleep and wake instructions to the HT16K33.

The final major component was the boost converter. Although I could have integrated this into the circuit myself, my lack of experience with them and the desire to complete the project quickly led me to use another breakout board featuring the TPS61023. This allowed the device to be powered by just two AA batteries, even though the system required 5V. The efficiency of this setup is approximately 88%, which is acceptable but not optimal.

By combining these hardware choices with low-current LEDs and efficient software, I achieved a reasonable power profile. Using Nordic's Power Profiler Kit II, I analyzed the current consumption during different operating modes. At maximum current draw, the device consumes an average of roughly 60mA (see image 1 below), and in deep sleep mode, it consumes about 11µA (see image 2 below). Considering that a typical AA battery has a rough capacity of around 2,200mAh at these draw rates, this translates to approximately 70 hours of operation at maximum current draw and up to 400,000 hours (or about 45 years) in sleep mode.

Current consumption during active mode
Current consumption during sleep mode

Software

See the Github repo for specifics zbauman3/digi-roll.

Initially, I wanted to develop the software for this project using the bare-bones avr-libc. However, since I was using a breakout board for the 7-segment display, this would have required me to write a custom library for I2C communication with the HT16K33 driver. While this was possible, it would have taken more time than I wanted to invest. Instead, I decided to use the Arduino framework for this project.

I'm not a fan of the Arduino IDE, so I tried out PlatformIO. This turned out to be an excellent choice, and I plan on using it for future projects, even though I would have preferred to work with the native AVR framework.

The project required handling multiple tasks concurrently, and I would normally reach for a real-time operating system in such cases. However, the ATtiny84 doesn’t have enough flash memory to support a full RTOS. As an alternative, I chose to use a cooperative multitasking library — AceRoutine. This lightweight library supports coroutines and, for five coroutines (effectively “threads”), it consumes only about 900 bytes of flash and 80 bytes of RAM.

For the software architecture, I used a MVC pattern. This approach allowed for a clear separation of input, state, and output logic. Controllers manage the buttons and Hall effect sensors, views handle the LEDs and 7-segment display, and a single “state” model ties everything together. Overall, this organization worked well, although some controller logic ended up in the state model. I may revisit this in a future iteration to improve the separation of concerns.

The final program occupies 6,994 bytes of flash and uses 269 bytes of RAM.

Media

Uses 2x AA batteries
The battery pack is attached with a long cord to allow the back to slide off

Usage

Selecting A Die

To select a die, press the button for that die. While you are choosing a die, its light will flash to indicate it is selected. Once selected, spin the large D20 spinner to roll. The light for the selected die remains lit when your result is displayed.

Selecting Multiple Dice

If you’d like to roll multiple dice of the same type (up to nine, such as 9d20), simply press the die’s button repeatedly until you reach the desired quantity. The light will flash while selecting. When you’re ready, spin the large D20 again to roll all chosen dice.

After rolling multiple dice, the currently selected die’s light will stay illuminated. Press the die’s button to cycle through the individual results. To see the total of all the dice rolled, keep pressing the button until the = sign appears. The number shown at that point is the sum of your rolls.

Parts List

3D Printed Case

FilamentPartsLink
Prusament PETG Anthracite GreyExternal casePrusa
Prusament PLA Azure BlueButtons, power switch, and dice spinnerPrusa

Electronics

PartDescriptionCountLink
ATTINY84AMain MCU1Mouser
CD4532BE8-bit priority encoder (Buttons)1Mouser
SN74HC595NShift register (LEDs)1Mouser
7-Segment Display BreakoutI2C, 4 digit display1Adafruit
TPS61023 BreakoutBoost converter1Adafruit
WP7113LVBC/D (LED)Low current LEDs7Mouser
2.4K Ohm ResistorsLED resistors7Mouser
Tactile Switches6 x 6 x 5mm buttons8Adafruit
1M Ohm ResistorsButton resistors8Mouser
0.1uF 50V CapacitorsPower stabilization2Mouser
SPDT Slide SwitchPower switch1Adafruit
US5881UAHall effect sensor1Mouser
Battery Holder2 x 1.5V AA1Amazon

Misc

PartDescriptionCountLink
Rubber FeetFor the bottom of the case4Amazon
BearingsFor the dice spinner2Amazon
MagnetsFor the dice spinner1Amazon
Battery ConnectorsAllows disconnecting the battery from the board for easy installation1Adafruit
PCB ScrewsM2 x 8mm4N/A
Hot glueSecuring the display and the magnet holer-N/A
Tacking screwsAttaching the battery holder to the case2N/A
Header pinsAttaching the breakout boards and a ISP connection for programming14N/A