~ Arnalog Buttics ~

Project Origins

I stumbled upon this ATtiny85 handheld console project page by Mira&Luna. It seems to be based on another project called Tiny Joypad. Looking at that schematic, I noticed that 3 pins are used for 5 buttons. Because Up-Down and Left-Right movement is impossible, these can share a pin. The ATtiny85 has a few analog pins which can tell the buttons apart.

However, I noticed the reset pin was taken, which can make reprogramming the MCU using ICSP difficult. An old thought bubbled up about using binary resistor values to put even more buttons on a single analog pin. It could be unreliable because resistors are not "ideal" components, but have an unknown variance as indicated by the Tolerance value. The old beige carbon resistors are less precise than the blue ones. Also, other parts of the physical circuit, as well as noise in the ADC could further blur things. And what about switches with intermittent contact? I'd guess rubber-dome buttons would work poorly.

I did a quick practical test and easily got three buttons to work, even when using less than ideal resistor values... so I got curious and wrote a simulator capable of generating a sort of histogram. Input is button count, resistors values and tolerances.

Four buttons produces 16 combinations. I suppose with precision components, five or six buttons is the limit. Regular 1% resistors run into problems at four or maybe five, so I I split my six buttons them between two pins. This complicated things because the pullup resistors needed diodes (I used 1N5817). Unfortunately it changed the properties of the voltage divider in a way I failed to model so I was back to making practical measurements...

This is my design for 5×7cm prototype board (18×24 holes). I enjoy trying to make these single-sided and structured, but when I added the ICSP header as an afterthought I needed to use a few jumper brackets. I wasn't sure if this would work until I actually built it... but it did. Laying out the traces manually in Photoshop because is a sort of pleasant Tron-bike game and I haven't bothered to learn Eagle or KiCAD. I wanted to design a case for fun, and to keep it small I imagined some kind of sandwich solution, but (with through-hole) it'll get too thick for that to look pleasing.

This schematic with some questionmarks left to straighten out. I'm unsure what kind of battery to use. Maybe AAA and a step-up? Later I found some 5K1 resistors, which of course is closer to 5 than 4K7 (or 4.67 like all mine seem to be). However, my code is configured for 4K7 now and my sim results don't show much difference.

Initially I wanted to use a 3.3V CR2032 battery like other similar designs... but ICSP programming is likely 5V and might poo on certain components. However, I noticed that my display, a GM009605, has a 5V->3.3V 662K LDO configured by two zero-Ohm jumper resistors so the screen is 5V tolerant. I kinda would prefer using 5V but don't know what battery to use yet.

This thing should sort of be compatible with the existing game library but would need new button and speaker code. I have that extra fire/action button to play around with too.

I suppose the ATtiny85s could be put on SIP cards and made into game cartridges. These cartridges could then have ICSP headers rather than the main console.

Test fit. Turns out that's a buzzer/beeper so I had to find something else. I discovered that some (cylindrical) speaker have legs that are not 0.1" friendly (but can be bent into position) It might also be possible to use an old phone speaker as those are heavily miniaturized.

When I solder I generally use component legs bent into little monorails. I never drag solder, which is not only wasteful and unhealthy, but it can also cause problems on double-sided prototype boards like the green ones (great for SMD too).

Nearly finished soldering (ended up pretty close the to the schematic) and moved on to testing the buttons using an ATmega328P through DIP-8 socket. I was worried that these black, more clicky switches might have more bounce but nothing shows on the LEDs anyways. When I hold a button down carefully in an intermittent state I just get flicker on its own LED so that's nice.

Huzzah! It's Alive! Powered though ICSP header hence the red LED. Because the green LED loses in a fight with the red (they share a 6K8 resistor), it's only on in main power mode due to the switch wiring. It's important that the main LED does not blind the user and the flat green ones I have are pretty faint. I don't have a datasheet for any of my LEDs though.

The display (or rather its 662K 3.3V regulator) rests on a 4x2 header. This means the angled header on the display sits soldered far out / on the edge of the pins (as seen on front image).

