tejashwi.io

Technology explored

author
Tejashwi Kalp Taru
Engineer, Tinkerer, Blogger
Reading time about 9 minutes

A tiny game console based on Attiny85


A tiny game console based on Attiny85

I had some Attiny85 chips lying around my desk and a few free days, so I went looking for projects. I found that Daniel Champagne had already created several games for this chip. His schematics were missing some resistor values, but he replied quickly when I emailed him.

This isn’t a retro gaming device. You can’t play 8-bit Nintendo games on an Attiny85. But you can play games specifically written for it, or write your own.

The OLED Problem

The project uses an SSD1306-based I2C OLED screen. I had a few of these in my lab. I compiled Daniel’s code using the ssd1306xled library from Github. It compiled fine. Nothing appeared on screen.

I tried several different OLED screens. None worked. I tested them with the Adafruit library. They all worked fine. The screens weren’t the problem.

The Github library is a port of the AVR TinuSaur project, and the original is hosted on BitBucket. Searching led me to a Tinusaur article describing compatibility issues. Most OLED screens from China claim to use SSD1306 but sometimes use SSD1315 or SSH1306 instead.

I cloned the original repository and modified it for my Attiny85. Still nothing. Digging into the code, I concluded the I2C implementation itself was broken. You can follow my debugging journey in this issue thread.

The Fix

The Attiny85 has 8KB of flash memory. The game uses about 6KB, leaving 2KB for the OLED driver. Libraries like Adafruit’s or Tiny4kOled would push the program over 8KB. I needed the lightweight ssd1306xled library to work.

I took the latest SSD1306XLED library and replaced its I2C implementation with the working one from TinyI2C. That fixed it.

My working fork is on Github.

The Schematic

While researching the OLED issue, I found a modified version of Daniel’s project by Dave on the element14 community. Dave optimized the Attiny85 pin usage. If you’re interested in this project, watch his video.

PCB Design

The goal was simple: make it as small as possible using SMD components. I used 0805 resistors. They’re small but still solderable by hand.

For quick projects I use EasyEDA instead of Altium. Here are the components I used:

Quantity Manufacturer Part Number Manufacturer Name Notes
1.0 ATTINY85-20PU MICROCHIP Attiny85 IC
5.0 SKQGAFE010 ALPS ALPINE Push button
2.0 MCWR08X2001FTL MULTICOMP PRO 2K resistor
2.0 WR08X1002FTL WALSIN 10K resistor
1.0 MCPWR05FTEW8201 MULTICOMP PRO 8.2K (8K2) resistor
1.0 ERJ6GEYJ392V PANASONIC 3.9K (3K9) resistor
1.0 MCWR08X1802FTL MULTICOMP PRO 18K resistor
1.0 MCABT-458-RC MULTICOMP PRO Speaker
1.0 796136-1 TE CONNECTIVITY CR2032 battery holder
1.0 JS102011SAQN C & K COMPONENTS Power switch
1.0 SSD1306 0.96 inch white OLED screen

Using Dave’s schematic as a reference, I created my PCB:

Design A schematic
Design A front Design A back Design A PCB

Another OLED Mistake

I ordered the PCB, then noticed a problem during the week-long wait. Look at the pin order: VCC-GND-SCL-SDA. Some OLED screens have the first two pins swapped.

two types of SSD1306 OLED screen

You can fix this with trace cuts and jumpers, but I made a second design with configurable pads:

Design B front

The first two pins are labeled 1 and 2 with a 4-pad box for configuration. If your screen is VCC-GND, connect PIN1 to VCC and PIN2 to GND. If it’s GND-VCC, reverse them.

two types of PCB

I call these Design A (specific to VCC-GND-SCL-SDA screens) and Design B (works with either pin order).

Assembly

After a week, the PCB and components arrived.

Calibrating the Controls

The directional buttons connect to PIN 2 (A3) of the Attiny85. The code uses analogRead to determine which button is pressed, but the exact values depend on your resistors and wiring. Use this code to find your values:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void setup() {
    _delay_ms(40);
    SSD1306.ssd1306_init();
}

void loop() {
    _delay_ms(500);
    SSD1306.ssd1306_fillscreen(0);
    int value = analogRead(A3);
    if(value > 0) {
        char buf[20];
        sprintf(buf, "value: %d", value);
        SSD1306.ssd1306_setpos(0, 1);
        SSD1306.ssd1306_string_font6x8(buf);
    }
}

My values:

  • UP: 180-250
  • DOWN: 300-400
  • LEFT: 90-110
  • RIGHT: >400

Update these in the game’s loop function, compile, and burn to the Attiny85. You can use an Arduino as ISP or a USBasp programmer.

running game 1 running game 2

Thanks to Daniel and Dave for the original work.

Downloads

comments powered by Disqus