-
-
Notifications
You must be signed in to change notification settings - Fork 47
Description
Greetings,
I have things working on a CYD, but I don't want to use a Wii nunchuck. CYD doesn't have adequate GPIO pins for a proper controller, so I've worked on making my own i2c device using an Seeeduino Xiao. I tested this i2c device using an ESP32 and it seems to work just fine when using the default i2c pins on the esp32. Here is the slave sketch:
#include <Arduino.h>
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
#define XPIN 0 // Arduino pin connected to VRX pin
#define YPIN 1 // Arduino pin connected to VRY pin
#define ZPIN 2 // Arduino pin connected to VRZ pin
#define APIN 3 // Arduino pin connected to button A pin
#define BPIN 6 // Arduino pin connected to button A pin
// Input values
int joystick_calibration_x = -3;
int joystick_calibration_y = 6;
int xValue = 0; // To store value of the X axis
int yValue = 0; // To store value of the Y axis
int xPinValue = 0;
int yPinValue = 0;
bool zButton = 0; // To store value of the Z button
bool aButton = 0; // To store value of the A button
bool bButton = 0; // To store value of the B button
// Banger
int bcount = 0;
// I2C Communication
void requestEvent() {
// Define a byte to hold data
byte bval = 0;
// Cycle through data
// First response is always 255 to mark beginning
switch (bcount) {
case 0:
bval = 255;
break;
case 1:
bval = xValue;
break;
case 2:
bval = yValue;
break;
// Note: Buttons read high normally, so we invert them
case 3:
bval = zButton;
break;
case 4:
bval = aButton;
break;
case 5:
bval = bButton;
break;
}
// Send response back to Master
Wire.write(bval);
Serial.printf("Sent: %d\n", bval);
// Increment byte counter
bcount++;
if (bcount > 5) bcount = 0;
}
void setup() {
Serial.begin(115200) ;
// Joystick X and Y pins are analog
pinMode(XPIN, INPUT);
pinMode(YPIN, INPUT);
pinMode(ZPIN, INPUT_PULLUP);
// Button A and B pins are digital
pinMode(APIN, INPUT_PULLUP);
pinMode(BPIN, INPUT_PULLUP);
// Initialize I2C communications as Slave
Wire.begin(SLAVE_ADDR);
// Function to run when data requested from master
Wire.onRequest(requestEvent);
}
void loop() {
// read analog X and Y analog values
xPinValue = analogRead(XPIN) + joystick_calibration_x;
yPinValue = analogRead(YPIN) + joystick_calibration_y;
// Convert analog values to 8-bit values
float xpct = (xPinValue / 1024.0);
float ypct = (yPinValue / 1024.0);
xValue = (floor(xpct*255)>255)?255:floor(xpct*255);
yValue = (floor(ypct*255)>255)?255:floor(ypct*255);
// read digital Z button value
zButton = digitalRead(ZPIN);
// read digital A button value
aButton = digitalRead(APIN);
// read digital B button value
bButton = digitalRead(BPIN);
// print data to Serial Monitor on Arduino IDE
Serial.printf("x = %d, y = %d, z = %d, a = %d, b = %d \n", xValue, yValue, zButton, aButton, bButton);
delay(10);
}
And here is the master sketch:
#include <Arduino.h>
#include <Wire.h>
#include <vector>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Define counter to count bytes in response
int bcount;
// Define array for return data
byte controller[5];
void setup()
{
Wire.begin();
Serial.begin(9600);
}
byte readI2C(int address) {
// Define a variable to hold byte of data
byte bval ;
long entry = millis();
// Read one byte at a time
Wire.requestFrom(address, 1);
// Wait 100 ms for data to stabilize
while (Wire.available() == 0 && (millis() - entry) < 100) Serial.print("Waiting");
// Place data into byte
if (millis() - entry < 100) bval = Wire.read();
return bval;
}
void loop()
{
while (readI2C(SLAVE_ADDR) < 255) {
// Until first byte has been received print a waiting message
Serial.print("Waiting");
}
for (bcount = 0; bcount < 5; bcount++) {
controller[bcount] = readI2C(SLAVE_ADDR);
}
// Vector of 5 strings
std::vector<String> labels = {"X: ", "Y: ", "Z: ", "A: ", "B: "};
for (int i = 0; i < 5; i++) {
Serial.printf("%s%d ", labels[i].c_str(), controller[i]);
}
Serial.println();
delay(20);
}
As I said, this seems to be working just fine. So I turned my hand toward modifying it to use with Galagino.
I got Galagino compiling and running on my CYD with just a few modifications to config.h per the instructions. The serial is reporting Nunchuck disconnected! of course, but the roms load and go through the motions, I can get them to start with the button as you'd expect.
I thought the best way to try to implement my i2c controller was to just overwrite the existing nunchuck.h include with my own i2c.h include with the same functions implemented for my device. I updated the main sketch to include my file instead of the original, confirmed it's being loaded, and got it compiling and loading just fine. So here is my implementation:
#ifndef _NUNCHUCK_H_
#define _NUNCHUCK_H_
// ----------------------------
// Standard Libraries
// ----------------------------
#include <Arduino.h>
#include <Wire.h>
#include <vector>
// Define Slave I2C Address
#define SLAVE_ADDR 9
#define CTRL_SDA 22
#define CTRL_SCL 27
// Define counter to count bytes in response
int bcount;
// Define array for return data
byte controller[5];
byte readI2C(int address);
//TwoWire Wire = TwoWire(1);
void nunchuckSetup() {
//Serial.begin(115200);
pinMode(CTRL_SDA, INPUT_PULLUP);
pinMode(CTRL_SCL, INPUT_PULLUP);
Serial.println("About to begin I2C.");
Wire.begin(CTRL_SDA, CTRL_SCL,100000);
Serial.println("I2C begun!");
}
unsigned char getNunchuckInput() {
//Wire.end();
//Wire.begin(CTRL_SDA,CTRL_SCL);
byte test = readI2C(SLAVE_ADDR);
while (test < 255) {
Serial.printf("Byte is currently:%d\n",test );
test = readI2C(SLAVE_ADDR);
// Until first byte has been received print a waiting message
Serial.printf("Waiting to end read\n");
}
for (bcount = 0; bcount < 5; bcount++) {
controller[bcount] = readI2C(SLAVE_ADDR);
}
//Wire.end();
// Read a joystick axis (0-255, X and Y)
// Roughly 127 will be the axis centered
int joyX = controller[0];
int joyY = controller[1];
int joyZ = controller[2];
int btnA = controller[3];
int btnB = controller[4];
Serial.printf("%d, %d, %d, %d, %d\n", joyX, joyY, joyZ, btnA, btnB);
return ((joyX < 127 - NUNCHUCK_MOVE_THRESHOLD) ? BUTTON_LEFT : 0) | //Move Left
((joyX > 127 + NUNCHUCK_MOVE_THRESHOLD) ? BUTTON_RIGHT : 0) | //Move Right
((joyY > 127 + NUNCHUCK_MOVE_THRESHOLD) ? BUTTON_UP : 0) | //Move Up
((joyY < 127 - NUNCHUCK_MOVE_THRESHOLD) ? BUTTON_DOWN : 0) | //Move Down
(btnA ? BUTTON_FIRE : 0) |
(btnB ? BUTTON_EXTRA : 0) ;
}
byte readI2C(int address) {
// Define a variable to hold byte of data
byte bval ;
long entry = millis();
// Read one byte at a time
Wire.requestFrom(address, 1);
// Wait 100 ms for data to stabilize
//while (Wire.available() == 0) Serial.printf("Waiting for read\n");
while (Wire.available() == 0 && (millis() - entry) < 100) Serial.printf("Waiting for read\n");
// Place data into byte
if (millis() - entry < 100) bval = Wire.read();
return bval;
}
#endif //_NUNCHUCK_H_
For some reason, when I use this implementation, I can see the values I'm expecting via serial print messages, except for the start byte, which is reading as "1073429516" instead of 255. Here is what I am getting:
Waiting to end read
Byte is currently:1
Waiting to end read
Byte is currently:1073429516
Waiting to end read
Byte is currently:127
Waiting to end read
Byte is currently:127
Waiting to end read
Byte is currently:1
Waiting to end read
Byte is currently:1
Waiting to end read
This is really strange to me, but I am new to i2c, Arduino IDE (platformio guy), and Galagino. I have tried the following things:
- Using TwoWire instead of wire, 0, 1, and 9 as indices for the constructor (9 just for funsies, it compiled and worked the same as 0, and 1 which behaved the same as just plain "Wire".
- Swapping both the code and the wiring of the SDA and SCL (and NO I didn't pull a two doctors BOTH reversing the polarity when making that test). I got hung up at a different area when I did this and confirmed I am wired correctly for the CYD with my current setup.
- Initializing the pins with pullup resistors (this seems prudent as I don't know if the Wire library will initialize the pins appropriately, but may not be necessary, I've tried it both ways and left it in for now). I realize this may be part of the issue since I have extended the wires by necessity at this point due to breadboarding needs. I will try adding pullups inline if nothing else works by tomorrow (not in my workshop rn so no resistors on hand).
- Adding a bunch of serial debugging messages - this helped narrow down where I am going wrong.
- Reinitializing the wire each time - this adds way too much latency and also doesn't work.
Things I haven't tried:
- Just setting it to say if the byte is equal to "1073429516" assume it is the start byte. I don't want to do this because I don't understand why I'm getting that number and it seems like cheating. I may try this later just for funsies, but it's NOT a solution.
- Adding in the pullup resistors. I will likely try this tomorrow.
Any suggestions are welcome. Thanks for the great software! So cool!!