I2C problem between Uno and nano

hi, guys, hope you doing all well, so i m using an arduino Uno as a master and an arduino rp2040 connect as slave through i2c communication, my goal was to send a String to the nano and then he extract the informations needed and goes into AP mode, this work ( meaning when master tries to write on slave it works) but now if i try to read something from the slave ( like for exemple if the configuration is done or not, nothing is hapenning and the code is stock and does nt go further the command : "Wire.request", is it a problem of desychnronisation ? here s the master code :

Serial.println("je suis dans la configuration master");
      currentMillis=millis();
      //Configuration du point d'acces AP         
        Wire.beginTransmission(8);
        String config=(String(selectedMode)+","+String(currentMillis)+","+String(nom_wifi)+","+String(password_wifi)+","+String(canal_wifi_value));
        Wire.write(config.c_str()); // Example configuration message
        Wire.endTransmission();
        delay(500); // Give some time for the slave to process the configuration

      Serial.println("j ai envoyé le message de configurartion");
      Serial.println(isConfigDone);
      while(!isConfigDone) {
       // Request status from the slave
       Serial.println("je suis dans la boucle pour check la config");
       Wire.requestFrom(8, 1); // Request 1 byte from peripheral device #8
       Serial.println("j'entre dans la boucle");
       while (Wire.available()) {
            char c = Wire.read();
            if (c == 'S') {
              Serial.println("Configuration successful. Proceeding with data exchange.");
              isConfigDone=true;
            } else if (c == 'F') {
              Serial.println("Configuration not yet done. Waiting...");
            }
        }
      }
      isConfigDone=false;
      Serial.println("i m at the end of it ");

and here s the slave go :

void receiveEvent(int howMany) {
  if(howMany>2) {
    isConfigDone=false;
  }
  if (!isConfigDone) {
    // Read the configuration parameters sent by the master
    char config[howMany+1];
    for (int i = 0; i < howMany; i++) {
      config[i] = Wire.read();
    }
    config[howMany] = '\0'; // Null-terminate the string
    Serial.println(config);

     char* token = strtok(config, ",");
    if (token != NULL) {
      strcpy(mode, token); // Copy the first token to mode
      token = strtok(NULL, ",");
    }
    if (token != NULL) {
      currentMillis = strtoul(token, NULL, 10); // Convert the second token to an unsigned long
      token = strtok(NULL, ",");
    }
    if (token != NULL) {
      strcpy(nom_wifi, token); // Copy the third token to nom_wifi
      token = strtok(NULL, ",");
    }
    if (token != NULL) {
      strcpy(password_wifi, token); // Copy the fourth token to password_wifi
    }
    if (token != NULL) {
      strcpy(canal_wifi, token); // Copy the fourth token to password_wifi
    }
    Serial.println(currentMillis);


    if (strcmp(mode, "Mode 6 ") == 0) {
              // Ensure BLE module is not in use
                if(BLE.connected()) {
                  BLE.disconnect();
                  BLE.end();
                }
                  digitalWrite(LEDR, LOW);
                  digitalWrite(LEDB, HIGH);
                  digitalWrite(LEDG, LOW);
            while (WiFi.status() == WL_NO_MODULE) {
            delay(100);
            }
              while(status!=WL_AP_LISTENING) {
                       // initialiser le point d'accés
              status = WiFi.beginAP(nom_wifi, password_wifi, atoi(canal_wifi));
            }
           

           digitalWrite(LEDR, HIGH);
           digitalWrite(LEDB, LOW);
           digitalWrite(LEDG, LOW);

           isConfigDone = true;
            Serial.println(millis());
            configtime=millis()-currentMillis;
            Serial.println(configtime);
            Serial.println("Configuration done"); 
    
          }  
   }
}
void requestEvent() {
  Serial.println("je suis la ");
  if (isConfigDone) {     
              Wire.write("S"); // Respond with 'S' to indicate configuration is successful
          } else {
            Wire.write("F"); // Respond with 'F' to indicate configuration is not yet done
          }
}

i repeat, the slave execute all the on receive function nice and clean and goes into AP mode, but it never execute the on request function, any suggestion ?

Can you please stop with the I2C bus ? It is not going to work.

The I2C bus is not a bus where you can put data in at one end and it comes out at the other end. It is not that kind of bus.

If you want, then I can give a big list of things that are wrong, but in the end it still does not work.

If you can find an example or a tutorial that has I2C communication between a RP2040 and a ATmega328P, and both run Arduino, then I'm interested. If you can not find that, then forget about it.

If you are serious about a I2C Master - Slave configuration, then try it with two Arduino Uno R3 boards. But don't use it for a real project as a beginner.

[UPDATE] I was so terribly wrong with this post, see post #7 where I looked into the I2C mode for the RP2040.

thanks for your ideas, but i managed to make it work between EVB pico and rp 2040 connect and works smoothly, and now i m trying between uno and rp 2040 connect, there s no reason why it shouldn t work here, since it still worked with EVB pico. + i m telling you in this scenario the write operation works it s only the read that causes problem. don't worry i will send you a copy once i figure it out no need for tutorial.

it worked, for everyone who wonders why it did nt , i forgot this line in setup of slave :

Wire.onRequest(requestEvent);

Good to know :smiley:
A RP2040 with the Arduino layer on top of Mbed can be a I2C Slave ?
And now you have this working as well ? Well done, I was not expecting that :exploding_head: I apologize for my previous post.

I have a few tips:

The Arduino Uno R3 is a 5V board (with a 5V I2C bus) and the Pico board is a 3.3V board (with a 3.3V I2C bus). It is better to use a level shifter for the SDA and SCL.

We don't send a variable length text over I2C. The I2C bus works best with binary data of a fixed length.
The receiveEvent() on a Arduino Uno R3 runs inside a interrupt. It should be very short and fast. I don't know how it is for a RP2040. To be sure, I suggest to keep is very short and fast as well. Can you move all the BLE, Serial and WiFi functions to the loop().

Mbed is a real multitasking system. That means that it is not allowed to use strtok().

yes, thank you for advice, i did use a BSS138 level shifter, simple and support a bi directionnal connection for i2c

I looked into the I2C Slave mode of the RP2040. This is mostly for myself, but it might be useful for others as well:

The Mbed I2C Slave mode is well defined and working: https://os.mbed.com/docs/mbed-os/v6.16/apis/i2cslave.html

The Arduino mode translates the Mbed functions to the Arduino functions inclusive the Slave mode: https://github.com/arduino/ArduinoCore-mbed/blob/main/libraries/Wire/Wire.cpp#L142

The define to turn the I2C Slave mode on is here: https://github.com/arduino/ArduinoCore-mbed/blob/main/variants/RASPBERRY_PI_PICO/defines.txt#L9

The most interesting part is that a new thread is created with a callback to call the onRequest and onReceive handlers: https://github.com/arduino/ArduinoCore-mbed/blob/main/libraries/Wire/Wire.cpp#L40
That means that the onRequest and onReceive handlers are not running in a interrupt, but they run in their own thread. It is therefor allowed to use functions that take time.

That is very cool. The RP2040 is now the best chip to run as a I2C Slave :partying_face:

1 Like