Wii nunchuk/Classic controller

Status
Not open for further replies.

niocnioc

Member
I'm not too much into electronics, more a software guy, so sorry if i say some mistakes

I'd like to make a classic controller to usb adapter, to be able to use my wii arcade stick on raspberry/pc/ps3

I've purchased a wiichuck adapter.

can i use a teensy LC for this purpose?

Is there any pitfall regarding powering, hid setup or other that i should be aware of?

thank you for reading !
 
the Wii-controllers use I2C if i remember that correctly. Teensies can register to the OS a Joystick+Mouse+Keyboard combo device and you can send mouse clicks, keystrokes and joystick axis positions to the PC/Mac.
Teensy LC will be a good choice for this project. Your software needs to translate the I2C messages from the Wii-Device into HID messages to the OS.
 
Thank you for your answer!
Do you know if I have to take care of voltage? I think USB delivers 5v, but teensy supports only 3.3v no?

Well of course I will learn this in the manual :)
 
Do you know if I have to take care of voltage? I think USB delivers 5v, but teensy supports only 3.3v no?
Not shure what you're asking here. Teensy LC runs on 3.3V logic voltage and is NOT 5V tolerant on its I/O pins. But it has an internal regulator so it can be supplied with 5V through it's USB port. This internal regulator is actually powerful enough to power some external devices as well, you may pull up to 100mA total for external use from Teensy LC's 3.3V pins.
I don't know whether the Wii device uses 5V or 3.3V on it's Bus. If it needs 5V you must use a bidirectional level shifter. If the I2C bus is slow enough, you can use the "sparkfun approach" here: https://www.sparkfun.com/products/12009
Note, however, that this level shifter is of "you get what you pay for"-quality. You can't use it for fast changing signals like high speed SPI. But for 100kHz I2C i guess it's ok.
Ben
 
Like i said i'm more a software guy, i got confused with those notices on the teensy LC product page :)

Thanks for all the valuable info. I think it will be fun
 
Finally i was able to get a teensy 2.0 and to move on to this side project. I have now my nunchuk acting as a joystick in windows, and it's pretty cool.

I'm still concerned about the voltage output, nunchuks and wii classic devics operate on 3.3v, and using 5V could damage the stuff ( not 100% sure there)
If I understand correctly i could use a voltage regulator on the Vcc output. Should i use capacitors?
 
Last edited:
That's good news :cool:
I'm impressed you followed through with this project and even reported back after such a long time. Much appreciated :)

Ben

Edit:
Regarding the Teensy 2.0 and voltage levels, I'm sorry I don't know :(
 
A quick run through google suggest nunchuks are indeed intended to run of 3.3V. The ugle hack solution is to just wire it up and see if it smokes, trusting the engineering in the nunchuck to cope, and replace it if things catch fire. The right solution is voltage conversion. First up that involves a regulator, which yes would normally need a cap on the output. You may also need to level convert the signals in and out, depending on how fussy the micro is about levels in, and if it truly reaches 3.3V on it's output levels.

The possibly simpler solution is:
https://www.pjrc.com/teensy/3volt.html and convert the whole Teensy 2 into a 3.3v Micro.

Or just buying a 3.3V native micro. Depends a great deal on what you want to do, and how much time, money and existing parts you have to work with.
 
I was finally able to complete this project

for the electronic part I've put a 3v3 AMS1117 regulator on the nunchuk adapter with a capacitor on the Vout

for the software I've used the code from havencking https://github.com/havencking/teensy-usb-wii-classic-controller, with some tweaks to get Y axis in the right direction, and axis value in the correct range.

I've not yet managed to get the wii home button mapped to the ps3 home, but that's a minor issue

Code:
/*   Copyright December 2015 - havencking@gmail.com
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * This is for a Wii Classic Controller adapted to connect as a joystick over
 * USB using a Teensy LC.  See http://havencking.blogspot.com for more info.
 *
 * When compiling using the Arduino IDE, you must select Joystick from the
 * "Tools > USB Type" menu.
 *
 * For more info about the Wii Classic Controller, see:
 * http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Classic_Controller
 */

// the improved Wire I2C library
// see:  https://www.pjrc.com/teensy/td_libs_Wire.html
#include "i2c_t3.h"
#include <Wire.h>             // fake include - points back to i2c_t3
// an array to store the six bytes of controller status
int buttons[6];

// the analog controls
int LX;
int LY;
int LT;
int RX;
int RY;
int RT;

// the digital controls
bool BDR;
bool BDD;
bool BLT;
bool Bminus;
bool BH;
bool Bplus;
bool BRT;
bool BZL;
bool BB;
bool BY;
bool BA;
bool BX;
bool BZR;
bool BDL;
bool BDU;

void setup() {
  // initialize Wii I2C using "the new way"
  // see: http://wiibrew.org/wiki/Wiimote/Extension_Controllers
  Wire.begin();
  Wire.beginTransmission(0x52); // Wii Classic 7-bit I2C address is 0x52
  Wire.write(0xF0);
  Wire.write(0x55);
  Wire.endTransmission();
  Wire.beginTransmission(0x52);
  Wire.write(0xFB);
  Wire.write(0x00);
  Wire.endTransmission();

  // initialize Joystick
  // see: https://www.pjrc.com/teensy/td_joystick.html
  Joystick.useManualSend(true);
}

void loop() {
  // request the 6 bytes of controller status and store in the buttons array
  Wire.requestFrom(0x52, 6);
  while (Wire.available()) {
    for (int i = 0; i < 6; i++) {
      buttons[i] = Wire.receive();
    }

    // parse the controller data
    // analog controls
    LX = buttons[0] & B00111111;
    LY = buttons[1] & B00111111;
    LT = ((buttons[2] >> 2) & B00011000) | ((buttons[3] >> 5) & B00000111);
    RX = ((buttons[0] >> 3) & B00011000) | ((buttons[1] >> 5) & B00000110) | ((buttons[2] >> 7) & B00000001);
    RY = buttons[2] & B00011111;
    RT = buttons[3] & B00011111;

    // digital controls
    BDR = (buttons[4] >> 7) & B00000001;
    BDD = (buttons[4] >> 6) & B00000001;
    BLT = (buttons[4] >> 5) & B00000001;
    Bminus = (buttons[4] >> 4) & B00000001;
    BH = (buttons[4] >> 3) & B00000001;
    Bplus = (buttons[4] >> 2) & B00000001;
    BRT = (buttons[4] >> 1) & B00000001;
    BZL = (buttons[5] >> 7) & B00000001;
    BB = (buttons[5] >> 6) & B00000001;
    BY = (buttons[5] >> 5) & B00000001;
    BA = (buttons[5] >> 4) & B00000001;
    BX = (buttons[5] >> 3) & B00000001;
    BZR = (buttons[5] >> 2) & B00000001;
    BDL = (buttons[5] >> 1) & B00000001;
    BDU = buttons[5] & B00000001;

    // set the status of the controls mapped as a USB Joystick
    // see: https://www.pjrc.com/teensy/td_joystick.html
    // analog controls
    // on my fighting stick values are read as 0, 32,63, and i'm unable to calibrate on the ps3
    // so i shift to get 0,512, 1023
    Joystick.X(LX<<4);// / 64 * 1024);        // "value" is from 0 to 1023
    // y is inversed
    Joystick.Y((64-LY)<<4);// / 64 * 1024);        //   512 is resting position
    Joystick.Z(RX);// / 32 * 1024);
    Joystick.Zrotate(RY);// / 32 * 1024);
    Joystick.sliderLeft(LT);// / 32 * 1024);
    Joystick.sliderRight(RT);// / 32 * 1024);
    // digital controls
    // renumber these buttons as you see fit
    Joystick.button(15, !BDR);
    Joystick.button(13, !BDD);
    Joystick.button(8, !BLT);
    Joystick.button(9, !Bminus);
    Joystick.button(11, !BH);
    Joystick.button(10, !Bplus);
    Joystick.button(6, !BRT);
    Joystick.button(7, !BZL);
    Joystick.button(2, !BB);
    Joystick.button(1, !BY);
    Joystick.button(3, !BA);
    Joystick.button(4, !BX);
    Joystick.button(5, !BZR);
    Joystick.button(14, !BDL);
    Joystick.button(12, !BDU);

    // send the controls over USB as a Joystick
    Joystick.send_now();
  }
  // restart at the beginning of the address space
  Wire.beginTransmission(0x52);
  Wire.write(0x00);
  Wire.endTransmission();
 
Hello,

I am trying to connnect a nunchuk to a Teensy 3.2 and I can't make it work.

I am using the code available here (https://github.com/GabrielBianconi/arduino-nunchuk) and I got it working properly with a Teensy 2++ without issues. On the 3.2 I have added 10K pullup resistors to the SDA and SCL pins (18 and 19). The code is simple:

Code:
#include <Wire.h>
#include <ArduinoNunchuk.h>

#define BAUDRATE 19200

ArduinoNunchuk nunchuk = ArduinoNunchuk();

void setup()
{
  Serial.begin(BAUDRATE);
  nunchuk.init();
}

void loop()
{
  nunchuk.update();

  Serial.print(nunchuk.analogX, DEC);
  Serial.print(' ');
  Serial.print(nunchuk.analogY, DEC);
  Serial.print(' ');
  Serial.print(nunchuk.accelX, DEC);
  Serial.print(' ');
  Serial.print(nunchuk.accelY, DEC);
  Serial.print(' ');
  Serial.print(nunchuk.accelZ, DEC);
  Serial.print(' ');
  Serial.print(nunchuk.zButton, DEC);
  Serial.print(' ');
  Serial.println(nunchuk.cButton, DEC);
  delay(100); //The only modification I have made to the code
}

The ArduinoNunchuk.h file is:
Code:
/*
 * ArduinoNunchuk.h - Improved Wii Nunchuk library for Arduino
 *
 * Copyright 2011-2013 Gabriel Bianconi, http://www.gabrielbianconi.com/
 *
 * Project URL: http://www.gabrielbianconi.com/projects/arduinonunchuk/
 *
 * Based on the following resources:
 *   http://www.windmeadow.com/node/42
 *   http://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/
 *   http://wiibrew.org/wiki/Wiimote/Extension_Controllers
 *
 */

#ifndef ArduinoNunchuk_H
#define ArduinoNunchuk_H

#include <Arduino.h>

class ArduinoNunchuk
{
  public:
    int analogX;
    int analogY;
    int accelX;
    int accelY;
    int accelZ;
    int zButton;
    int cButton;

    void init();
    void update();

  private:
    void _sendByte(byte data, byte location);
};

#endif

ANd the ArduionNunchuk.cpp file:

Code:
/*
 * ArduinoNunchuk.cpp - Improved Wii Nunchuk library for Arduino
 *
 * Copyright 2011-2013 Gabriel Bianconi, http://www.gabrielbianconi.com/
 *
 * Project URL: http://www.gabrielbianconi.com/projects/arduinonunchuk/
 *
 * Based on the following resources:
 *   http://www.windmeadow.com/node/42
 *   http://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/
 *   http://wiibrew.org/wiki/Wiimote/Extension_Controllers
 *
 */

#include <Arduino.h>
#include <Wire.h>
#include "ArduinoNunchuk.h"

#define ADDRESS 0x52

void ArduinoNunchuk::init()
{
  Wire.begin();

  ArduinoNunchuk::_sendByte(0x55, 0xF0);
  ArduinoNunchuk::_sendByte(0x00, 0xFB);

  ArduinoNunchuk::update();
}

void ArduinoNunchuk::update()
{
  int count = 0;
  int values[6];

  Wire.requestFrom(ADDRESS, 6);

  while(Wire.available())
  {
    values[count] = Wire.read();
    count++;
  }

  ArduinoNunchuk::analogX = values[0];
  ArduinoNunchuk::analogY = values[1];
  ArduinoNunchuk::accelX = (values[2] << 2) | ((values[5] >> 2) & 3);
  ArduinoNunchuk::accelY = (values[3] << 2) | ((values[5] >> 4) & 3);
  ArduinoNunchuk::accelZ = (values[4] << 2) | ((values[5] >> 6) & 3);
  ArduinoNunchuk::zButton = !((values[5] >> 0) & 1);
  ArduinoNunchuk::cButton = !((values[5] >> 1) & 1);

  ArduinoNunchuk::_sendByte(0x00, 0x00);
}

void ArduinoNunchuk::_sendByte(byte data, byte location)
{
  Wire.beginTransmission(ADDRESS);

  Wire.write(location);
  Wire.write(data);

  Wire.endTransmission();

  delay(10);
}

I get data sent to the serial port, but the numbers don't change, except that periodically (every 2 seconds or so), the values change a few times (5 or 6 datasets sent to the serial port are different), then they go back to their previous values. I am feeding the nunchuk with the 3.3v pin of the Teensy. I have also tried the Vcc in, which is 5V, from the computer usb port (just in case, since it worked for the Teensy 2++, which runs on 5V), but that doesn't make a difference. As I said before, I am using 10K pullup resistors.

Any idea of what I could try?

Admittedly I have not tried niocnioc's code, but I will try it this evening when I am at home.

I know this is an old thread but I thought it would be better to bring this one back to life and have all the related information in a single thread than starting a new one. Also, sorry for the long post with a lot of code, I thought it would save us some time if I was thorough with the explanation from the beginning.

Thank you all in advance,

Pixe
 
Hi Pixe,
try the I2C Scanner from the wire library first!
If does not work, too, i'd use stronger pullups, like 3k3.
 
Thank you Frank. I used the code posted above, and after a few modifications I got it working.

I used 3k3 pullup resistors as you suggested, but it seems to work without them as well. Is it ok to remove them?

The thing is the code posted above is for the classic wii controller, I wanted to use it for the nunchuk and the mapping of the data is different.

So, I use the code above (which in turn is based on the code that can be found here), with the mapping I found in a project by Gabriel Bianconi (the code is here).

And in case somenone needs my final code in the future, I am posting it below. It reads the data from a wii nunchuk and sends it to the serial port. This page explains the data format of the nunchuk.

My code:
Code:
// the improved Wire I2C library
// see:  https://www.pjrc.com/teensy/td_libs_Wire.html
#include "i2c_t3.h"

// an array to store the six bytes of controller status
int values[6];

// the analog controls
int analogX;
int analogY;
int acceanalogX;
int acceanalogY;
int acceanalogZ;
int zButton;
int cButton;


void setup() {
  // initialize Wii I2C using "the new way"
  // see: http://wiibrew.org/wiki/Wiimote/Extension_Controllers
  Wire.begin();
  Wire.beginTransmission(0x52); // Wii Classic 7-bit I2C address is 0x52
  Wire.write(0xF0);
  Wire.write(0x55);
  Wire.endTransmission();
  Wire.beginTransmission(0x52);
  Wire.write(0xFB);
  Wire.write(0x00);
  Wire.endTransmission();

  // initialize Serial
  Serial.begin(19200);
}


void loop() {
  // request the 6 bytes of controller status and store in the buttons array
  Wire.requestFrom(0x52, 6);
  while (Wire.available()) {
    for (int i = 0; i < 6; i++) {
      values[i] = Wire.receive();
    }


    // parse the controller data
    // analog controls
    analogX = values[0] & B11111111; 
    analogY = values[1] & B11111111; 
    acceanalogX = (values[2] << 2) | ((values[5] >> 2) & B00000011); 
    acceanalogY = (values[3] << 2) | ((values[5] >> 4) & B00000011); 
    acceanalogZ = (values[4] << 2) | ((values[5] >> 6) & B00000011);
    zButton = !((values[5] >> 0) & 1);
    cButton = !((values[5] >> 1) & 1);


  Serial.print("analogX ");
  Serial.print(analogX, DEC);
  Serial.print("; analogY ");
  Serial.print(analogY, DEC);
  Serial.print("; acceanalogX ");
  Serial.print(acceanalogX, DEC);
  Serial.print("; acceanalogY ");
  Serial.print(acceanalogY, DEC);
  Serial.print("; acceanalogZ ");
  Serial.print(acceanalogZ, DEC);
  Serial.print("; zButton ");
  Serial.print(zButton, DEC);
  Serial.print("cButton ");
  Serial.print(cButton, DEC);
  Serial.println(' ');
  }
     
  // restart at the beginning of the address space
  Wire.beginTransmission(0x52);
  Wire.write(0x00);
  Wire.endTransmission();

  delay(200); // don't read too fast
}

Thanks again,

Pixe
 
Glad to know you got it to work
I'm still using my code with the classic controller, it's working nice even if I've never been able to make the home button work on the ps3- there's a trick at the hid level

Thank you for sharing your code, I will have a look, I plan to use a nunchuk to make a gatt hid Bluetooth controller for the hololens with an esp32 😁
 
Status
Not open for further replies.
Back
Top