Redesigning the case (WIP), now fully enclosing the PCB. I didn't want to do that initially as it makes the screen look smaller. I compensated with a... Sorgkant as we say in Swedish... black border around a funeral letter. The buttons are going to need some kind of extension. Well the +pad at least as that tilts and the pivot point can't be too far down I don't think.

A Tamagotchi game might suit this handheld's system specs. Nothing too redraw heavy. Will have to compile with LTO and gut any libraries down to barebones. Clock speed is... I think 1 MHz factory but it can be set to 8 (no external clock). Sounds slow, but it's millions of instructions per second with no OS overhead.

1/2 KB SRAM!     8KB Program Flash ("ROM")    1/2 KB EEPROM ("Drive")
PC speaker.      6 buttons.                   128x64 1-bit OLED graphics.

I skimmed the SSD1306 datasheet. There are some interesting features like inversion, scrolling, remapping how the onboard screen RAM is read. Clever use of offsets might speed up partial redrawns. It doesn't sem possible to use the screen RAM as extra storage over two wire. A 128*64 pixel in 1-bit is 1KB so having a title screen uncompressed in MCU program memory will be expensive. RLE/dictionary compression is only effective for some types of graphics. The ATtiny85 will need something some lean and mean code (likely work already done by someone). The Adafruit libraries are bloated by genereral purpose / safety stuff.

This 32KB Atmel24C256 i2c serial memory could be used as a Character/Font/BootScreen/Song memory, a sort of "Mascot ROM", cementing a stronger identity. I see a CH341A eeprom programmer on ebay for 3 bucks but I guess they can be programmed from a larger Arduino too. Defining graphics in the MCU PROGMEM eats up a lot of space and any decompression routines become proportionally large and are not fun to deal with either. I already have an i2c bus but it seems I'm out of space on the PCB...

I couldn't find an i2c eeprom in a 6 or 4 pin through-hole package. A 4-pin SIP would be so nice. The 24C256 can be modded into a SIP as the righthand pins can all be tied to GND and the i2c pins are on the left side. Might need resistors... not sure. I could stand it up to the right of the speaker. The speaker might might bump the volume disc if moved over. 32KB is enough for 32 full screen images or sprite sheets.

Earlier 3+3 button prototype joypad test. Have you ever seen resistors standing so tall and proud? These red flat buttons are less clicky than the black ones.

Below is the code (for the 328P at the moment). There's a lot of debug #ifdef that can be removed later. I'm packing the 6 button states into a single byte after polling the 3+3 buttons. Let's hope the HTML doesn't eat characters.

// ARNALOG BUTTICS Version 0.91 - By Arne, 2020 April 11-13 - www.androidarts.com

// Read three buttons on one analog pin. However, I have two groups of buttons, each in this config.
// USB 5V -->|-- 4K7 pullup ---+---- Analog measure 0-1023 (regardless of voltage afaik.)
//                             |     Voltage division point. Value is ( 1024 / TotalR ) * ButtonsR
// GND ------ 4K7 --- SwA(B) --+     
// GND ------ 10K --- SwL(D) --+
// GND ------ 20K --- SwR(U) --+     ButtonsR = 1 / ( 1/4K7 + 1/10K + 1/20K .. )   ( when all pressed )

// Schottky  0.267V 46.1K  Note: With 2 button groups the pullups need diodes it seems. 
// 1N4001    0.54V  ?      Diodes have voltage drop and resistance... 
// 1N5817    0.18V  0.854K  <-- used this.

//   U                  1                                7 0 1
// L o R   B   A      8 o 2  16  32  (BuB's bit values)  6 x 2  (JoyAngle)
//   D                  4                                5 4 3

int  JA = 0;           // Storing ADC pin's button measurement. Ints are 16-bit signed.
byte BuB = 0;          // Complete joy Button Bitfield, 6 bits used. Written as B00000000 for clarity.
byte JoyAngle, JoyFire;// Simpler to deal with.

#define JOY_UP = 0;   JOY_UPRIGHT = 1;  JOY_RIGHT = 2; JOY_DOWNRIGHT = 3;  // Perhaps handy.
#define JOY_DOWN = 4; JOY_DOWNLEFT = 5; JOY_LEFT = 6;  JOY_UPLEFT = 7; 

#define DEBUG_LED      // LEDs on D3-D8?
#define DEBUG_SERIAL   // Feedback over serial?

