Arduino Mega 2560: I2C issues (configured as a i2c slave)

hello,
I have issues with a Arduino Mega 2560 which is configured as a i2c slave.
I’m using digital pins 20+21 for SDA and SCL.

I have the following program running on my Mega
the i2c rspond message is overall 14 bytes long, stored values are 0…13 according to the array index.

The i2c connection is set up correctly (checked),
but the master receives and displays just the first numer (0) and then just “255” (unsigned byte) or -1 (signed char)

Instead, if I use this program by my Uno everything is fine, though (used pins: analog 4+5), all values from 0 to 13 are shown completely correctly!

i2c Master is a Lego Mindstorms NXT.

Any ideas what’s going wrong?
Any ideas about isolating the error?

This is the Arduino source code:

//***********************************************************************************
// I²C Multiplexor:  Arduino Slave
// ver 1.101 Arduino Mega 2560  
//************************************************************************************
//


#include <PID_v1.h>
#include <Wire.h>

#define DEV_ADDR_I_ARDUINO  4 // I_ARDUINO I2C dev addr (to shift to upper 7 bit << 1 == 8)



#define MAXMAINCOUNTER     11 // main loop counter 0-11 for 1/12 thread priority division

    
// I2C setup:
// SDA: dig pin 20 <-> NXT blue   (+pullup resitor 47k-83k -> NXT Vc 4,3V)
// SCL: dig pin 21 <-> NXT yellow (+pullup resitor 47k-83k -> NXT Vc 4,3V)
// >>> !!! connect Arduino-GND <-> NXT-GND red wire !!! <<<
// >>> !!! DON'T connect Arduino-Vc <-> NXT-Vc  green wire !!! <<<  DON'T DO IT !!!  <<<




//************************************************************************************
// global variables for I²C master-slave communication
//************************************************************************************

    #define I2CMSGSIZE   14 // size of I2C messages (byte arrays to send + receive)



    byte i2cmastermsg[I2CMSGSIZE],  // i2c master message (command)
                               // 0+1: chksum (INT_16)
                               // 2: acknowledge
                               // 3: MOTORSLOT: MotNr
                               // 4: mot_runstate
                               // 5: pwm
                               // 6+7: mot enc_int16
                               // 8: buffer (encoder INT_24?)
                               // 9: ANASLOT:
                               // 10+11:
                               // 12+13: DIGSLOT: write digital pins 12(0-7) + 13(8-15)

         i2cslavemsg[I2CMSGSIZE]; //i2c slave message (reply)
                               // 0+1: chksum (INT_16)
                               // 2: acknowledge
                               // 3: MOTORSLOT: MotNr
                               // 4: mot_runstate
                               // 5: pwm
                               // 6+7: mot enc_int16
                               // 8: buffer (encoder INT_24?)
                               // 9: ANASLOT: nr
                               // 10+11: INT_16
                               // 12+13: DIGSLOT: write digital pins 12(0-7) + 13(8-15)


//************************************************************************************
// setup
//************************************************************************************
    int   __mainloopcnt__=0;             // counter for priority prescaler in main loop

    void setup()
    {
       //------------------------------------------------------------------------------------ 
      
       Wire.begin(DEV_ADDR_I_ARDUINO);   // join i2c bus with MY (I_ARDUINO) dev address
       Wire.onReceive(receiveEvent);     // register event
       Wire.onRequest(requestEvent);     // register event

       memset (i2cslavemsg, 0, sizeof(i2cslavemsg)); // reset i2c msg array

       
       
       pinMode(12,        INPUT_PULLUP);  // touchpin 12
       pinMode(13,        OUTPUT);        // touchpin => LED monitor 13

     
       //------------------------------------------------------------------------------------
       
    }



//************************************************************************************
// I²C events
//************************************************************************************

    void receiveEvent(int byteCount){

        byte i=0;
       
        while( Wire.available() ) {
          i2cmastermsg[i] = Wire.read();     // i2cmastermsg[0]: transmitted chksum
          ++i;                       // number of bytes read
        }

    }
    
//------------------------------------------------------------------------------------

    void requestEvent() {
      Wire.write(i2cslavemsg, sizeof(i2cslavemsg));  // respond with message (sizeof) bytes
    }



//************************************************************************************
// build I²C message to the master out of digital and analog values
//************************************************************************************

    
    
    void BuildI2Cmessage() {
      //memset (i2cslavemsg, 0, I2CMSGSIZE);
      for (int i=0; i<I2CMSGSIZE; ++i)  i2cslavemsg[i] = i ;
      
    }



//************************************************************************************
// main loop()
//************************************************************************************

    void loop()
    {

       // build I²C message to the master out of digital and analog values repeatedly
       if (__mainloopcnt__ % 2 == 0) {
          BuildI2Cmessage();                            // priority = 1/2
       }


       if (__mainloopcnt__ >=MAXMAINCOUNTER) {           // priority = 1/12
           __mainloopcnt__=0;                            // reset loop counter
       }

       delay(5);
    }

