Wire Library - Device Not Present

I would try testing this out myself first, but I can't find the stupid cord I made for the device I want to try.* Short version of the project, I want to program my Leonardo to use a Wii Nunchuk as a mouse.

The Nunchuk communicates with the IIC protocol, which is the Wire.h library in Arduino. I've already found a library that reads information from the Nunchuk (http://www.gabrielbianconi.com/projects/arduinonunchuk/), but I'm looking through the source and wondering what would happen if the Nunchuk was unplugged. In particular, I want to know about the behavior of these two functions when the device is not present on the bus.

Wire.available()
Wire.read()

The key part of the function that I'm looking at is:

  Wire.requestFrom(ADDRESS, 6);

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

What happens when this is run when no nunchuk is plugged in? What do available() and read() return? Will the while loop run forever, or never?

If it's problematic like this, how could I modify it to check for the presence or absence of the device?

  • For those curious, rather than hack apart my Nunchuk's cord and destroy it, I bought an extension cord and crimped an RJ-45 onto the end of it. After weeks of having it be in the most inconvenient spots shuffling around my bedroom, it's now lost when I actually want it. Such is life.

If it's problematic like this, how could I modify it to check for the presence or absence of the device?

Look at the code in an I2C scan sketch.

Found one here: Arduino Playground - I2cScanner

Looks like it'll answer that question.

Furthermore, it looks like the library I have is assuming the Nunchuk is always plugged in. It wouldn't deal with the situation of an unplugged Nunchuk. I'll probably have to fix that somehow.

That library is the one you are using (as seen by the statement #include <Wire.h>). I2C Scanner contains precisely the code you need to check to see if a device is present. In fact, the code looks for all possible devices and reports the ones it finds.

Based on my code from this page:

You basically check if you get anything back from

  Wire.requestFrom (NUNCHUK_ADDRESS, 6);// request data from nunchuk

  ...

  // no data from nunchuk
  if (Wire.available () < 6) 
    return false;

Although really you should check the return from Wire.requestFrom like this:

if (Wire.requestFrom (NUNCHUK_ADDRESS, 6) != 6)
  return false;   // no data

Also you can check on the endTransmission:

  Wire.beginTransmission(NUNCHUK_ADDRESS);
  Wire.send(0);
  if (Wire.endTransmission() != 0)
     return false;   // no response

Am I correct in thinking that requestFrom is a blocking function? Does it wait for all the bytes to be clocked before returning?

Just tested that with my own version of the library, and it looks like requestFrom()'s return value will be my best option to use. I'll start making my library now.

Thanks for the help, Grumpy & Nick.

EDIT: One more question, if I read bytes with the requestFrom() function, but don't want to use them, how do I clear the buffer? Will flush() (Inherited from Stream class) work? Do I need to do a read() loop? Or will it be cleared next time requestFrom() is called? (Probably not)

Yes, it blocks.

uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
{
  // clamp to buffer length
  if(quantity > BUFFER_LENGTH){
    quantity = BUFFER_LENGTH;
  }
  // perform blocking read into buffer
  uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);
  // set rx buffer iterator vars
  rxBufferIndex = 0;
  rxBufferLength = read;

  return read;
}

It looks like it resets the buffer so you don't necessarily need to clear it.

Jiggy-Ninja:
Am I correct in thinking that requestFrom is a blocking function? Does it wait for all the bytes to be clocked before returning?

From the Wire - Arduino Reference, "Used by the master to request bytes from a slave device. The bytes may then be retrieved with the available() and read() functions."

You should probably read that and the other functions linked from Wire - Arduino Reference

However that page is unclear about whether it blocks. For example, doing a Serial.read doesn't block.

More stuff about I2C:

Ah, thank you for that. I know where to find the Arduino source code in the hardware folder, but I'm a bit new at reading code like this. The only stuff I was exposed to at school was dirt simple lab examples and assignments, so professionally done code like this can be a bit over my head to look through and interpret.

I haven't looked at the library code, but the wording of the docs for that function would seem to be saying that the function blocks, in the sense that it completes a read into a buffer that belongs to the library, and then it returns the number of bytes it read, but those bytes need to be fetched by the user's program with read();

I just wanted to make sure that Jiggy-Ninja understands that the function doesn't return the bytes, but only the number of bytes it retrieved.

lar3ry:
I haven't looked at the library code, but the wording of the docs for that function would seem to be saying that the function blocks, in the sense that it completes a read into a buffer that belongs to the library, and then it returns the number of bytes it read, but those bytes need to be fetched by the user's program with read();

I just wanted to make sure that Jiggy-Ninja understands that the function doesn't return the bytes, but only the number of bytes it retrieved.

I did look at the library reference page before I asked,and agree with Nick that it was ambiguous. I did understand that it returned the number of bytes, rather than the data. Wire.read() is for the data.

Thanks to the help here I was able to modify the library to detect when it was plugged in, and even reinitialize the connection when it detects it being plugged back in. After i clean it up more, I'll need to find somewhere to post it.