void setup()
{  
  #ifdef DEBUG_LED
    pinMode(3, OUTPUT);    // Response test using LEDs on digital pins 3-8.
    pinMode(4, OUTPUT);    // Could probably take a whole port and just write joypad byte,
    pinMode(5, OUTPUT);    // but this is just temp debug.
    pinMode(6, OUTPUT); 
    pinMode(7, OUTPUT); 
    pinMode(8, OUTPUT); 
  #endif
  #ifdef DEBUG_SERIAL
    Serial.begin(9600);    // More debug output.
  #endif
}

void loop()
{
  PollButtons();
  delay(10);              // 10ms. Poll rate. Doing no debounce.
}
  
void PollButtons()
{
  JA = analogRead(A0);          // First analog read.
  BuB = DecodeJAButtons();      // Turns JA into 3 bits. Some simple games only need one read!
                                // Might be useful to remember old BuB somewhere though?
  #ifdef DEBUG_SERIAL
    Serial.print("Analog read 1: "); Serial.println(JA);
    Serial.print("BuB 1: ");         Serial.println(BuB, BIN);
  #endif
  
  BuB = BuB << 1;               // Move over and make room. Bits are actually interlaced together.
  JA = analogRead(A1);          // Second analog read.
  BuB = BuB | DecodeJAButtons();// Superimpose three more bits from second button set.
  
  #ifdef DEBUG_SERIAL
    Serial.print("Analog read 2: "); Serial.println(JA);
    Serial.print("BuB 2: ");         Serial.println(BuB, BIN);
  #endif
  
  JoyAngle = DecodeJoyAngle();  // A useful clockwise 8-way angle, starting up at 0.
  JoyFire  = (BuB >> 4);        // 4-bit nibble: --AB, four possible states. > 0 is any button.
  
  #ifdef DEBUG_LED              // Instead of bitRead(BuB, n)
   if ((BuB & B00000001) != 0) {digitalWrite(3, HIGH);} else {digitalWrite(3, LOW);}
   if ((BuB & B00000010) != 0) {digitalWrite(4, HIGH);} else {digitalWrite(4, LOW);}
   if ((BuB & B00000100) != 0) {digitalWrite(5, HIGH);} else {digitalWrite(5, LOW);}
   if ((BuB & B00001000) != 0) {digitalWrite(6, HIGH);} else {digitalWrite(6, LOW);}
   if ((BuB & B00010000) != 0) {digitalWrite(7, HIGH);} else {digitalWrite(7, LOW);}
   if ((BuB & B00100000) != 0) {digitalWrite(8, HIGH);} else {digitalWrite(8, LOW);}
  #endif
  
  #ifdef DEBUG_SERIAL
    Serial.print("Button Byte: "); Serial.println(BuB, BIN);
    Serial.print("Joy Angle:   "); Serial.println(JoyAngle);
    Serial.print("Joy Fire:    "); Serial.println(JoyFire); Serial.println(" ");
    delay(1400);
  #endif
}  
  
byte DecodeJAButtons()
{ // If-Else block mapping various ranges to 3 bits/buttons. Called twice, possibly.
  if      (JA > 914) {return B00000000;} // None pressed.
  else if (JA > 739) {return B00000001;}
  else if (JA > 626) {return B00000100;}
  else if (JA > 536) {return B00000101;}
  else if (JA > 467) {return B00010000;} // Could also set individual button variables here I suppose.
  else if (JA > 419) {return B00010001;}
  else if (JA > 380) {return B00010100;}
  else               {return B00010101;} // All must have been pressed.
  //    Finally interlaced as --ABLDRU    (Could spell BALDUR but I didn't.)
}

byte DecodeJoyAngle()
{ // Clockwise 0-7, ignores illegal/impossible angles. Could treat UDL as L though. Other ways to do this.
  switch (BuB & B00001111)
  {
    case B0001: return 0; break;
    case B0011: return 1; break;
    case B0010: return 2; break;
    case B0110: return 3; break;
    case B0100: return 4; break;
    case B1100: return 5; break;
    case B1000: return 6; break;
    case B1001: return 7; break;
    default: return 255; break;
  }
}

