Skip to content

Commit c25eb19

Browse files
committed
document phoenix-arduino-joystick and HidDescriptorHelper
1 parent 50afc06 commit c25eb19

File tree

5 files changed

+82
-17
lines changed

5 files changed

+82
-17
lines changed

README.md

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ The Gravis Phoenix is a 4-axis programmable Joystick with 24 buttons. Up to 4 bu
77

88
It's no longer practical to use this joystick with modern computers due to the lack of a joystick port. Even USB joystick adapters do not make it possible to use the DOS boot disk configuration utility in order to reprogram the buttons.
99

10-
This project will investigate removing the main logic board of the phoenix and replacing it with an Arduino which will also act as a USB input device. The [UnoJoy](https://github.com/AlanChatham/UnoJoy) project includes both Arduino code and host drivers in order to send axes positions and button states to a computer.
11-
12-
The initial focus will be on understanding the Phoenix's circuitry in order to make the proper connections and readings with the Arduino. To do this, I disassembled the joystick in order to investigate its components.
10+
This project will investigate removing the main logic board of the phoenix and replacing it with an Arduino which will also act as a USB input device. The initial focus will be on understanding the Phoenix's circuitry in order to make the proper connections and readings with the Arduino. To do this, I disassembled the joystick in order to investigate its components.
1311

1412
## Components
1513

@@ -58,16 +56,83 @@ axes: X: adc:548 res:87 out:127 clmp:127
5856
T: adc:702 res:46 out:63 clmp:63
5957
```
6058
* adc: 0-1023 reading from the Analog to Digital Converter
61-
* res: resistance computed using Ohm's law from the ADC reading and the reference resistance. In the image above, note the reference resistors to the left of the Arduino near the analog input pins.
62-
* out: resistance mapped linearly to a specified output range, currently set to 0-127 for each potentiometer
63-
* clmp: the output value clamped to the output range, to ensure it is within spec
64-
65-
Each time one of the buttons' state changes, the test program dumps the button state. Below is sample output when the trigger and one of the wing buttons are pressed.
59+
* res: resistance computed using Ohm's law from the ADC reading and the
60+
reference resistance. In the image above, note the reference resistors to the
61+
left of the Arduino near the analog input pins.
62+
* out: resistance mapped linearly to a specified output range, currently set to
63+
0-127 for each potentiometer
64+
* clmp: the output value clamped to the output range, to ensure it is within
65+
spec
66+
67+
Each time one of the buttons' state changes, the test program dumps the button
68+
state. Below is sample output when the trigger and one of the wing buttons are
69+
pressed.
6670
```
6771
group 01234567
6872
handle .....0..
6973
wing .......0
7074
thrttl ........
7175
```
7276

73-
## Testing UnoJoy
77+
## Arduino Micro with Native HID Support
78+
79+
The [Arduino Micro](https://store.arduino.cc/usa/arduino-micro) is based on the
80+
ATmega32U4 which has integrated USB support. Many other Arduinos rely on an
81+
external chip for USB communication, which requires flashing software onto both
82+
chips and communicating between them in order to implement a USB device such as
83+
a joystick. However, the Arduino Micro is able to use the built-in
84+
[HID](https://www.arduino.cc/en/Reference/HID) library in order to add a
85+
descriptor for your USB HID device and report events. The
86+
[Mouse](https://github.com/arduino-libraries/Mouse/blob/master/src/Mouse.cpp)
87+
library is a convenient example for this functionality.
88+
89+
The most difficult part of creating a USB HID device is creating the descriptor.
90+
This is a blob of binary data sent from the device to the computer describing
91+
the device's capabilities and the format of the data that it reports. I found
92+
many examples of descriptors which were raw hex bytes with haphazard comments
93+
that were hard to follow. I wanted a better way to directly generate the HID
94+
descriptor using C++ enums, so I created
95+
[HidDescriptorHelper.h](src/HidDescriptorHelper.h) based on the
96+
[HID 1.11](http://www.usb.org/developers/hidpage/HID1_11.pdf) and
97+
[HID Usage Tables 1.12](http://www.usb.org/developers/hidpage/Hut1_12v2.pdf)
98+
specifications.
99+
100+
Here is the beginning of a descriptor constructed using HidDescriptorHelper.h:
101+
```C++
102+
#include "HidDescriptorHelper.h"
103+
using namespace usb::hid;
104+
static const u8 sHidDescriptorData[] PROGMEM = {
105+
Global::UsagePage | 1, usage::Page::GenericDesktop,
106+
Local::Usage | 1, usage::generic_desktop::Application::Joystick,
107+
108+
Main::Collection | 1, Collection::Application,
109+
...
110+
Main::EndCollection | 0,
111+
};
112+
```
113+
114+
I strongly prefer this to the alternative which requires continuously
115+
referencing the specifications and allows for the possibility of the data
116+
not matching the comments.
117+
```C++
118+
static const u8 sHidDescriptorData[] PROGMEM = {
119+
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
120+
0x09, 0x04, // USAGE (Joystick)
121+
0xa1, 0x01, // COLLECTION (Application)
122+
0xc0, // END COLLECTION
123+
};
124+
```
125+
126+
Using [HidDescriptorHelper.h](src/HidDescriptorHelper.h), I created the example
127+
[phoenix-arduino-joystick.ino](examples/phoenix-arduino-test/phoenix-arduino-joystick.ino)
128+
which adds a HID descriptor for the phoenix and reports events. Since I replaced
129+
the Nano with the Micro, I also reworked my wiring layout and made corresponding
130+
updates to the pin mappings.
131+
132+
![Arduino Micro Bread Board Prototype](images/arduino_micro_bread_board.png)
133+
134+
After all of these changes, I was finally able to run the new example. I saw the
135+
joystick register with 4 axes and 24 buttons, and verified that all were
136+
functioning correctly.
137+
138+
![Windows Game Controller Test](images/game_controller_test.png)

examples/phoenix-arduino-joystick/phoenix-arduino-joystick.ino

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ static const u8 sHidDescriptorData[] PROGMEM = {
5959
const hc165_config_t hc165_configs[kNumButtonGroups] = {
6060
{
6161
.name = "handle",
62-
.ploadPin = 7,
63-
.clockDataPin = 4,
62+
.ploadPin = 8,
63+
.clockDataPin = 7,
6464
},
6565
{
6666
.name = " wing",
@@ -85,15 +85,15 @@ hc165_collection_t hc165_collection = {
8585
const Potentiometer axesPotentiometers[kNumAxes] = {
8686
{ Potentiometer::Parameters{
8787
.name = "X",
88-
.analogInputPin = A8,
88+
.analogInputPin = A7,
8989
.referenceResistance = 100,
9090
.resistanceRange = {.min = 0, .max = 87},
9191
.outputRange = {.min = kAxesMin, .max = kAxesMax},
9292
}
9393
},
9494
{ Potentiometer::Parameters{
9595
.name = "Y",
96-
.analogInputPin = A9,
96+
.analogInputPin = A6,
9797
.referenceResistance = 100,
9898
.resistanceRange = {.min = 0, .max = 85},
9999
.outputRange = {.min = kAxesMin, .max = kAxesMax},

examples/phoenix-arduino-test/phoenix-arduino-test.ino

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ const size_t numButtonGroups = 3;
1010
const hc165_config_t hc165_configs[numButtonGroups] = {
1111
{
1212
.name = "handle",
13-
.ploadPin = 7,
14-
.clockDataPin = 4,
13+
.ploadPin = 8,
14+
.clockDataPin = 7,
1515
},
1616
{
1717
.name = " wing",
@@ -38,14 +38,14 @@ const size_t numAxes = 4;
3838
const Potentiometer axesPotentiometers[numAxes] = {
3939
{Potentiometer::Parameters{
4040
.name = "X",
41-
.analogInputPin = A8,
41+
.analogInputPin = A7,
4242
.referenceResistance = 100,
4343
.resistanceRange = {.min = 0, .max = 87},
4444
.outputRange = {.min = 0, .max = 127},
4545
}},
4646
{Potentiometer::Parameters{
4747
.name = "Y",
48-
.analogInputPin = A9,
48+
.analogInputPin = A6,
4949
.referenceResistance = 100,
5050
.resistanceRange = {.min = 0, .max = 85},
5151
.outputRange = {.min = 0, .max = 127},

images/arduino_micro_bread_board.png

2.21 MB
Loading

images/game_controller_test.png

10.6 KB
Loading

0 commit comments

Comments
 (0)