I2C communication does not work with IDF but it does with Arduino

Good day esteemed.

Currently, I am attempting to set up a capacitive keyboard (Integrated CY8CMBR3116) with I2C communication to an ESP32-S3, which I am programming using IDF libraries through PlatformIO in Visual Studio Code. I am encountering an issue with I2C communication. I configure the I2C and send the write and read frames as indicated in the datasheet (see Figure 19, 20, and 21), but it never writes or allows me to read the registers of this controller (SEE CODE 1). On the other hand, I have code in Arduino (SEE CODE 2), which does work for me. I only did this to verify since I am currently programming everything on ESP32-S3 with IDF and would like to continue with it.

Could you assist me with “CODE 1” in case I have some error that I am not aware of that might affect the writing and reading of CY8CMBR3116 registers?

CODE1 (configurations):

#define I2C_MASTER_NUM          I2C_NUM_0
#define I2C_MASTER_SCL_IO       GPIO_NUM_19
#define I2C_MASTER_SDA_IO       GPIO_NUM_18
#define I2C_MASTER_FREQ_HZ      10000
#define CY8CMBR3116_ADDR        0x37
#define GPO_OUTPUT_STATE        0x80
#define SENSOR_EN               0x00
#define BUTTON_LBR              0x1F
#define SENSITIVITY0            0x08
#define SENSITIVITY1            0x09
#define SENSITIVITY2            0x0A
#define SENSITIVITY3            0x0B
#define BUTTON_STAT             0xAA
#define CTRL_CMD                0x86
#define SAVE_CHECK_CRC          0x02
#define SW_RESET                0xFF
#define DEVICE_ID               0x90
#define BUZZER_CFG              0x3E
#define SLIDER_CFG              0x5D
#define SPO_CFG                 0x4C
#define GPIO_INT_CY8CMBR3116    GPIO_NUM_41
#define GPIO_INT_CY8CMBR3116_MASK           (1ULL<<GPIO_NUM_41)
//Definicion de flag para las INT
#define ESP_INTR_FLAG_DEFAULT       0



*******************************WRITE*******************************
void configureCY8CMBR3116(void)
{
    // Configurar el CY8CMBR3116 para detectar teclas presionadas
    unsigned char configData[128] = {
    0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    0x00u, 0x00u, 0x00u, 0x00u, 0x80u, 0x80u, 0x80u, 0x80u,
    0x80u, 0x80u, 0x80u, 0x80u, 0x80u, 0x80u, 0x80u, 0x80u,
    0x80u, 0x80u, 0x80u, 0x80u, 0x03u, 0x00u, 0x00u, 0x00u,
    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x80u,
    0x05u, 0x00u, 0x00u, 0x02u, 0x00u, 0x02u, 0x00u, 0x00u,
    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x1Eu, 0x00u,
    0x00u, 0x1Eu, 0x1Eu, 0x00u, 0x00u, 0x00u, 0x01u, 0x01u,
    0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu,
    0xFFu, 0x00u, 0x00u, 0x00u, 0x14u, 0x03u, 0x01u, 0x58u,
    0x00u, 0x37u, 0x06u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u,
    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x88u, 0x95u
};
    esp_err_t ret=-1;
    i2c_cmd_handle_t cmd;

    while(ret==-1){

        ret=0;
            
        cmd = i2c_cmd_link_create();
        ret=i2c_master_start(cmd);
        ret=i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        //ret=i2c_master_write_byte(cmd, SENSOR_EN, true);
        //ret=i2c_master_write_byte(cmd, 0x00, true);
        //ret=i2c_master_stop(cmd);
        //ret=i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100 / portTICK_PERIOD_MS);
        //i2c_cmd_link_delete(cmd);



        //cmd = i2c_cmd_link_create();
        ret=i2c_master_start(cmd);
        ret=i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        ret=i2c_master_write_byte(cmd, SENSOR_EN, true);
        //ret=i2c_master_write_byte(cmd, 0x00, true);
        //ret=i2c_master_stop(cmd);
        //ret=i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
        //i2c_cmd_link_delete(cmd);



        //cmd = i2c_cmd_link_create();
        //ret=i2c_master_start(cmd);
        //ret=i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        //ret=i2c_master_write_byte(cmd, SENSOR_EN, true);
        ret=i2c_master_write(cmd, &configData[0], 31, true);
        //ret=i2c_master_stop(cmd);


        //ret=i2c_master_start(cmd);
        //ret=i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        //ret=i2c_master_write_byte(cmd, BUTTON_LBR, true);
        ret=i2c_master_write(cmd, &configData[31], 31, true);
        //ret=i2c_master_stop(cmd);


        //ret=i2c_master_start(cmd);
        //ret=i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        //ret=i2c_master_write_byte(cmd, BUZZER_CFG, true);
        ret=i2c_master_write(cmd, &configData[62], 31, true);
        //ret=i2c_master_stop(cmd);


        //ret=i2c_master_start(cmd);
        //ret=i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        //ret=i2c_master_write_byte(cmd, SLIDER_CFG, true);
        ret=i2c_master_write(cmd, &configData[93], 31, true);
        //ret=i2c_master_stop(cmd);



        //ret=i2c_master_start(cmd);
        //ret=i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        //ret=i2c_master_write_byte(cmd, 0x7C, true);
        ret=i2c_master_write(cmd, &configData[124], 4, true);
        ret=i2c_master_stop(cmd);
        //ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 100 / portTICK_PERIOD_MS);


        

        ret=i2c_master_start(cmd);
        ret=i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        ret=i2c_master_write_byte(cmd, CTRL_CMD, true);
        ret=i2c_master_write_byte(cmd,SAVE_CHECK_CRC, true);
        //ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 200 / portTICK_PERIOD_MS);
        //ret=i2c_master_stop(cmd);
        //ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 100 / portTICK_PERIOD_MS);


        vTaskDelay(200 / portTICK_PERIOD_MS);



        ret=i2c_master_start(cmd);
        ret=i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        ret=i2c_master_write_byte(cmd, CTRL_CMD, true);
        ret=i2c_master_write_byte(cmd,SW_RESET, true);
        //ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 200 / portTICK_PERIOD_MS);
        ret=i2c_master_stop(cmd);

        if(ret==ESP_OK){
            printf("Transmission SW_RESET CHECK OKEY");
        }

        //vTaskDelay(200 / portTICK_PERIOD_MS);
        
        i2c_cmd_link_delete(cmd);

        if(ret==-1){
            printf("ERROR CONFIG I2C\n");
        }
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }



    return;
}




*******************************READ*******************************
void readKeypadState(void *pvParameters)
{

    uint8_t rx_data[10];
    esp_err_t ret2=0;
    // uint8_t command[126] = {0x01};
    vTaskDelay(2000 / portTICK_PERIOD_MS);
    configureCY8CMBR3116();
    vTaskDelay(2000 / portTICK_PERIOD_MS); // Espera un segundo antes de enviar nuevamente
    i2c_cmd_handle_t cmd;


    while (1)
    {
/*
        cmd2 = i2c_cmd_link_create();
        ret2=i2c_master_start(cmd2);
        ret2=i2c_master_write_byte(cmd2, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        ret2=i2c_master_write_byte(cmd2, BUTTON_STAT, true); // Dirección del registro SENSITIVITY0
        ret2=i2c_master_stop(cmd2);
        
        ret2=i2c_master_read(cmd2, &rx_data[0], 2, true);

        i2c_cmd_link_delete(cmd2);


*/
        //Ubico el puntero en el registro BUTTON_STAT
        cmd = i2c_cmd_link_create();
        ret2=i2c_master_start(cmd);
        ret2=i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_WRITE, true);
        ret2=i2c_master_write_byte(cmd, BUTTON_STAT, true);  // Dirección del registro SENSOR_EN (cualquier registro de lectura servirá)
        ret2=i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (CY8CMBR3116_ADDR << 1) | I2C_MASTER_READ, true);
        i2c_master_read(cmd, rx_data, sizeof(rx_data), I2C_MASTER_ACK);
        i2c_master_stop(cmd);
        //i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
        i2c_cmd_link_delete(cmd);
        


        for(int j=0;j<10;j++)
            printf("ESTADO TECLADO%d: %u\n",j,rx_data[j]);

        if(ret2==-1){
            printf("ERROR READ I2C\n");
        }

        

        vTaskDelay(1000 / portTICK_PERIOD_MS); // Espera un segundo antes de enviar nuevamente
    }
    
}









*******************************PIN CONFIG*******************************
static esp_err_t i2c_master_init(void)
{
    i2c_config_t confi2c;
    confi2c.mode = I2C_MODE_MASTER;
    confi2c.sda_io_num = I2C_MASTER_SDA_IO;
    confi2c.scl_io_num = I2C_MASTER_SCL_IO;
    confi2c.sda_pullup_en = GPIO_PULLUP_ENABLE;
    confi2c.scl_pullup_en = GPIO_PULLUP_ENABLE;
    confi2c.master.clk_speed = I2C_MASTER_FREQ_HZ; // Velocidad del reloj I2C en Hz
    confi2c.clk_flags = 0;
    i2c_param_config(I2C_MASTER_NUM, &confi2c);
    i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER, 0, 0, 0);

    return ESP_OK;
}













void app_main()
{
    Init_Pulsador_OFF();
    i2c_master_init();

    // Inicializacion del Queue para las interrupciones
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));

    xTaskCreate(INTERRUPTION_TASK, "INTERRUPTION_TASK", 2048, NULL, 6, NULL);
    // Crea la tarea para leer el estado de las teclas capacitivas
    xTaskCreate(readKeypadState, "read_task", configMINIMAL_STACK_SIZE * 3, NULL, 7, NULL);
}

CODE 2:



#define SLAVE_ADDR  0x37
#define REGMAP_ORIGIN        0x00  
#define BUTTON_LBR          0x1F
#define BUZZER_CFG          0x3E
#define SLIDER_CFG          0x5D
#define CTRL_CMD            0x86
#define SAVE_CHECK_CRC          0x02
#define SW_RESET                0xFF

*******************************WRITE*******************************
void configCY8CMBR3102()
{
  int writeerr = 0;
  
  //Write dummy data
  Wire.beginTransmission(x); // transmit to device #0x37
  Wire.write(REGMAP_ORIGIN);          // sends Offset byte 
  Wire.write(00);
  Wire.endTransmission();    // stop transmitting
  
  Wire.beginTransmission(SLAVE_ADDR); // transmit to device #0x37
  Wire.write(REGMAP_ORIGIN);          // sends Offset byte 
  Wire.write(00);
  Wire.endTransmission();    // stop transmitting
  
  //Arduino function can send only 31 bytes of data
  //So whole frame is send in chunks
  //from [0] to [30]
  Wire.beginTransmission(SLAVE_ADDR); 
  Wire.write(REGMAP_ORIGIN);      //0     
  size_t sendedSize = Wire.write(&configData[0],31);        
  Wire.endTransmission();   
  
  writeerr = Wire.getWriteError();
  
  if(writeerr == 0) {
     Serial.print("First packet sended\n");
  }

  //from [31] to [61]
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write(BUTTON_LBR);         //31
  sendedSize = Wire.write(&configData[31],31);
  Wire.endTransmission(); 

  writeerr = Wire.getWriteError();
  
  if(writeerr == 0) {
     Serial.print("Second packet sended\n");
  }

  //from [62] to [92]
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write(BUZZER_CFG);          //62 
  sendedSize = Wire.write(&configData[62],31);
  Wire.endTransmission();

  writeerr = Wire.getWriteError();
  
  if(writeerr == 0) {
     Serial.print("Third packet sended\n");
  }

  //from [93] to [123]
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write(SLIDER_CFG);         //93
  sendedSize = Wire.write(&configData[93],31);
  Wire.endTransmission();

  writeerr = Wire.getWriteError();
  
  if(writeerr == 0) {
     Serial.print("Fourth packet sended\n");
  }

  //from [124] to [127]
  Wire.beginTransmission(SLAVE_ADDR); 
  Wire.write(0x7C);         //124
  sendedSize = Wire.write(&configData[124],4);        
  Wire.endTransmission();    

  writeerr = Wire.getWriteError();
  
  if(writeerr == 0) {
     Serial.print("Fifth packet sended\n");
  }

  /*
  Write 0x02 to 0x86 
  Info from datasheet
  The device calculates a CRC checksum over the configuration data in this register map and
  compares the result with the content of CONFIG_CRC. If the two values match, the device saves
  the configuration and the CRC checksum to nonvolatile memory.
  */
  Wire.beginTransmission(SLAVE_ADDR); // transmit to device #0x37
  Wire.write(CTRL_CMD);
  Wire.write(SAVE_CHECK_CRC);
  Wire.endTransmission();    // stop transmitting
  
  delay(200);

  //Reset
  Wire.beginTransmission(SLAVE_ADDR); 
  Wire.write(CTRL_CMD);
  Wire.write(SW_RESET);
  Wire.endTransmission();    // stop transmitting
  
  delay(200);
}








*******************************READ*******************************
void ReadAndDisplaySensorStatus()
{
  char readedData[2] = {0x00};

  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write(BUTTON_STATUS);        
  Wire.endTransmission();
  
  int i=0;


  Wire.requestFrom(SLAVE_ADDR, 2); //2 bytes for whole BUTTON_STATUS
  while(Wire.available())  
  { 
    readedData[i] = Wire.read();
    Serial.print("Hex: 0x"); 
    Serial.print(readedData[i], HEX); 
    Serial.print("\n"); 
    i++;
  }
  Wire.endTransmission();
      
  DisplaySensorStatus(&readedData[0]); 
  delay(1000);
  
}






void setup()
{
  Wire.begin(18,19);  
  Serial.begin(115200);  // start serial for output
  //For single chip is need to be call only once.
  //If do not change configuration 
  configCY8CMBR3102();
  Serial.print("Device configurated\n");
}

void loop()
{
   ReadAndDisplaySensorStatus();
  delay(50);
}

Do you have one of those cheap $10 logic analyzers? Hook it up to the I2C lines, capture the I2C traffic with each of the firmwares, compare the differences. If the sent and receive data match, you know the error is in the retrieval or interpretations of the result. If there’s a difference in sent data (and thus probably also received data), you will know exactly which transaction is wrong and can investigate there.

1 Like

Yes, that’s the next thing I’m going to try. However, I wanted to know if I have any conceptual errors in setting up the register write and read functions. Tanks