Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I2C Repeated Start #390

Closed
tomgidden opened this issue Jun 12, 2014 · 16 comments
Closed

I2C Repeated Start #390

tomgidden opened this issue Jun 12, 2014 · 16 comments

Comments

@tomgidden
Copy link

I'm trying to write a library for MPL3115A2 (note, NOT the existing MPL115A2) but according to the Arduino library along with various Google results, it appears that it needs Repeated Start capability on I2C: I think this means not sending a STOP command after a read or a write.

Whether or not this is correct behaviour for I2C slave devices (which as far as I can see should be able to support with and without repeated starts), it's been an issue on Raspberry Pi (since fixed), and was added to Arduino in v.1.0.1.

Related code (from the MPL3115A2 Arduino driver):

// These are the two I2C functions in this sketch.
byte MPL3115A2::IIC_Read(byte regAddr)
{
  // This function reads one byte over IIC
  Wire.beginTransmission(MPL3115A2_ADDRESS);
  Wire.write(regAddr);  // Address of CTRL_REG1
  Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
  Wire.requestFrom(MPL3115A2_ADDRESS, 1); // Request the data...
  return Wire.read();
}

and also, http://raspberry.znix.com/2013/03/raspberry-pi-and-repeated-start-i2c.html

I'd guess this might be best presented as an extra optional boolean parameter on I2C.readFrom and I2C.writeTo, although the fix for #370 might scupper that.

@gfwilliams
Copy link
Member

Thanks. Yes, that's a pain.

Are there any other patterns apart from write then read? I guess it might end up being easier to just have a new function that did just that.

Or perhaps:

I2C.writeTo({address:0x55, stop:false}, data);
I2C.readFrom({address:0x55, stop:false}, count);

@tomgidden
Copy link
Author

I don't know of any other patterns, but it's possible I guess. Maybe keep writeTo and readFrom as-is for a higher-level capability where it doesn't matter, but also build beginTransmission,write,requestFrom,read and endTransmission to match Arduino when greater control is needed. A bit like fopen/fread/fclose vs. open/read/close in C.

It would be handy to have an I2C.readRegister(address, register, count=1) convenience function, although I don't know how widespread Repeated Start is. I've only programmed a few I2C devices, and this is the first one I've encountered that needs Repeated Start. I don't know whether other devices allow it, prefer it or prohibit it. Apparently it is an official thing, though: http://www.i2c-bus.org/repeated-start-condition/

@gfwilliams
Copy link
Member

I'm sort of against re-implementing Arduino's functions, because they tend to complicate things and provide more opportunity for error. Also a silicon problem on the STM32F1 means that you can totally lock up the I2C peripheral if you send a STOP at the wrong time, so it's good not to let people have that choice :)

I don't think that allowing an object instead of a numeric address would cause any backwards compatibility problems though - at least not unless people were doing something really nasty.

@gfwilliams
Copy link
Member

Just tried to fix this... it should work like:

I2C.writeTo({address:0x55, stop:false}, data);
I2C.readFrom({address:0x55, stop:false}, count);

I don't have anything to test with though, so please let me know how this works.

A build should be up soon at: http://www.espruino.com/binaries/git/commits/a939ef6285ca9c6f639d4edaaf86fe7606176829

@gfwilliams
Copy link
Member

Looks like this may not work - but I'll have to get some hardware to test with first.

@gfwilliams gfwilliams reopened this Aug 11, 2014
@tomgidden
Copy link
Author

@gfwilliams : unfortunately I'm not going to have a chance to test this for a while, thanks to real life. However, I'd be happy to buy you an MPL3115A2 if you want to have a go with it... if so, email or DM me with postal address.

@tomgidden
Copy link
Author

@gfwilliams I just tested this with 1v70:

    var _read_reg = function (_i2c, _reg) {
        _i2c.writeTo({address:MPL3115A2_ADDRESS /* 0x60 */, stop:false}, _reg);
        var bs = _i2c.readFrom(MPL3115A2_ADDRESS, 1);
        return bs[0];
    };

    var whoami = _read_reg(_i2c, MPL3115A2_WHO_AM_I /* 0x0C */);
    console.log("WHOAMI (should return 196 apparently): "+whoami);

returns:

WHOAMI: undefined
Uncaught InternalError: Timeout on I2C Read BUSY

I've been using https://github.com/sparkfun/MPL3115A2_Breakout/blob/master/firmware/MPL3115A2/MPL3115A2.ino#L355 as a reference.

I'm currently using BMP180 instead as it's cheaper, more accurate, and simpler. However the MPL3115A2 does have on-board altitude calculation (lower memory footprint?) and has interrupt lines (ultra low power capability). The I2C Repeated Start is, however, probably worth fixing for other devices I suppose.

@gfwilliams
Copy link
Member

Hi - thanks for testing it out (and for the offer of a sensor)... I've actually just bought one though - when it arrives I'll see if I can fix the repeated start issue. It should only be a few lines I hope!

@tomgidden
Copy link
Author

Incidentally, while hacking the libraries on nrf51, I noticed that the MPU6050 code write/read routine for that SDK uses Repeated Start too. I believe it's optional on that sensor.

@errantspark
Copy link

I'm trying to get an MMA8451 (http://www.adafruit.com/datasheets/Freescale_MMA8451QR1.pdf) working and it doesn't seem like the repeated start is working properly?
I get

 Uncaught InternalError: Timeout on I2C Read BUSY

when I try to read after writing an address with stop set to false. Reading gives me the same 7 bytes every time.

Relevant Arduino code:
https://github.com/adafruit/Adafruit_MMA8451_Library/blob/master/Adafruit_MMA8451.cpp

@gfwilliams
Copy link
Member

Ok, thanks. Will try and look into it when I get back to the UK.

What board was this on? The I2C implementations are different on different chips

@gfwilliams
Copy link
Member

What board were you using? a Pico?

@errantspark
Copy link

yup, using a pico

@gfwilliams
Copy link
Member

Fixed. On the MPL3115, the following code now works:

function r(addr) {
  i2c.writeTo({address:0x60, stop:false}, addr);
  return i2c.readFrom(0x60,1)[0];
}

var i2c = I2C3;
i2c.setup({sda:B4,scl:A8});
r(0x0c)==196; // WHOAMI

@errantspark
Copy link

Just came back to this project, using 1v85 and I cannot get it to connect on I2C1. On I2C3 (on a different board) it works fine. Unfortunately for my current project i'm using those pins for SPI so a way to get this working with I2C1 would be super helpful. Same Uncaught InternalError: Timeout on I2C Write BUSY error as before. Using the code snippet from above but different (obviously) addresses.

@gfwilliams
Copy link
Member

You sure it's not that you're missing pullup resistors or having SDA/SCL mixed? The code is identical for I2C1/2 and 3 - so the chances of it working on one and not the other are pretty minimal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants