Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   C/C++ (http://www.chiefdelphi.com/forums/forumdisplay.php?f=183)
-   -   I2C Arduino Port (Wii MotionPlus) (http://www.chiefdelphi.com/forums/showthread.php?t=125733)

kylelanman 03-02-2014 07:59

I2C Arduino Port (Wii MotionPlus)
 
I'll start off by saying prior to this season our team has had no prior knowledge of I2C.

We successfully were able to talk to a LSM303D using the standard calls in the WPILib I2C class.

We are now trying to integrate with a Wii MotionPlus. We have a working setup with an Arduino. In hopes of eliminating the Arduino we tried to port the Arduino sketch to C++. Our limited knowledge of I2C has made this a little bit of a challenge.

Code:

/* Arduino */
void receiveData(){
  Wire.beginTransmission(0x52);    //now at address 0x52
  Wire.send(0x00);                    //send zero to signal we want info
  Wire.endTransmission();
  nunchuck)
  Wire.requestFrom(0x52,6);          //request the six bytes from the WM+
  for (int i=0;i<6;i++){
    data[i]=Wire.receive();
  }
}

I realize there is additional initialization that needs to happen. But that is straight forward. The 2 new concepts that the LSM303D did not require but that the Wii MotionPlus does are:
1. Sending data over I2C with no register as a target.
2. Receiving data over I2C with out a particular register as a source.

Code:

/* WPILib */
        // _wmp is an instance of I2C
        uint8_t buffer[6];
        _wmp->Transaction(0x00, 1, buffer, sizeof(buffer);

Are these code snippets functionally equivalent? If not what are the equivalent of requestFrom() and read() in the WPILib?

Thanks in advance to anyone that can assist us.

Kyle

Mike Bortfeldt 03-02-2014 09:00

Re: I2C Arduino Port (Wii MotionPlus)
 
Kyle,

I'll take a shot at this. My experience is with I2C in Java and an Arduino, but most of that should apply here. First, if you are using an address of 0x52 on an Arduino to communicate with the Wii MotionPlus, then you will most likely need to use an address of 0xA4 on the cRio. Your code doesn't show how you are setting up the I2C object. For the "receiveing data" portion, you should be able to use the following code to just receive data.

Code:

_wmp->Transaction(0x00, 0, buffer, sizeof(buffer));
The zero length of the send buffer will prevent the cRIO from transmitting any data. As for the sending without any address, the register address typically is the first byte in the transmission string. It is all up to the Wii MotionPlus on how it interprets the data it receives, so this should not be a problem.

Mike

kylelanman 03-02-2014 09:43

Re: I2C Arduino Port (Wii MotionPlus)
 
Quote:

Originally Posted by Mike Bortfeldt (Post 1336722)
Kyle,

I'll take a shot at this. My experience is with I2C in Java and an Arduino, but most of that should apply here. First, if you are using an address of 0x52 on an Arduino to communicate with the Wii MotionPlus, then you will most likely need to use an address of 0xA4 on the cRio. Your code doesn't show how you are setting up the I2C object. For the "receiveing data" portion, you should be able to use the following code to just receive data.

Thanks for the quick response can you explain why the change in address is needed when switching from the Arduino to the cRio? We did notice it was on a different address but don't understand why.

Thanks

Kyle

Mike Bortfeldt 03-02-2014 10:26

Re: I2C Arduino Port (Wii MotionPlus)
 
Kyle,

The I2C specification calls out for a 7 bit device address (there is also a 10 bit address, but that doesn't apply here), along with a single bit to indicate read/write. This information is combined where the address is the high 7 bits and the read/write is the LSB as shown below, where 'A' indicates an address bit and R indicates the read/write bit (write is 0, read is 1)

Code:

Bit (MSB) 76543210 (LSB)
          AAAAAAAR

Some devices interpret this (or at least sometimes describes it) as two 8 bit addresses, one for read one for write. The Arduino uses the specificed 7 bit address and internally bit shifts it by 1 (effectively multiplying the address by 2) and then adds the read/write. The cRio wants you to specifiy the address already bit shifted. You'll notice that the cRio addresss I gave is the same as the Arduino * 2.

Hopefully this makes sense.

Mike

For reference, I found the I2C bus specification here : http://www.nxp.com/documents/user_manual/UM10204.pdf

kylelanman 03-02-2014 13:39

Re: I2C Arduino Port (Wii MotionPlus)
 
Your explanation of the addresses makes sense and clears things up.

I realized I misread your first post and didn't catch the difference between your snippet and mine.

Quote:

Originally Posted by kylelanman (Post 1336707)

Code:

/* Arduino */
void receiveData(){
  Wire.beginTransmission(0x52);    //now at address 0x52
  Wire.send(0x00);                    //send zero to signal we want info
  Wire.endTransmission();
  nunchuck)
  Wire.requestFrom(0x52,6);          //request the six bytes from the WM+
  for (int i=0;i<6;i++){
    data[i]=Wire.receive();
  }
}

Code:

/* WPILib */
        // _wmp is an instance of I2C
        uint8_t buffer[6];
        _wmp->Transaction(0x00, 1, buffer, sizeof(buffer);


Quote:

Originally Posted by Mike Bortfeldt (Post 1336722)

Code:

_wmp->Transaction(0x00, 0, buffer, sizeof(buffer));

With my 1 transaction call I was trying to kill 2 birds with one stone. The Wii MotionPlus requires that you send 0x00 in order for it to return data. That is why I was using a size of 1. Will this work all in one transaction or do we need to do 2 separate transactions. 1 for sending 0x0 and the other for receiving?

Thanks

Kyle

Mike Bortfeldt 03-02-2014 13:53

Re: I2C Arduino Port (Wii MotionPlus)
 
Kyle,

Quote:

Originally Posted by kylelanman (Post 1336899)
Will this work all in one transaction or do we need to do 2 separate transactions. 1 for sending 0x0 and the other for receiving?

You should be able to do this in one transaction as you had in your original post. I misunderstood what you were asking.

Mike

- You may also want to verify if the transmit data (buffer) needs to be passed as an address to a byte array. I know in Java this is true.

kylelanman 03-02-2014 23:42

Re: I2C Arduino Port (Wii MotionPlus)
 
Thanks for all the help. We had moderate success tonight.

The biggest thing that we never would have figured out was the addressing. On the Arduino you have to initialize the Wii MotionPlus on 0x53. Then communicate with it on 0x52.

When switching to the cRio we initially were trying to initialize it at 0xa5 and then communicate with it on 0xa4. Thanks to your advice we figured out it needed to be 0xa6 and 0xa4.

We were having a load of problems with execution hanging at the Transaction call. After separating it out into 7 separate transactions. 1 write and 6 reads things smoothed out. Some additional searching on chief delphi leads us to believe that WPILib only supports reading or writing 4 bytes at a time. The comments in the source indicate 7 so that was mildly frustrating. At this point I think we have it working.

Provided we end up going this route once we get the code cleaned up and all the bugs worked out we hope to share our seemingly robust wrapper for the Wii MotionPlus with the rest of the first community.

Thanks Again!!!

Kyle

Mike Bortfeldt 04-02-2014 09:09

Re: I2C Arduino Port (Wii MotionPlus)
 
Kyle,

Glad to hear you are making progress. If you could post what you are (or are not seeing) when you try transactions > 4 bytes, perhaps I could help. The cRio should be able to communicate in up to 7 byte transactions (at least it was able to last year). One thing you could try is to call "setCompatibilityMode(true)" on the I2C object. This will probably not do anything as I read that it was set to TRUE by default this year (unlike last year), but it won't hurt to try. I also had some initial issues last year with Java and the bytes > 4 (wrong data), but that was specific to Java and should be corrected this year.

Mike

kylelanman 04-02-2014 15:11

Re: I2C Arduino Port (Wii MotionPlus)
 
When trying to troubleshoot the lockups we slowly broke the following line into multiple calls.

Code:

_wmp->Transaction(0x00, 1, &buffer[0], sizeof(buffer));
Code:

printf("I2C Write\n");
_wmp->Transaction(0x00, 1, 0, 0;
printf("I2C Read Start\n");
_wmp->Transaction(0, 0, &buffer[0], sizeof(buffer));
printf("I2C Read Finish\n");

At this point it would lockup and the console would show the following.
Code:

...
I2C Write
I2C Read Start

Whenever a lockup occurred we found that momentarily removing power from the Wii MotionPlus would unlock the system and it would continue executing for 10s of seconds before the same thing happened.

We ended the night with the following code and had successfully run 5 minutes with no lockups. That may just be a coincidence

Code:

_wmp->Transaction(0x00, 1, 0, 0);
_wmp->Transaction(0, 0, &buffer[0], 1));
_wmp->Transaction(0, 0, &buffer[1], 1));
_wmp->Transaction(0, 0, &buffer[2], 1));
_wmp->Transaction(0, 0, &buffer[3], 1));
_wmp->Transaction(0, 0, &buffer[4], 1));
_wmp->Transaction(0, 0, &buffer[5], 1));