Here's some loose display code for my particular GM009605. I borrowed took this code from the webz and also installed the two Adafruit libraries. I wired it up using A4--"SDA" and A5--"SDK" (SDL me thinks) (also this is on the ATmega328P!), and then just 5V & GND. The display apparently does some regulation onboard.

#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>

// OLED display TWI address (for model GM009605)
#define OLED_ADDR   0x3C

Adafruit_SSD1306 display(-1);

#if (SSD1306_LCDHEIGHT != 64)
#error("Screen height error?");
#endif

// -------------------------------------------------------------------------

// Call from setup()
void DispSetup() {
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.clearDisplay();
  display.display();
}

void DispSomething() {
  display.clearDisplay();

  display.drawPixel(0, 0, WHITE);  display.drawPixel(127, 63, WHITE);

  display.setTextSize(1);  display.setTextColor(WHITE);
  display.setCursor(5,5);  display.print("Tiny Panties.");
  
  display.display();
}

Another Arnuino (Ardumite?)

But Why?

The original Arduino board design has some problems with header spacing and labelling, but is otherwise not bad. I felt compelled to do another Arduino redesign though, this time closer to the original than my square thingy on another page. I spent some time looking at schematics to make sure I at least didn't make any huge mistakes.

First I wanted to have a recognisable silhouette and chose the iconic "folder" shape. I added silkscreen effects to further push visual branding. I think having a visual identity is something Arduino got right. There are many boards which are quite anonymous looking.

I wanted to make sure that the holes and headers match (align to) a 7x5cm prototype board, so I drew the whole thing on a 0.1" grid. The board also has an "up" so all text is readable, including IC text.

The RX&TX LEDs are not connected to the 328P, only the serial IC (on dedicated pins), however, they share a resistor package with the actual RX&TX lines to the 328P wires so it' s useful but maybe somewhat misleading to place the stuff where I did, but I separated RX and TX out because I tend to avoid those pins until last.

Over the serial IC I have added a Power/ON RGB LED + resistor package, the idea being that the user can drive the two remaining channels from any pin. I had two unused header slots top left and gave them vias for it.

The pin 13/L LED is isolated using an OpAmp but my LED kinda far off. I'm not sure if it's needed because the RGB LED can be used now.

The vertical interlocking feature was mostly added to support "knolling", which is pleasing... but unlikely to serve a practical purpose.

I removed the ICSP header for the serial/usb chip because it's rarely useful. I suppose there could be pads on the back.

As for the prototype board, maybe it's not so useful, but I've been wanting something which can do a bit of each. There are pads for USB B, Barrel Jack, DE-9, C64 edge conn., and SOP16. SOP pads can also take small SMD components. The notches are for snapping it apart.

Microchip VALKYRIE

Pitch

Well, here's an idiot fantasy project/pitch from 2019 that I likely won't have time to wrap up. Meant to be a SBC+TV_BASIC+MCU+ZX-like thing. A fictional partnership between Microchip (mcu) and Logitech (plastics). Bitbanging would perhaps work poorly from BASIC, but there could be a few built in "libraries" for high frequency and timing sensitive stuff. One could debug directly onto the TV. BASIC is pretty powerful when it comes to tweaking programs and inspecting variables.

The main pitch sheet.

Unfinished work on some of the internals. Had some wonky idea about using a super long shift register chain for the keys. I borrowed some ideas for the joypad from my joypad project page. It could be wired as simple switches wired using a DE-9 cable, but the PCB also has pads for ICs. There's a front panel on the keyboard case which could also be customised. The back has a slot for a connector bracket or a card, as that part of the case is rather empty.

This case design is based on the Sony HiTBiT F1XD

The minimal "OS" could look something like my ZX Spectrum mockup here. ROM (flash) space is pretty cheap now so there could be some built in libraries and utilities. Lowres tile-based 1-bit graphics don't eat much memory.

The Rest

SIPs were cute but went the way of the Dodo.

The Nokia 5110 display, if I were to guess, is some kind of New Old Stock sold to hobbyists. The resolution & screen size would work pretty well for a Tamagotchi or Digimon type game.


Art & Stuff by Arne Niklas Jansson

AndroidArts.com