Arduboy Joystick Adventures

I'm not sure what compelled me, since I haven't touched my microcontrollers in years, but I recently dug into my stash and realized... dang, I have a lot of stuff. I was last working on Arduboy stuff. And it was fun to tinker with! Looking over my notes from 2020, I sound like someone who knows what they're talking about. Impressive! So here's a nice fresh Arduboy for Dummies (me) post to help refresh my memory.

Getting Started

Games

Let's play some games!

A lot of games are available as .hex files via Ewrin's Arduboy Collection. Builds that don't follow the official wiring with a SDD1309 display can't use the auto-uploaders that are available (source) so you gotta upload the source. I dug around for games and my kid and I got into some fun Game and Watch style ports from Press Play on Tape.

What's Next?

When I left off, I wondered if I could implement a thumb stick I ordered from Adafruit. I hooked it up to a breadboard and used an analog joystick test like this one. These thumbsticks have 2 pentometers that return x/y values.

PIN ID
1 VC
2 Y
3 X
4 Gnd

Side Quest: Pro Micro Bricking, Once Again

At this point in this process, both my Pro Micros bricked and needed to be reset or something. Fortunately my previous notes explain this and provide the solution, which is setting up an Uno as ISP and using that to flash bootloaders to the bricked boards. I went ahead and set up a little plug and play flash station because I figured I'd be flashing these a lot and surprise! that is indeed what happened. It's useful to be able to just plunk a Pro Micro in there whenever it needs to be reflashed.

Implementing Thumbstick with Arduboy

I wasn't sure where to start with this, but this very long post about an ItsyBitsy Arduboy offered a lot of advice and suggestions. The main issue is the thumbstick is analog with 2 inputs, but programatically the D-pad is treated as digital and it has 4 inputs, so it's not a simple hardware drop-in, we have to modify the library as well (chiefly Arduboy2). Fortunately, the button inputs are already on the analog pins, so wiring is simple: wire the X and Y pins to A0 and A1, respectively.

My Arduboy uses MrBlinky's homemade package due to the SH1106 display I mentioned earlier, and if you use homemade package you are not supposed to install the Arduboy libraries individually because there will be a conflict. The homemade packages version of Arduboy2 is located under C:\Users\{username}\AppData\Local\Arduino15\packages\arduboy-homemade\hardware\avr\libraries

When I first updated Arduboy2Core.cpp, a joystick serial test worked but uploading other sketches created a white screen (I learned this is flashlight mode). Reviewing the discussion again, I saw suggestions for modifying Arduboy2Core::bootPowerSaving() and enabling ADC.

It turns out the Arduboy library diables ADC, which is what you need to read the analog values. So I made sure that if ADC is no longer disabled.

These are the changes I made to Arduboy2Core.cpp so far (work in progress):


uint8_t Arduboy2Core::buttonsState()
{ 
  analogRead(0);
  int yvalue = analogRead(0);
  analogRead(1);
  int xvalue = analogRead(1); 

  uint8_t buttons = 0;

  // up, right, left, down
  buttons = ((~PINF) &
              (_BV(UP_BUTTON_BIT) | _BV(RIGHT_BUTTON_BIT) |
               _BV(LEFT_BUTTON_BIT) | _BV(DOWN_BUTTON_BIT) |
              #ifdef SUPPORT_XY_BUTTONS
               _BV(Y_BUTTON_BIT) |
              #endif              
               0));

  // A
  if (bitRead(A_BUTTON_PORTIN, A_BUTTON_BIT) == 0) { buttons |= A_BUTTON; }
  // B
  if (bitRead(B_BUTTON_PORTIN, B_BUTTON_BIT) == 0) { buttons |= B_BUTTON; }

  // up, down, left, right
  if (yvalue > 700) { buttons |= UP_BUTTON; }    // Up
  if (yvalue < 400) { buttons |= DOWN_BUTTON; }  // Down
  if (xvalue > 600) { buttons |= LEFT_BUTTON; } // Left
  if (xvalue < 400) { buttons |= RIGHT_BUTTON; } // Right

  return buttons;
}


void Arduboy2Core::bootPowerSaving()
{
  // disable Two Wire Interface (I2C) and the ADC
  // All other bits will be written with 0 so will be enabled
  PRR0 = _BV(PRTWI);
  // disable USART1
  PRR1 = _BV(PRUSART1);
}


unsigned long Arduboy2Core::generateRandomSeed()
{
  unsigned long seed;

  power_adc_enable(); // ADC on

  // do an ADC read from an unconnected input pin
  ADCSRA |= _BV(ADSC); // start conversion (ADMUX has been pre-set in boot())
  while (bit_is_set(ADCSRA, ADSC)) { } // wait for conversion complete

  seed = ((unsigned long)ADC << 16) + micros();

   //power_adc_disable(); // ADC off 11/22/23

  return seed;
}

Software Issues

One issue I encountered was I got the Arduboy2 Button Test working perfectly, but the joystick still didn't work for some games or the directions were inconsistent. I'm continuing to tweak and study the controls, but I've had particular trouble with the down button. If the joystick is at zero resting, it triggers down, and if I press down, it does nothing.

While I was going around and around about this, I noticed you can get 5-way joystick modules that break out the directions into 4 inputs. You can add this type of control without going through this hassle. They're generally sold as AVR 5D Rockers, and the pinout has 8 connections.