ps,
as written before, this was the downsized program version.
The complete versions which are already fine, both for Uno and NXT, you may find here:

http://www.mindstormsforum.de/viewtopic.php?f=70&p=65304#p65304

      for (int i=0; i<I2CMSGSIZE; ++i)  i2cslavemsg[i] = i ;

Every for loop I’ve ever written uses postfix notation for the increment step, not prefix notation. There IS a difference, and it may be a factor.

I can’t see that this code is doing anything useful. Setting the ith element of an array to i doesn’t strike me as useful, especially since you never do anything with the array.

There IS a difference, and it may be a factor.

There is a difference, but here it isn’t a factor.

Many old C++ hands will use the prefix operator for performance reasons (with older compilers), but these days there is no saving (it’s all to do with constructors)

yes, with prefix increment there never are issues, only postfix may probably cause issues - but never stand-allone in loop counters.

And, as already written, this code works fine on my Uno, and of course this code is just to check the connection and the data communication .

The complete versions which are already fine and doing something useful, both for Uno and NXT, you may find here: http://www.mindstormsforum.de/viewtopic.php?f=70&p=65304#p65166

If you code works on the UNO but not the Mega ( which is how I have understood your original post ), then one difference might be the pull-up resistors.

To use the Mega with 3.3V devices, you can phyiscally pull the I2C lines "up" to 3.3V with resistors, for this to be effective you need to edit the Wire library, and comment out the code which turns on the internal pull up resistors in the atmega chip.

The point here not being that you are using 3.3V, the point is that you may be having too many multiple instances of pulling up the same lines.

If you are reading FF's, could be the I2C data line is being pulled up too strongly.

I use 5V, and the pullups are to master Vc, not to Arduino Vc.

The bigger the resistors, the less they pull to +Vc,
currently I use 83k,
but I also tried resistors of 47k, 22k, 8.2k, 4.7k .

In case of resistors <= 22k there is no i2c connection at all, >=47k is fine for both Mega and Uno.

So pullups actually can’t be the reason of this malfunction.

update:
I meanwhile changed my test code for the respond image a little to become more meaningful:

    void BuildI2Cmessage() {
      for (int i=0; i<I2CMSGSIZE; ++i)  i2cslavemsg[i] = i+1 ;
      
    }

for the Mega:
now the master receives the first array cell correctly (1), and the rest is still 255 (-1).
so i2c connection is ok, just the last 13 values are not transmitted to the master.

for the Unos:
the master receives and shows all values correctly 1…14.

what the heck…?!?

ps, whole code:

//***********************************************************************************
// I²C Muxer feat. PID controller
// I²C Arduino Slave
// ver 1.101 Arduino Mega 2560 // transmitts medians of 3 sensor data
//************************************************************************************


#include <PID_v1.h>
#include <Wire.h>

#define DEV_ADDR_I_ARDUINO  4 // I_ARDUINO I2C dev addr (to shift to upper 7 bit << 1 == 8)



#define MAXMAINCOUNTER     11 // main loop counter 0-11 for 1/12 thread priority division

    
// I2C setup:
// SDA: dig pin 20 <-> NXT blue   (+pullup resitor 47k-83k -> NXT Vc 4,3V)
// SCL: dig pin 21 <-> NXT yellow (+pullup resitor 47k-83k -> NXT Vc 4,3V)
// >>> !!! connect Arduino-GND <-> NXT-GND red wire !!! <<<
// >>> !!! DON'T connect Arduino-Vc <-> NXT-Vc  green wire !!! <<<  DON'T DO IT !!!  <<<




//************************************************************************************
// global variables for I²C master-slave communication
//************************************************************************************

    #define I2CMSGSIZE   14 // size of I2C messages (byte arrays to send + receive)



    byte i2cmastermsg[I2CMSGSIZE],  // i2c master message (command)
                               // 0+1: chksum (INT_16)
                               // 2: acknowledge
                               // 3: MOTORSLOT: MotNr
                               // 4: mot_runstate
                               // 5: pwm
                               // 6+7: mot enc_int16
                               // 8: buffer (encoder INT_24?)
                               // 9: ANASLOT:
                               // 10+11:
                               // 12+13: DIGSLOT: write digital pins 12(0-7) + 13(8-15)

         i2cslavemsg[I2CMSGSIZE]; //i2c slave message (reply)
                               // 0+1: chksum (INT_16)
                               // 2: acknowledge
                               // 3: MOTORSLOT: MotNr
                               // 4: mot_runstate
                               // 5: pwm
                               // 6+7: mot enc_int16
                               // 8: buffer (encoder INT_24?)
                               // 9: ANASLOT: nr
                               // 10+11: INT_16
                               // 12+13: DIGSLOT: write digital pins 12(0-7) + 13(8-15)


