0
\$\begingroup\$

I'm new to I2C and am trying to get two ATtiny85 to talk to each other.

  • I have Arduino IDE 1.8.0
  • I used this link (damellis) to install the ATtiny board in the IDE
  • I use an Arduino nano to program the ATtiny85.
  • I use this TinyWire library from lucullusTheOnly.

The ATtiny has to be able of being both master and slave. I based my code on this example of lucullusTheOnly.

I have a very simple program (see below) that sends one character on the bus, but I get an error 0x0C USI_TWI_ARBITRATION_LOST.

I reduced my setup to only the master on the breadboard with 5kOhm pullups on the two I2C wires (2x10kOhm in parallel) to 5V to eliminate all other traffic. But the error remains. Really nothing else on the board.

ATtiny pin usage
3 --> 1kOhm --> LED --> GND (for flashing out error-code)
4 --> GND
5 --> Pullup 5kOhm --> 5v
6 --> Pullup 5kOhm --> 5v
8 --> 5V

I have no scope at hand to monitor traffic on the bus. I can go to a lab next week, but that's long waiting ;-/

In Arduino IDE, I have the Clock speed of the ATtiny set to 1Mhz (was default). Could that be the problem? Should I increase that? Can I simply change that in the Tools>Clock menu? I thought I read somewhere that I had to burn the bootloader too.

Test program:

#include <TinyWire.h>

int error_led_pin = 3; // == physical pin 2 on attiny

byte own_address = 10;
byte slave_address = 11;


void setup() {
   // config error_led_pi as Output for driving an LED
   pinMode(error_led_pin, OUTPUT);   
   // config TinyWire library for I2C slave functionality
   TinyWire.begin( own_address );

   TinyWire.beginTransmission( slave_address );
   // fill the send buffer
   TinyWire.send('b');
   // execute the master sending and check for an error
   // returns 0 if there was no error (otherwise you can find the different error code definitions in TinyWire.h)
   int errorCode = TinyWire.endTransmission();
   if(errorCode!=0) {
      // turn on the error LED, if there was an error
      handleError(errorCode);
   }
}

void loop() {

}

void handleError(int code) {
   if (code != 0) {
      // *** ERROR ***
      // errors defined at https://github.com/lucullusTheOnly/TinyWire/blob/master/TinyWire.h
      digitalWrite(error_led_pin, LOW); // TODO: remove!
      delay(500);
      // blink resultCode number of times  // TODO: should be led at pin 2 = push button
      for (int i = 0; i <= code; i++) {
         digitalWrite(error_led_pin, HIGH);
         delay(500);
         digitalWrite(error_led_pin, LOW);
         delay(500);
      }
   }
}

Any thoughts on finding why I get USI_TWI_ARBITRATION_LOST ?

\$\endgroup\$
  • 1
    \$\begingroup\$ arduino logic analyzer ... elecenjoy.wordpress.com/2014/10/01/16 .... also one here instructables.com/id/… \$\endgroup\$ – jsotola Feb 21 '18 at 3:57
  • \$\begingroup\$ @jsotola, the second link creates a logical analyzer that can sample at about 10~20 microseconds. That's about 100kHz? Is that enough to sample I2C signals? I thought the I2C clock was at 400kHz by default. Not sure though! \$\endgroup\$ – mvermand Feb 21 '18 at 5:56
  • \$\begingroup\$ @jsotola correction, the default I2C clock speed seems to be 100kB/s (i2c-bus.org/speed), so I think the Logical Analizer sampling at max 8kB/s will not be able to sample this, right? \$\endgroup\$ – mvermand Feb 21 '18 at 6:06
2
\$\begingroup\$

I've looked at this library on GitHub where you got it from and I looked at the TinyWire.h file. This is what it says about the exception that you're receiving.

" #define USI_TWI_ARBITRATION_LOST 0x0C // The master lost the arbitration due to the transmission of another master"

It looks like you're trying to I2C between more than one master when in fact you need a slave. That's how I2C works. Therefore, when you get this error, there's some conflict of interest with your I2C and it won't let one of the masters connect until you have a slave.

I've tried looking at other code to see where the author of this TinyWire library has demonstrated where this exception occurs but I haven't found anything else about it.

EDIT: Wait! I did find something about it... This is in the twi.cpp file.

#ifdef BUS_ARBITRATION if(!ack && (USISR & (1<<USIDC))) { // Check data collision bit Twi_slave_init(slaveAddress); result.result = 0; result.error_code = USI_TWI_ARBITRATION_LOST; return result;

Looking at this if statement right here, if there hasn't been acknowledgement from the slave while USISR (which appears to be a variable for a flag) performs an AND operation with USIDC = 0 (USIDC is defined from above) which will always give you zero, it will raise that exception. In other words if there is no acknowledgement from your slave and if the flags are set to zero, you'll get this error.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ This could explain why the reduced setup with only one ATtiny does not work, but it does not explain why the initial setup with 2 ATtiny's doesnt work... I'll try digging in the code as you did. Thanks already. \$\endgroup\$ – mvermand Feb 20 '18 at 19:26
  • \$\begingroup\$ @mvermand You're welcome :) be sure and +1 and accept answers if you found one of our answers helpful. \$\endgroup\$ – user103380 Feb 20 '18 at 19:57
2
\$\begingroup\$

An I2C master will think it's lost arbitration if it releases the SDA pin and the SDA pin does not go high. It can happen if you have too much capacitance on the bus and so SDA is slow to rise. This can be a big problem especially at high frequencies.

Try reducing the pullup resistance to 1k and see if that helps.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

You can not talk between I2C masters. You need a master and a slave. See also Why can't masters talk to each other in a I2C bus?.

You get the error because both of your masters are trying to get on the I2C bus and one of them loses.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I do not have 2 masters. I have only one ATtiny in the reduced setup. And it is configured as a slave which can send to another slave as (temporary) master. See the provided links to the used example. It is all described there. \$\endgroup\$ – mvermand Feb 20 '18 at 19:17
0
\$\begingroup\$

If you only have a single I2C master in your system and thus you don't need arbitration just comment out the line

#define BUS_ARBITRATION

in twi.h and the I2C communication should work. I stopped debugging (simple master - slave system) at this point - might be some kind of race condition or wrong interpretation of the data collision bit USIDC in twi.cpp which throws the error:

    USICR = temp;                          // Generate negative SCL edge.
    #ifdef BUS_ARBITRATION
    if(!ack && (USISR & (1<<USIDC))) { // Check data collision bit
      Twi_slave_init(slaveAddress);
      result.result = 0;
      result.error_code = USI_TWI_ARBITRATION_LOST;
      return result;
    }
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.