I2C Communication Error with ESP32 (using camera module)

Hello everyone. I'm currently developing a project where I need to extract data from a camera and a sensor simultaneously, and I'm getting an I2C communication error when I try to do so.

My board is a DFRobot Firebeetle 2 ESP32-S3 v1.0, which supports a camera module. My sensor is a MPU6500.

I created this short snippet of code just to test the communication between both sensors.

#include "esp_camera.h"
#include <Wire.h> 
#include "DFRobot_AXP313A.h" // Necessary due to v1.0 board

// ESP32 FireBeetle 2 pins
#define PWDN_GPIO_NUM  -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM  45
#define SIOD_GPIO_NUM  1  // I've also tried changing these two pins but it just gives errors
#define SIOC_GPIO_NUM  2  // (comment above)
#define Y9_GPIO_NUM    48
#define Y8_GPIO_NUM    46
#define Y7_GPIO_NUM    8
#define Y6_GPIO_NUM    7
#define Y5_GPIO_NUM    4
#define Y4_GPIO_NUM    41
#define Y3_GPIO_NUM    40
#define Y2_GPIO_NUM    39
#define VSYNC_GPIO_NUM 6
#define HREF_GPIO_NUM  42
#define PCLK_GPIO_NUM  5

#define SDA_PIN 18   // board SDA pin
#define SCL_PIN 9    // board SCL pin

#define MPU_ADDRESS 0x69

DFRobot_AXP313A axp;             // I got this part of the code from DFRobot Wiki
TwoWire myI2C = TwoWire(1); // Creates another I2C BUS

bool cam;

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.println("System Starting...");

  setupCamera();
  delay(500);

  //myI2C.begin();
  myI2C.begin(SDA_PIN, SCL_PIN);
  myI2C.setClock(400000);
  delay(500);
}

void loop() {
  uint8_t who_am_i = readWhoAmI();
  Serial.print("WHO_AM_I Register Value: 0x");
  Serial.print(who_am_i, HEX);
  Serial.print(" | cam: ");
  Serial.println(cam);
  delay(5e3);
}


void setupCamera() {
  // ------------ v1.0 code ------------ //
  while(axp.begin() != 0){
    Serial.println("init error");
    delay(1000);
  }
  axp.enableCameraPower(axp.eOV2640);
  // ----------------------------------- //

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 40000000; // was 20000000
  config.pixel_format = PIXFORMAT_JPEG;

  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 12;
  config.fb_count = 1;
  config.frame_size = FRAMESIZE_QVGA;


  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    Serial.println();
    cam = false;
    return;
  } 
  else {
    cam = true;
  }

  if (psramFound()) {
    heap_caps_malloc_extmem_enable(20000);  
    //Serial.printf("PSRAM initialized. malloc to take memory from psram above this size");    
    //Serial.println();
  }  
}


uint8_t readWhoAmI() {
  myI2C.beginTransmission(MPU_ADDRESS);
  myI2C.write(0x75);
  myI2C.endTransmission(false);
  myI2C.requestFrom(MPU_ADDRESS, 1);

  return myI2C.read();
}

Two situations can happen when I run this code:

  1. If "setupCamera()" is commented, the camera does not work (variable camera in the code is false) and the sensor works. This is the output:
System Starting...
WHO_AM_I Register Value: 0x70 | cam: 0
  • I can access the sensor's registers, so the I2C communication with the sensor is fine.
  1. If "setupCamera()" is uncommented, the camera works fine but I can't communicate with the sensor via I2C. I always get this output:
System Starting...
E (803) i2c: i2c driver install error
WHO_AM_I Register Value: 0xFF | cam: 1
  • In this code there is no way to verify the camera video, but I've tested it with a different one and it works. The sensor, however, doesn't.
    The line "E (803) i2c: i2c driver install error" does not show up if I use "TwoWire myI2C = TwoWire(0);" instead of "TwoWire myI2C = TwoWire(1);".

In this version of the code I try to create another I2C BUS (with the TwoWire instance) for the communication with the sensor, to possibly avoid any conflicts between the camera and the MPU. However, I tried to start the I2C the normal way with 'Wire.begin()' and the results are the same. I've also tried a lot of different pins for the SDA and SCL, but the result is always the same.

