Programm-Upgrade Uno -> Mega; hier: i2c Probleme

hallo,
bei meinem Programm-Upgrade Uno → Mega habe ich jetzt plötzlich i2c Probleme - vorher auf dem Uno hat es geklappt (ana4+5)

Jetzt verwende ich pins 20+21 auf dem Mega.

die i2c Verbindung wird hergestellt, wenn ich probeweise unterbreche (SDA rausziehen o.ä.) merkt der Master das und piept.
Ansonsten zeigt er die bestehende Verbindung zum Arduino-Slave an, aber er bekommt keine vernünftigen Daten mehr.

Muss ich bei der Umstellung ana 4+5 auf dig 20+21 noch was anderes beachten? Interrupts oder pwm-pins?
Kann ich die i2c-Geschwindigkeit manuell einstellen auf 9600 Hz?

dies ist das Programm mit dem Pin-Setup:

passt wieder nicht rein wegen 9500 Zeichen -Begrenzung !!
- kann das nicht mal jemand BITTE! BITTE!! BITTE!!! auf 64 k erhöhen ?!?!?

muxer1101.ino (23 KB)

HaWe:
Kann ich die i2c-Geschwindigkeit manuell einstellen auf 9600 Hz?

hmm - danke, aber das verstehe ich nicht, ist etwas zu kompliziert.

Gibt's nicht so was wie "i2c.begin(Hz)" ? So wie bei Serial.begin(Hz) ?

ps - hat das überhaupt beim Arduino als Slave einen Sinn?

Wenn du das schreibst, dann gibt es das danach :stuck_out_tongue:

Hier ist eine Code Zeile, die den Prescaler noch nicht berücksichtigt:

TWBR = (F_CPU/ frequency - 16)/2;

Solange das Ergebnis davon in ein 8 Bit Register passt, reicht das. Für frequency = 9600 käme da 825 raus. Also erst mal schlecht.

Aber dann kann man noch den Prescaler auf 4 setzen. Also:

TWSR |= _BV (TWPS0);

Dann passt es da (16.000.000 / 9600 - 16) / 2 / 4 = 206

hat das überhaupt beim Arduino als Slave einen Sinn?

Nein. Der Takt wird vom Master vorgegeben

ich komm nicht weiter - woran kann es liegen?
Uno: SDA ana4, SCL ana5
Mega: SDA dig20, SCL dig21

wenn ich vom Uno aus einen test-Array[14] schicke (Werte 0..13 entsprechnd dem Index),
dann wird auf dem Master-Programm jeder einzelne Wert korrekt empfangen + angezeigt

Auf dem Mega aber (selbes Programm!) wird zwar i2c verbunden, aber er zeigt nur Werte von 255 oder (teilw) 0.

Was läuft da schief?
Können die pins 20+21 kaputt sein? Könnte man das testen?
Muss man auf dem Mega i2c irgendwie was vorher konfigurieren?
Gibt es noch einen anderen i2c Port für den Slave Betrieb?
Kann es an pwm/Timer-Konflikten o.ä. liegen?

Tippe auf Timerkonflikt! Da gibt es eine effizente Möglichkeit. Code komplett entschlagen oder neuanlegen mit lediglich dieser Funktion.

mit welchen Timern /Interrupts arbeitet denn i2c?

Ich arbeite momentan nur mit Timer 5 (pins 44-46), vorgesehen sind noch Timer 0 (pins 4, 13) und Timer 4 (pin 6)- aber noch nicht in Gebrauch.

Ich bekam aber auch mit Minimal-Code keine Verbindung.

Hab auf die schnelle nichts gefunden, welcher TIMER evtl. gebraucht wird. Aber was ist, wenn du das Programm nur auf I2C begrenzt?

habe ich - kommt nichts außer 0 und 255.

I2C arbeitet nicht mit einem Timer. Das hat einen eigenen Interrupt Vektor

Und wenn man sich mal twi.c ansieht:

ISR(TWI_vect)
{
     //viele, viele Abfragen hier je nach Zustand des Busses
}

was bedeutet das?
was soll ich machen?
Kann ich was testen, um den Fehler einzugrenzen?

hier ist der Minimalcode:
Uno alles ok, Anzeige auf dem Master 0…13
Mega: Anzeige 0, und dann Rest alles nur noch 255

//***********************************************************************************
// 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 ;
      
    }



//************************************************************************************
// 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);
    }

Sowas ist meistens Pfusch:

    void receiveEvent(int byteCount){

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

    }

Das triggert nach dem ersten Byte und die anderen Bytes sind eventuell noch unterwegs. Du musst entweder warten bis alle Bytes die du erwartest wirklich da sind und erst dann auslesen. Oder du setzt i nicht jedesmal zurück, sondern lässt den Event Handler wiederholt triggern und setzt die Zählvariable erst am Ende zurück.

kA wieso es auf dem UNO geht, aber der Code ist nicht sauber.

255 ist -1 und heißt das keine Daten gelesen wurden!

aha, ok, und wie macht man es sauber?

Wenn du weißt dass du 14 Bytes erwartest:

if(Wire.available() >= 14)
{
    for(int i = 0; i < 14; i++)
       i2cmastermsg[i] = Wire.read();
}

Oder sowas vielleicht:

boolean dataReceived;

void receiveEvent(int byteCount)
{
        static byte i;
       
        while( Wire.available() ) 
          i2cmastermsg[i++] = Wire.read();

        if(i == 14)       //geht dann glaube ich von 0-13
        {
           i = 0;
           dataReceived = true;
        }
    }
}
// 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)
.
.
.

Meiner Meinung nach fehlt da das Komma. 4,7K wäre ein gängiger Wert für den PullUp. Ich hatte es schon, das ich mit 10K am UNO nur Müll hatte. Bis 2,2K kannst du problemlos runter gehen.

Gruß Gerald

nein, das sind die Pullups für den NXT, das stimmt schon so.
Der NXT braucht immer mindestens 40k Pullups.
Die Pullups gehen ja auch auf NXT+Vc - alles schon ganz am Anfang ausgetestet!

Klappt ja auch mit dem Uno.

(edit - kann's ja nochmal testen, denn es waren ja erst analog pins, jetzt ist es digital)

@Serenify:
der 2. Code bringt auch nur 1x 0 und dann nur noch 255.

der 1. auch.

Das ist nur 255 weil du es in eine signed Variable schreibst. Eigentlich liefert read() -1, und das bedeutet dass keine Daten da sind:

Returns
the first byte of incoming serial data available (or -1 if no data is available) - int

Hätte aber gedacht, dass es an dem zu Schnellen Auslesen lag :~