Thanks again and appreciate your willingness to assist!!!

Kyle

Mike Bortfeldt 04-02-2014 19:16

Re: I2C Arduino Port (Wii MotionPlus)
 
Kyle,

It's interesting that it hangs on the read transaction. The actual I2C communication is handled by the FPGA so it's a little difficult to know exactly what is happening. Normally, I would expect the transaction to return an error if it couldn't complete. My only thought is that the Wii MotionPlus is holding the clock signal low preventing the transaction from completing. Removing power from the Wii would allow the clock to resume. There are two things I can suggest you try.

First, the transaction routine expects a pointer to a byte array for the "dataToSend" argument. So I think your 0x00 in the send transmission is getting converted to a pointer to memory address 0x00 rather than a value of zero. Try changing to the following:
Code:

uint8_t sendBuffer[1]={0};
_wmp->Transaction(sendBuffer, 1, 0, 0);

Second, ensure the setCompatibilityMode is set to true in your initiation routine.
Code:

_wmp->setCompatibilityMode(TRUE);
Other than these two things, your code looks like it should work.

Mike

Joe Hershberger 05-02-2014 02:26

Re: I2C Arduino Port (Wii MotionPlus)
 
Quote:

Originally Posted by kylelanman (Post 1337274)
Some additional searching on chief delphi leads us to believe that WPILib only supports reading or writing 4 bytes at a time. The comments in the source indicate 7 so that was mildly frustrating.

For the first year or two the cRIO FRC personality in the FPGA supported only 4 bytes per transaction. Since then it has supported 7. Perhaps that's why you found out-of-date information on CD.


All times are GMT -5. The time now is 12:49.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi