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

Support for Start/Stop (non Repeated Start) reads? #14

Closed
brendanarnold opened this Issue Jul 25, 2015 · 5 comments

Comments

Projects
None yet
2 participants
@brendanarnold

brendanarnold commented Jul 25, 2015

I'm not familiar with the I2C conventions but it seems that some implementations (notably the Raspberry Pi, see this answer http://raspberrypi.stackexchange.com/a/7142/12232) use a STOP/START sequence rather than a START sequence when performing a I2C read e.g.

[ 3 0 ] [ 2 r r r r r ]

instead of

[ 3 0 [ 2 r r r r r ]

Is this something that the TinyWire library can be made resilient to? Is this something that should be supported?

@rambo

This comment has been minimized.

Show comment
Hide comment
@rambo

rambo Jul 25, 2015

Owner

Tinywire does not care, neither should any of my examples (in fact the star/stop events are not even exposed to the user code). BUT Raspberry Pi has a I2C master that cannot deal with a slave that does clock-stretching and on attiny85 @8MHz the slave will always stretch the clock.

Owner

rambo commented Jul 25, 2015

Tinywire does not care, neither should any of my examples (in fact the star/stop events are not even exposed to the user code). BUT Raspberry Pi has a I2C master that cannot deal with a slave that does clock-stretching and on attiny85 @8MHz the slave will always stretch the clock.

@brendanarnold

This comment has been minimized.

Show comment
Hide comment
@brendanarnold

brendanarnold Jul 25, 2015

Hmm if that is the case then I am at a loss - I have tried reducing the Baud rate of the I2C bus down to much lower rates progressively from 100kbps, to 32kpbs, 10kbps 1kbps and even 500bps and the results are progressively improved but always break down after enough block reads.

The code I am using is https://github.com/rambo/TinyWire/blob/master/TinyWireS/examples/attiny85_i2c_slave/attiny85_i2c_slave.ino and so should not be using too many cycles to process each read - is it really the case that clock stretching is always used?

The ATTiny85 is running at 8MHz on an internal clock at 3.3V. The Raspberry Pi code is Python using the smbus module wrapper.

brendanarnold commented Jul 25, 2015

Hmm if that is the case then I am at a loss - I have tried reducing the Baud rate of the I2C bus down to much lower rates progressively from 100kbps, to 32kpbs, 10kbps 1kbps and even 500bps and the results are progressively improved but always break down after enough block reads.

The code I am using is https://github.com/rambo/TinyWire/blob/master/TinyWireS/examples/attiny85_i2c_slave/attiny85_i2c_slave.ino and so should not be using too many cycles to process each read - is it really the case that clock stretching is always used?

The ATTiny85 is running at 8MHz on an internal clock at 3.3V. The Raspberry Pi code is Python using the smbus module wrapper.

@rambo

This comment has been minimized.

Show comment
Hide comment
@rambo

rambo Jul 26, 2015

Owner

The streching happens already at when tinywire (on the library level) checks if this is our slave address or not. In theory on low enough clock speeds the streching should not matter any more but for practical speeds you will hit http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html often enough for things to be unreliable.

You can use this sketch on an ATMega328 based Arduino (Uno, Duemilanove etc) to verify that things work correctly with a properly working I2C master: https://github.com/rambo/I2C/blob/master/examples/i2crepl/i2crepl.ino

Owner

rambo commented Jul 26, 2015

The streching happens already at when tinywire (on the library level) checks if this is our slave address or not. In theory on low enough clock speeds the streching should not matter any more but for practical speeds you will hit http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html often enough for things to be unreliable.

You can use this sketch on an ATMega328 based Arduino (Uno, Duemilanove etc) to verify that things work correctly with a properly working I2C master: https://github.com/rambo/I2C/blob/master/examples/i2crepl/i2crepl.ino

@brendanarnold

This comment has been minimized.

Show comment
Hide comment
@brendanarnold

brendanarnold Jul 27, 2015

I found a few things that might be of interest

I tried out the code you posted here https://github.com/rambo/I2C/blob/master/examples/HMC5883L/HMC5883L.ino on an UNO and using the I2C library it worked perfectly. However I also tried the Wire.h example in the comments below.

Generally I found about 5 to 20 read errors in every 10,000 reads. I took out the Wire.endTransmission() and it worked perfectly (presumably this gives true repeated start rather than the stop-start). This was similar behaviour to what I was finding on the Raspberry Pi after lowering the Baud rate to 32,000. Final code snippet below (for device at address 0x05)

Wire.beginTransmission(0x05);
Wire.write(0x00);
Wire.requestFrom(0x05, 3);
x = Wire.read();
y = Wire.read();
z = Wire.read(); 

I think the problem is the ATTiny code occasionally not hitting the Stop check in time even though it was the only bit of logic in the loop() function.

So it seems Raspberry Pi with the out-of-the-box SMBUS has two problems when using TinyWireS, i.e. clock stretching (fix by raising speed of ATTiny using external 16MHz crystal and lowering RPi I2C BaudRate) and the ATTiny occasionally missing the stop signal in start-stop I2C read requests.

Most libraries for RPi just wrap the SMBUS commands but the PiGPIO library provides a deamon that you can call in Python to 'bit bang' at the level of the bus-pirate notation and it support clock stratching. To read using repeated-start, try the following

import pigpio

# Use the existing I2C pins since they have pullups builtin
SDA = 2 
SCL = 3

pi = pigpio.pi()
fh = pi.bb_i2c_open(SDA)

# The following uses the pigpio notation found at 
# http://abyz.co.uk/rpi/pigpio/python.html#bb_i2c_zip
# Basically the numbers in HEX are the data sent, the rest are START, STOP etc.
(b, d) = pi.bb_i2c_zip(SDA, [4, 0x05, 2, 7, 1, 0x00, 2, 6, 0x03, 3, 0])

print [int(x) for x in d] # Prints contents of first three registers

This worked without error for as long as I tested (100,000 reads)

Sorry for long comment but I wanted to make sure that user of my device could use the ATTiny85 with out-of-the-box components as much as possible.

brendanarnold commented Jul 27, 2015

I found a few things that might be of interest

I tried out the code you posted here https://github.com/rambo/I2C/blob/master/examples/HMC5883L/HMC5883L.ino on an UNO and using the I2C library it worked perfectly. However I also tried the Wire.h example in the comments below.

Generally I found about 5 to 20 read errors in every 10,000 reads. I took out the Wire.endTransmission() and it worked perfectly (presumably this gives true repeated start rather than the stop-start). This was similar behaviour to what I was finding on the Raspberry Pi after lowering the Baud rate to 32,000. Final code snippet below (for device at address 0x05)

Wire.beginTransmission(0x05);
Wire.write(0x00);
Wire.requestFrom(0x05, 3);
x = Wire.read();
y = Wire.read();
z = Wire.read(); 

I think the problem is the ATTiny code occasionally not hitting the Stop check in time even though it was the only bit of logic in the loop() function.

So it seems Raspberry Pi with the out-of-the-box SMBUS has two problems when using TinyWireS, i.e. clock stretching (fix by raising speed of ATTiny using external 16MHz crystal and lowering RPi I2C BaudRate) and the ATTiny occasionally missing the stop signal in start-stop I2C read requests.

Most libraries for RPi just wrap the SMBUS commands but the PiGPIO library provides a deamon that you can call in Python to 'bit bang' at the level of the bus-pirate notation and it support clock stratching. To read using repeated-start, try the following

import pigpio

# Use the existing I2C pins since they have pullups builtin
SDA = 2 
SCL = 3

pi = pigpio.pi()
fh = pi.bb_i2c_open(SDA)

# The following uses the pigpio notation found at 
# http://abyz.co.uk/rpi/pigpio/python.html#bb_i2c_zip
# Basically the numbers in HEX are the data sent, the rest are START, STOP etc.
(b, d) = pi.bb_i2c_zip(SDA, [4, 0x05, 2, 7, 1, 0x00, 2, 6, 0x03, 3, 0])

print [int(x) for x in d] # Prints contents of first three registers

This worked without error for as long as I tested (100,000 reads)

Sorry for long comment but I wanted to make sure that user of my device could use the ATTiny85 with out-of-the-box components as much as possible.

@rambo

This comment has been minimized.

Show comment
Hide comment
@rambo

rambo Jul 27, 2015

Owner

Cool, need to add link to that library to the README so other RPi users can benefit from it. Thanks for the info.

Owner

rambo commented Jul 27, 2015

Cool, need to add link to that library to the README so other RPi users can benefit from it. Thanks for the info.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment