espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.61k stars 7.41k forks source link

I2C Module CLK never initialized #9282

Open drschlaumeier opened 8 months ago

drschlaumeier commented 8 months ago

Board

ESP32, M5Stack, M5Stick etc.

Device Description

ESP32 Dev Module, M5STACK Core, M5Stick C and other

Hardware Configuration

I2C0 Slave Mode, SDA=GIO21, SCL=GPIO22

Version

v2.0.14

IDE Name

Arduino IDE or vMicro

Operating System

Windows10

Flash frequency

80Mhz

PSRAM enabled

yes

Upload speed

115200 - 921600

Description

Already back 2019 I have developed a working I2C slave implementation where master can read/write to address memory. BTW, this is still not working in Espressif IDE examples or Arduino Wire examples. It always sends garbage back to I2C Master because TX FIFO Empty & ACK/NACK not working. Anyhow, from time to time I'm updating to newest Arduino ESP32 when I need to make small changes in the code. In my I2C slave implementation I have own, e.g.:

But since updating to 2.0.14 (cant remember which version I had before), my I2C Slave implementation did not work any more. It was working somehow but somehow not. It took me over one week with different debugging tests until individual registers and interrupts until I figured out the problem and I think thats a general problem in Arduino ESP32 I2C implementation:

YOU MISS TO ENABLE THE I2C MODULE CLK !

I just added this two lines into my i2c_param_config code and all was working as before: DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT0_RST);

Interestingly, the I2C module is also working without the module CLK enables. I receive some data from I2C master and some parts of the code are working but other parts not. The problem is that without the module CLK, you cannot modify any registers defined in i2c_dev_t....and it obviously uses somehow the default values. It also gives no error messages from Espressif IDE.

I also checked the Arduino ESP32 Git code if I find some references to module CLK enable. I only found for SPI...here: https://github.com/espressif/arduino-esp32/blob/113de1fa02b3665a9755e09fb189304f0eb3ac7b/cores/esp32/esp32-hal-spi.c#L655

BR

Sketch

static DRAM_ATTR i2c_dev_t* const I2C_DEV[I2C_NUM_MAX] = { &I2C0, &I2C1 };

esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf)
{
...
    I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);

    //needed to add this two lines to enable e.g. I2C0 module
    DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN);
    DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT0_RST);

...
    if (i2c_conf->mode == I2C_MODE_SLAVE) {
      ...
      I2C_DEV[i2c_num]->sda_hold.time = I2C_SLAVE_SDA_HOLD_DEFAULT;
      I2C_DEV[i2c_num]->sda_sample.time = I2C_SLAVE_SDA_SAMPLE_DEFAULT;

    }

    I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
    return ESP_OK;
}

Debug Message

no debug message available

Other Steps to Reproduce

Try using Espressif IDE code and modify registers with i2c_dev_t struct, e.g. sda_hold.time or sda_sample.time Reread the registers and you will see that nothing changed!

I have checked existing issues, online documentation and the Troubleshooting Guide

me-no-dev commented 8 months ago

Did you use Arduino's I2C Slave or IDF's API?

drschlaumeier commented 8 months ago

I'm using Arduino-ESP32 2.0.14. What you mean with Arduinos I2C slave? There is no in 2.0.14. I only found esp32-hal-i2c-slave.h ? There are some slave examples in the internet using IDf and also some with wire.h. But that's never working. I explained above because handling of TX FIFO empty and ACK/NACK is not implemented correctly..neither in Arduino nor in Espressif IDF. So, I had to implement my own initialization and I2C ISR handler. Using current, not working, Arduino/IDF implementation, you need to know in advance which address master wants to read and prefill TX Fifo ... buts thats implossible. e.g. That part of my code of I2C ISR handler is crucial that master can correctly read from slave address.

      ....
        } else if (status & I2C_TXFIFO_EMPTY_INT_ST_M) {
            p_i2c->addrrcv = 0;
            if (p_i2c->mode == I2C_MODE_SLAVE) {
                // ** data requested by master
                // push data byte from slave buffer at current address to tx fifo
                uint16_t addr = p_i2c->slave_state.txaddr + p_i2c->slave_state.txptr;
                if (addr < p_i2c->bufflen) {
                    WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), p_i2c->slave_buffer[addr]);
                    p_i2c->slave_state.txptr++;
                }
                else {
                    // address outside buffer, push dummy byte
                    WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), 0xFE);
                    p_i2c->slave_state.txovf++;
                }
             }
            I2C_DEV[i2c_num]->int_ena.tx_fifo_empty = 1;
            I2C_DEV[i2c_num]->int_clr.tx_fifo_empty = 1;
       }
.....

Anyhow, thats not the topic. I just wanted make you aware that you not initialize the I2C module clock in Arduino-esp32. I think thats a mistake and makes problems for all I2C implementations...doesn't matter if Arduino or IDF