//************************************************************************************
// setup
//************************************************************************************
    int   __mainloopcnt__=0;             // counter for priority prescaler in main loop

    void setup()
    {
       //------------------------------------------------------------------------------------ 
      
       Wire.begin(DEV_ADDR_I_ARDUINO);   // join i2c bus with MY (I_ARDUINO) dev address
       Wire.onReceive(receiveEvent);     // register event
       Wire.onRequest(requestEvent);     // register event

       memset (i2cslavemsg, 0, sizeof(i2cslavemsg)); // reset i2c msg array

       
       
       pinMode(12,        INPUT_PULLUP);  // touchpin 12
       pinMode(13,        OUTPUT);        // touchpin => LED monitor 13

     
       //------------------------------------------------------------------------------------
       
    }



//************************************************************************************
// I²C events
//************************************************************************************

    void receiveEvent(int byteCount){

        byte i=0;
       
        while( Wire.available() ) {
          i2cmastermsg[i] = Wire.read();     // i2cmastermsg[0]: transmitted chksum
          ++i;                       // number of bytes read
        }

    }
    
    
     
    
    
//------------------------------------------------------------------------------------

    void requestEvent() {
      Wire.write(i2cslavemsg, sizeof(i2cslavemsg));  // respond with message (sizeof) bytes
    }



//************************************************************************************
// build I²C message to the master out of digital and analog values
//************************************************************************************

    
    
    void BuildI2Cmessage() {
      //memset (i2cslavemsg, 0, I2CMSGSIZE);
      for (int i=0; i<I2CMSGSIZE; ++i)  i2cslavemsg[i] = i+1 ;
      
    }



//************************************************************************************
// main loop()
//************************************************************************************

    void loop()
    {

       // build I²C message to the master out of digital and analog values repeatedly
       if (__mainloopcnt__ % 2 == 0) {
          BuildI2Cmessage();                            // priority = 1/2
       }


       if (__mainloopcnt__ >=MAXMAINCOUNTER) {           // priority = 1/12
           __mainloopcnt__=0;                            // reset loop counter
       }

       delay(5);
    }

I guess I'm getting a little closer to the reason....:

http://botbench.com/blog/2009/08/04/connecting-the-nxt-to-an-arduinomega/

unfortunately I don't understand WHICH resistors WHERE exactly are meant, and the fotos are broken! :(

ps, as it turned out, it's a hardware failure, not a programming issue - @moderators: -> shift to another forum?

but I also tried resistors of 47k, 22k, 8.2k, 4.7k .

In case of resistors <= 22k there is no i2c connection at all, >=47k is fine for both Mega and Uno.

That seems bizarre, since most people report using resistors between 2.2k and 10k, and 4.7k seems to be the most commonly reported value.

In fact, since you report getting successful results with such weak pull-up resistors, that seems to me to be all the more reason why there is in fact multiple pull-ups in your arrangement, some of which you might not be aware of.

is there anyone who has an idea how to remove the internal i2c pullups ? will there be additional issues if they once have been removed?

or can the pin 20/21 i2c pullups be disabled by software configuration?

/* 
 * Function twi_init
 * Desc     readys twi pins and sets twi bitrate
 * Input    none
 * Output   none
 */
void twi_init(void)
{
  // initialize state
  twi_state = TWI_READY;
  twi_sendStop = true;     // default value
  twi_inRepStart = false;
  
  // activate internal pullups for twi.
  //digitalWrite(SDA, 1);
  //digitalWrite(SCL, 1);

In arduino/libraries/wire/utility is a file called twi.c and the last two lines in the excerpt posted here are commented out to prevent the activation of the internal pullups for twi ( which is an alternate name for I2C apparently )

I have no directory c:\Programme\arduino/libraries/wire/...

edit: ok, found one in C:\Programme\Arduino\hardware\arduino\avr\libraries\Wire\utility

indeed, they had not been outcommented, so they were apparently activated.

edit:

YES ! Now it works! THANKS! :grin: :grin: :grin: :grin:

Hi Helmut

With the internal pullup resistors disabled, there are still discrete 10K pullup resistors on the Mega 2560 board. But it sounds like leaving them in circuit is not causing you a problem.

If you ever need to remove them to use higher value external ones instead, they are in the small black package highlighted in this picture of part of the PCB. Only two of the four resistors in the package are used.

Regards

Ray

resistor network.jpg

hi,
this black package is made for micro-scanning-electron-microscope-manipulation-surgery, right? :sunglasses:

no, just kidding.

Thanks a lot for your input … and I hope I’d never need to do this, though :grin: