The recent release of the Wii Motionplus sensor gives us a < $20 3-axis (yes, it IS 3 axis!) gyro that speaks I2C. I got the thing to answer up. It's I2C address os 0x53. But I have yet to figure out how to extract the data. Several sites have some data, but there is still much missing. Any help would be much appreciated.
FWIW - I am using Cypress PSoCs
EDIT 1 -
I apologize for the duplicate thread. I intended to bump the other, but got distracted. The links mentioned in the links mentioned in the other thread point to gret stuff for the nunchuck accellerometer data, but say nothing about MotionPlus. Wiire.org appears to be a cobweb. It hasn't been updated in a while.
Now a little detail:
I have a motionplus which I have hacked slightly. Since I needed a connector for the proprietary Wii connector, I took the one that was already attached and used it. It has a "pass through" for the I2C bus. The connector that goes to the Wiimote is soldered to the middle of the board. That's a great one to leave for the input. The "pass through" is soldered to the edge of the board with FlexTrace. I removed it and replaced the flextrace with a rainbow-colored ribbon cable using the same color scheme as Nintendo.
Pin 1 (brown) is +3.3v
Pin 2 (red) is I2C clock
Pin 3 (orange) not used
Pin 4 (yellow) not used
Pin 5 (green) I2C Data
Pin 6 (blue) Ground
I connected the device to a Cypress USB-I2C Bridge. Using the usbiic.exe application I issued the command to LIST which immediately produced the following output:
Devices list: 8bit 7bit
address : 00 00
address : 02 01
address : 04 02
address : 06 03
address : 08 04
address : 0A 05
address : 0C 06
address : 0E 07
address : A6 53 <== Here's our boy!
address : F0 78
address : F2 79
address : F4 7A
address : F6 7B
address : F8 7C
address : FA 7D
address : FC 7E
address : FE 7F
Using the "Wii Nunchuck" hacks as a guide, we send:
0x00 to address 0x40
and then write a 0x00 to the device.
Both actions produce an ACK
However, data is not available at the usual place (offset . So. . . I have missed something entirely. I will attempt to rewire this a little so that I can talk to a Wiimote over Bluetooth while simultaneously sniffing the I2C bus. Will report findings.
Wii MotionPlus protocol. . . Let us hack . . .
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- sorceress sarah
- Posts: 100
- Joined: Sat Jun 20, 2009 2:07 pm
-
- Posts: 12151
- Joined: Thu Apr 06, 2006 4:21 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
very exciting, i just heard of this device...will check it out soon. keep hacking!
- sorceress sarah
- Posts: 100
- Joined: Sat Jun 20, 2009 2:07 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
Update 1:
Sorceress Sarah did dumb and stupid thing. Remember the connector that I removed (the pass-through?) OK, I put a pin header on it, 'cuz I got some 6-conductor cables that had just the right spacing to use a pin header there. But I gotta make the other end of one fit the USB-IIC bridge. So I make the wire. Ohms out fine. I hook it up and "TIMEOUT".
That's when I remember the ferrite bead on the end I left intact. OK, remove the ferrite. Many fewer timeouts, but. . . Dmn, something's gettin' hot! I know 'cuz I burnt my finger! Not good. . .
Check the bug with the original adapter. . . Still OK. But apparently this thing does not appreciate being probed from the back side. . . (I wonder why?)
Additionally, it appears that the Wiimote does not play well with others. It's the I2C master, and apparently is not set up for multi-master. So much for that idea. . . The I2C bridge that I have isn't set up for multi-master either. . . Bummer. . .
EDIT 1
I usually do my best thinking in bed. Too bad I have insomnia. . . :/ As usual,I have an idea. When I get home from work, I'll make a PSoC that has a UART that is optically isolated from the data and clock lines that just re-clocks and retransmits the data out the USB. . .
Sorceress Sarah did dumb and stupid thing. Remember the connector that I removed (the pass-through?) OK, I put a pin header on it, 'cuz I got some 6-conductor cables that had just the right spacing to use a pin header there. But I gotta make the other end of one fit the USB-IIC bridge. So I make the wire. Ohms out fine. I hook it up and "TIMEOUT".
That's when I remember the ferrite bead on the end I left intact. OK, remove the ferrite. Many fewer timeouts, but. . . Dmn, something's gettin' hot! I know 'cuz I burnt my finger! Not good. . .
Check the bug with the original adapter. . . Still OK. But apparently this thing does not appreciate being probed from the back side. . . (I wonder why?)
Additionally, it appears that the Wiimote does not play well with others. It's the I2C master, and apparently is not set up for multi-master. So much for that idea. . . The I2C bridge that I have isn't set up for multi-master either. . . Bummer. . .
EDIT 1
I usually do my best thinking in bed. Too bad I have insomnia. . . :/ As usual,I have an idea. When I get home from work, I'll make a PSoC that has a UART that is optically isolated from the data and clock lines that just re-clocks and retransmits the data out the USB. . .
-
- Posts: 12151
- Joined: Thu Apr 06, 2006 4:21 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
if its a passthru then how can it be a master on both ends? perhaps i have to see this thing in person...
- sorceress sarah
- Posts: 100
- Joined: Sat Jun 20, 2009 2:07 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
Wiimote = Master 1
Cypress USB-I2C bridge = Master 2
I am guessing that the dueling clocks were making the bug in the middle unhappy.
So I am going to try to create a device that is just a receive-only I2C sniffer from a PSoC.
And, co-incidentally, I just found a box on my doorstep from DigiKey! Yay!!
Cypress USB-I2C bridge = Master 2
I am guessing that the dueling clocks were making the bug in the middle unhappy.
So I am going to try to create a device that is just a receive-only I2C sniffer from a PSoC.
And, co-incidentally, I just found a box on my doorstep from DigiKey! Yay!!
- chelmi
- Posts: 53
- Joined: Wed Nov 19, 2008 12:09 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
FYI, somebody on the arduino forum has code to interface with the Wii MotionPlus
http://www.arduino.cc/cgi-bin/yabb2/YaB ... 1245723011
http://www.arduino.cc/cgi-bin/yabb2/YaB ... 1245723011
- sorceress sarah
- Posts: 100
- Joined: Sat Jun 20, 2009 2:07 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
Cool stuff. I'll see if I can (w)hack it to work on a PSoC.
Be very careful, though. The guy's pinout is wrong. He's got the wires right, but the numbers of the pins are wrong.
His:
123
456
Correct
From the plug side:
531
642
Where:
1 = Power
2 = Clock
5 = Data
6 = Ground
Be very careful, though. The guy's pinout is wrong. He's got the wires right, but the numbers of the pins are wrong.
His:
123
456
Correct
From the plug side:
531
642
Where:
1 = Power
2 = Clock
5 = Data
6 = Ground
- sorceress sarah
- Posts: 100
- Joined: Sat Jun 20, 2009 2:07 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
OK, so I hacked up the Arduino code. Here's the PSoC version. It has a bug. the same string is displayed for all the values and it contains non-digit characters. Maybe someone here can see what I can't 'cuz it's dangerous to code while sleeping.
Code: Select all
//----------------------------------------------------------------------------
// C main line
//----------------------------------------------------------------------------
#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules
#include "stdlib.h"
#define WiiMP_BeginI2C_ADDR 0x53
#define WiiMP_ADDR 0x52
#define BANNED 0xfe
#define ActivationData 0x04
const BYTE txActBuf[] = {0xfe, 0x04};
const BYTE txZeroBuf[] = {0x00};
BYTE rxBuf[6];
BYTE * txBuf; // RAM tx buffer
int yaw, pitch, roll; //three axes
int yaw0, pitch0, roll0; //calibration zeroes
char * yBuf;
char * pBuf;
char * rBuf;
void DisplayResults(void){
itoa(yBuf,yaw,10);
itoa(pBuf,pitch,10);
itoa(rBuf,roll,10);
LCD_Position(1,0);
LCD_PrString(yBuf);
LCD_Position(1,9);
LCD_PrString(pBuf);
LCD_Position(0,0);
LCD_PrString(rBuf);
}
void main()
{
BYTE status;
int i;
M8C_EnableGInt; // Enble the Global Interrupt
LCD_Start(); //Start the LCD module
I2Cm_Start(); // Start the I2C in Master mode
// Initialize Wii MotionPlus
status = I2Cm_bWriteCBytes(WiiMP_BeginI2C_ADDR,txActBuf,2,I2Cm_CompleteXfer);
/* From this point on is a straight rip of the Arduino code. */
// Calibrate Zeros
for (i = 0; i < 10; i++) {
status = I2Cm_bWriteCBytes(WiiMP_ADDR,txZeroBuf,1,I2Cm_CompleteXfer); // Write a zero to request data
status = I2Cm_fReadBytes(WiiMP_ADDR, rxBuf, 6, I2Cm_CompleteXfer); // Read the data into the receive buffer
yaw0+=(((rxBuf[3]>>2)<<8)+rxBuf[0])/10; //average 10 readings for each zero
pitch0+=(((rxBuf[4]>>2)<<8)+rxBuf[1])/10;
roll0+=(((rxBuf[5]>>2)<<8)+rxBuf[2])/10;
}
// I2Cm_SendStop();
for (;;){ //Loop forever
status = I2Cm_bWriteCBytes(WiiMP_ADDR,txZeroBuf,1,I2Cm_CompleteXfer); // Write a zero to request data
status = I2Cm_fReadBytes(WiiMP_ADDR, rxBuf, 6, I2Cm_CompleteXfer); // Read the data into the receive buffer
yaw=((rxBuf[3]>>2)<<8)+rxBuf[0]-yaw0; //see http://wiibrew.org/wiki/Wiimote/Extension_Controllers#Wii_Motion_Plus
pitch=((rxBuf[4]>>2)<<8)+rxBuf[1]-pitch0; //for info on what each byte represents
roll=((rxBuf[5]>>2)<<8)+rxBuf[2]-roll0;
DisplayResults();
}
}
- fat16lib
- Posts: 595
- Joined: Wed Dec 24, 2008 1:54 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
Looks like it might be the itoa() calls. I see two things. yBuf, pBuf, and rBuf are pointers that are not initialized to point to separate buffers. Second, it looks like the first two parameters in the itoa() calls may be swapped.
The itoa I knew was:
The itoa I knew was:
Code: Select all
char *itoa(int value, char *string, int radix);
value - the integer to be converted to a string representation.
string - points to the buffer that is to hold resulting string.
radix - the base of the number.
- sorceress sarah
- Posts: 100
- Joined: Sat Jun 20, 2009 2:07 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
The parameters are correct. Here's the function prototype from stdlib.h:
I'll have a look at the output assembler to verify that the three buffers are indeed separate buffers when I get home from work. Thanks for the help.
EDIT 1 -
Oh, and here's the prototype for the call to LCD_PrString();
And the Assembler output:
Code: Select all
char *itoa(char *buf, int i, int base);
EDIT 1 -
Oh, and here's the prototype for the call to LCD_PrString();
Code: Select all
extern void LCD_PrString(char * sRamString);
Code: Select all
(0027) void DisplayResults(void){
(0028) itoa(yBuf,yaw,10);
_DisplayResults:
__text_start:
083D: 50 00 MOV A,0
083F: 08 PUSH A
0840: 50 0A MOV A,10
0842: 08 PUSH A
0843: 62 D0 00 MOV REG[208],0
0846: 51 25 MOV A,[yaw]
0848: 08 PUSH A
0849: 51 26 MOV A,[yaw+1]
084B: 08 PUSH A
084C: 62 D0 00 MOV REG[208],0
084F: 51 19 MOV A,[yBuf]
0851: 08 PUSH A
0852: 51 1A MOV A,[yBuf+1]
0854: 08 PUSH A
0855: 7C 0B 65 LCALL _itoa
0858: 38 FA ADD SP,250
(0029) itoa(pBuf,pitch,10);
085A: 50 00 MOV A,0
085C: 08 PUSH A
085D: 50 0A MOV A,10
085F: 08 PUSH A
0860: 62 D0 00 MOV REG[208],0
0863: 51 29 MOV A,[pitch]
0865: 08 PUSH A
0866: 51 2A MOV A,[pitch+1]
0868: 08 PUSH A
0869: 62 D0 00 MOV REG[208],0
086C: 51 1D MOV A,[pBuf]
086E: 08 PUSH A
086F: 51 1E MOV A,[pBuf+1]
0871: 08 PUSH A
0872: 7C 0B 65 LCALL _itoa
(0030) itoa(rBuf,roll,10);
0875: 50 00 MOV A,0
0877: 08 PUSH A
0878: 50 0A MOV A,10
087A: 08 PUSH A
087B: 62 D0 00 MOV REG[208],0
087E: 51 21 MOV A,[roll]
0880: 08 PUSH A
0881: 51 22 MOV A,[roll+1]
0883: 08 PUSH A
0884: 62 D0 00 MOV REG[208],0
0887: 51 17 MOV A,[rBuf]
0889: 08 PUSH A
088A: 51 18 MOV A,[rBuf+1]
088C: 08 PUSH A
088D: 7C 0B 65 LCALL _itoa
0890: 38 F4 ADD SP,244
(0031) LCD_Position(1,0);
0892: 10 PUSH X
0893: 57 00 MOV X,0
0895: 50 01 MOV A,1
0897: 7C 04 F4 LCALL 0x04F4
(0032) LCD_PrString(yBuf);
089A: 62 D0 00 MOV REG[208],0
089D: 51 19 MOV A,[yBuf]
089F: 08 PUSH A
08A0: 51 1A MOV A,[yBuf+1]
08A2: 5C MOV X,A
08A3: 18 POP A
08A4: 7C 03 B2 LCALL 0x03B2
(0033) LCD_Position(1,9);
08A7: 57 09 MOV X,9
08A9: 50 01 MOV A,1
08AB: 7C 04 F4 LCALL 0x04F4
(0034) LCD_PrString(pBuf);
08AE: 62 D0 00 MOV REG[208],0
08B1: 51 1D MOV A,[pBuf]
08B3: 08 PUSH A
08B4: 51 1E MOV A,[pBuf+1]
08B6: 5C MOV X,A
08B7: 18 POP A
08B8: 7C 03 B2 LCALL 0x03B2
(0035) LCD_Position(0,0);
08BB: 50 00 MOV A,0
08BD: 5C MOV X,A
08BE: 7C 04 F4 LCALL 0x04F4
(0036) LCD_PrString(rBuf);
08C1: 62 D0 00 MOV REG[208],0
08C4: 51 17 MOV A,[rBuf]
08C6: 08 PUSH A
08C7: 51 18 MOV A,[rBuf+1]
08C9: 5C MOV X,A
08CA: 18 POP A
08CB: 7C 03 B2 LCALL 0x03B2
08CE: 20 POP X
08CF: 7F RET
Last edited by sorceress sarah on Tue Jun 23, 2009 9:21 am, edited 1 time in total.
- fat16lib
- Posts: 595
- Joined: Wed Dec 24, 2008 1:54 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
Wow itoa() is non-standard! Here it is from the Arduino/Avr stdlib.h:
Edit - I looked at the Cypress compiler and it is has the parameters reversed from other itoa implementations.
The example I found was:
So maybe it is just the buffer to hold the string.
Code: Select all
extern char *itoa(int __val, char *__s, int __radix);
The example I found was:
Code: Select all
void main(void)
{
int myInt = 10;
char OutputString[7]; // String to hold the ascii result
itoa(OutputString, ADCResult, myInt);
LCD_Position(0,0);
LCD_PrString(OutputString);
}
- sorceress sarah
- Posts: 100
- Joined: Sat Jun 20, 2009 2:07 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
Changing the buffer declaration fixed it. This works:
Thanks for the pointer to the pointer (pun intended )
So for PSoC, the code is:
Code: Select all
char yBuf[];
char pBuf[];
char rBuf[];
So for PSoC, the code is:
Code: Select all
//----------------------------------------------------------------------------
// C main line
//----------------------------------------------------------------------------
#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules
#include "stdlib.h"
#define WiiMP_BeginI2C_ADDR 0x53
#define WiiMP_ADDR 0x52
#define BANNED 0xfe
#define ActivationData 0x04
const BYTE txActBuf[] = {0xfe, 0x04};
const BYTE txZeroBuf[] = {0x00};
BYTE rxBuf[6];
BYTE * txBuf; // RAM tx buffer
int yaw, pitch, roll; //three axes
int yaw0, pitch0, roll0; //calibration zeroes
char yBuf[];
char pBuf[];
char rBuf[];
void DisplayResults(void){
itoa(yBuf,yaw,10);
itoa(pBuf,pitch,10);
itoa(rBuf,roll,10);
LCD_Position(1,0);
LCD_PrString(yBuf);
LCD_Position(1,9);
LCD_PrString(pBuf);
LCD_Position(0,0);
LCD_PrString(rBuf);
}
void main()
{
BYTE status;
int i;
M8C_EnableGInt; // Enble the Global Interrupt
LCD_Start(); //Start the LCD module
I2Cm_Start(); // Start the I2C in Master mode
// Initialize Wii MotionPlus
status = I2Cm_bWriteCBytes(WiiMP_BeginI2C_ADDR,txActBuf,2,I2Cm_CompleteXfer);
/* From this point on is a straight rip of the Arduino code. */
// Calibrate Zeros
for (i = 0; i < 10; i++) {
status = I2Cm_bWriteCBytes(WiiMP_ADDR,txZeroBuf,1,I2Cm_CompleteXfer); // Write a zero to request data
status = I2Cm_fReadBytes(WiiMP_ADDR, rxBuf, 6, I2Cm_CompleteXfer); // Read the data into the receive buffer
yaw0+=(((rxBuf[3]>>2)<<8)+rxBuf[0])/10; //average 10 readings for each zero
pitch0+=(((rxBuf[4]>>2)<<8)+rxBuf[1])/10;
roll0+=(((rxBuf[5]>>2)<<8)+rxBuf[2])/10;
}
for (;;){ //Loop forever
status = I2Cm_bWriteCBytes(WiiMP_ADDR,txZeroBuf,1,I2Cm_CompleteXfer); // Write a zero to request data
status = I2Cm_fReadBytes(WiiMP_ADDR, rxBuf, 6, I2Cm_CompleteXfer); // Read the data into the receive buffer
yaw=((rxBuf[3]>>2)<<8)+rxBuf[0]-yaw0;
pitch=((rxBuf[4]>>2)<<8)+rxBuf[1]-pitch0;
roll=((rxBuf[5]>>2)<<8)+rxBuf[2]-roll0;
DisplayResults();
}
}
- sorceress sarah
- Posts: 100
- Joined: Sat Jun 20, 2009 2:07 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
One last change:
Applies an infinite impulse response filter to the data. Alpha is declared as:
A value of 0.1 provides about 10% smoothing. Smaller values for alpha provide more smoothing but at the expense of lag. There's your trade-off: Smooth data or fast response. Alpha can be adjusted to best suit your application. This has a significant advantage over a Finite Impulse Response filter in that it is computationally cheap. It requires only 4 extra bytes (float uses single-precision in PSoC) of memory and executes quickly.
If another interface (USB, I2C, SPI, 1-Wire, UART) is added, Alpha can be set at run-time and adjusted on the fly.
Code: Select all
for (;;){ //Loop forever
status = I2Cm_bWriteCBytes(WiiMP_ADDR,txZeroBuf,1,I2Cm_CompleteXfer); // Write a zero to request data
status = I2Cm_fReadBytes(WiiMP_ADDR, rxBuf, 6, I2Cm_CompleteXfer); // Read the data into the receive buffer
// Smooth the data with IIR
yaw = yaw + alpha * ((((rxBuf[3]>>2)<<8)+rxBuf[0]-yaw0) - yaw);
pitch = pitch + alpha * ((((rxBuf[4]>>2)<<8)+rxBuf[1]-pitch0) - pitch);
roll = roll + alpha * ((((rxBuf[5]>>2)<<8)+rxBuf[2]-roll0) - roll);
DisplayResults();
}
Code: Select all
float alpha = 0.1;
If another interface (USB, I2C, SPI, 1-Wire, UART) is added, Alpha can be set at run-time and adjusted on the fly.
Last edited by sorceress sarah on Wed Jun 24, 2009 12:03 am, edited 1 time in total.
- sorceress sarah
- Posts: 100
- Joined: Sat Jun 20, 2009 2:07 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
There's still something wrong and I think it's in the original Arduino code. I get results on the LCD:
at rest:
Yaw = 4462x
Pitch = 462x
Roll = 54462x
where x is uncertain. Has anyone tried out the Arduino code on an Arduino?
at rest:
Yaw = 4462x
Pitch = 462x
Roll = 54462x
where x is uncertain. Has anyone tried out the Arduino code on an Arduino?
- fat16lib
- Posts: 595
- Joined: Wed Dec 24, 2008 1:54 pm
Re: Wii MotionPlus protocol. . . Let us hack . . .
The buffers are still part of the problem.
allocates a single byte, the string's zero byte, with most compilers. Try a dimension of 7 like this:
Looks like the three strings overlay each other. Note the common sub string 462.
Code: Select all
char yBuf[];
Code: Select all
char yBuf[7];
Looks like the three strings overlay each other. Note the common sub string 462.
Please be positive and constructive with your questions and comments.