I've tried doing the same in a different board, the ESP32-CAM, and everything worked fine. Both the video and sensor functioned simultaneously, so that makes me wonder if the problem is board-related.
Do you have any suggestions I can try?
Thank you all in advance!

I should also add the board settings I'm using.

Some notes:

  • USB CDC On Boot needs to be enabled, otherwise I can't upload any code
  • PSRAM needs to be OPI PSRAM or the camera won't work

I've also tried tweaking with a bunch of these, but I got no positive results.

If you prefer to initialize I2C by yourself, then set correspoinding camera config fields to -1 (i.e. clock and data fields in camera config), initialize your Wire instance and then call camera_init().

I tried to do it other way: let the camera to initialize SCCB (i.e. I2C) bus, but then instead of calling i2c.begin() i did i2cInit(...) with the same pin numbers I used in camera config. Doing it this way I was able to use both camera and my i2c device.

Anothehr thing you can try is to decrease I2C frequency to 100kHz.

Also, I suspect that your camera can't run at 40MHz

Thank you for your answer!
I tried both approaches you mentioned.


In the first approach, I changed the camera's data and clock to -1 (SIOD_GPIO_NUM = -1 and SIOC_GPIO_NUM = -1). Then I initialized the Wire instance and only after called setupCamera(). I got two different results from this (none of them positive), depending how I initialized the I2C communication.

  1. Case 1
  • I initialized the I2C the normal way, ie, Wire.begin(SDA_PIN, SCL_PIN);. This way, all I got was this:
System Starting...
init error
init error
init error
//... and so on
  1. Case 2
  • Initializing as I was doing previously, ie, myI2C.begin(SDA_PIN, SCL_PIN);, defining the TwoWire instance before, gave this output:
System Starting...
Camera init failed with error 0x102
WHO_AM_I Register Value: 0x70 | cam: 0
  • So a new error I haven't seen before appeared (Camera init failed with error 0x102).

In both cases, the camera doesn't seem to work.
Also, in Case 1, commenting the v1.0 board code (inside setupCamera) makes the output the same as Case 2.
As a side note, I also changed the I2C clock speed to 100kHz and the camera to 20MHz.


In the second approach I didn't quite get what you meant by i2cInit().
From what I got, I initialized the camera pins as normal, ie, with pins 1 and 2 in SIOD_GPIO_NUM and SIOC_GPIO_NUM, respectively. After that I initialized I2C with the same pins as the camera config (1 for SDA and 2 for SCL) and what I got was this:

System Starting...
WHO_AM_I Register Value: 0xFF | cam: 1

So, it is the same result as my first post mentioned.


Could you please clarify what you meant by i2cInit() ?
You said you got it to work. Did you use the same board as me? I also got this to work with a ESP32-CAM, but with this board specifically it is not working out.

Thank you again for your help!

Hello everyone.
After separately discussing with @vvb333007, we found a solution to this problem.

All I did was:

  1. Add this line at the beginning to the code: #include <esp32-hal-i2c.h>

  2. Initialize the camera's SCCB_DATA and SCCB_CLK pins as -1. This is done in the board's pin definition and should look like this:
    #define SIOD_GPIO_NUM -1
    #define SIOC_GPIO_NUM -1
    Alternatively, this can be changed directly in the setupCamera() function, but I'd do it here

  3. Add this line in the setupCamera() function: config.sccb_i2c_port = 0;
    In the end it should look something like this:

setupCamera() {
  ...

  config.sccb_i2c_port = 0;
  config.pin_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_scl = SIOC_GPIO_NUM;

 ...
}

After these steps the output showed this:

System Starting...
WHO_AM_I Register Value: 0x70 | cam: 1

which means everything is working fine. I was also able to test the camera and the sensor working as they were supposed to in my full code.


All credit of the discovery goes to @vvb333007, I'm just simply sharing our discussion.
I'll close the topic as solved now, but if anyone has a similar problem and this is not working I'm happy to help.
Cheers!