(solved) error when trying to use I2C

User avatar
fly135
Posts: 606
Joined: Wed Jan 03, 2018 8:33 pm
Location: Orlando, FL

Re: error when trying to use I2C

Postby fly135 » Tue Nov 06, 2018 6:22 pm

mzimmers wrote:Well, my HW guys have checked out the board and say it looks OK, so I'm inclined to think I'm doing something wrong.

Here's a code snippet of my attempt to implement the protocol described in the drawing in my above post.

Code: Select all

    m_i2c_cmd = i2c_cmd_link_create();
    ESP_ERROR_CHECK(i2c_master_start(m_i2c_cmd));
    ESP_ERROR_CHECK(i2c_master_write_byte(m_i2c_cmd, (uint8_t) ((devAddr) | I2C_MASTER_READ), true));
    ESP_ERROR_CHECK(i2c_master_write_byte(m_i2c_cmd, (uint8_t) regAddr, true));
    ESP_ERROR_CHECK(i2c_master_read(m_i2c_cmd, data, 2, I2C_MASTER_LAST_NACK))
    ESP_ERROR_CHECK(i2c_master_stop(m_i2c_cmd));
    err = (i2c_master_cmd_begin(I2C_PORT_NBR, m_i2c_cmd, 100));
Does anything jump out at you as wrong here?

Thanks.
i2c_master_write_byte(m_i2c_cmd, (uint8_t) ((devAddr << 1) | I2C_MASTER_READ), true)

User avatar
mzimmers
Posts: 643
Joined: Wed Mar 07, 2018 11:54 pm
Location: USA

Re: error when trying to use I2C

Postby mzimmers » Tue Nov 06, 2018 6:53 pm

Hi Fly -

It took me some time to figure out the Maxim datasheet, but I believe that their addresses are "pre-shifted."

Slave Addresses
Charger: 0xD2/D3h
Clogic, GTEST and Safeout LDOs: 0xCCh/0xCDh
Fuel Gauge: 0x6C/0x6D. See the Fuel Gauge I2C Protocol for details in the Fuel Gauge section.


I believe that, in the example of the fuel gauge, the address is really 0x6c >> 1. When you want to write, you use 0x6c; when you want to read, you use 0x6d (I hope that made sense).

I've managed to get this much working (and by "working" I mean not producing a timeout error):

Code: Select all

esp_err_t PowerMgr::i2cRead(uint8_t devAddr, uint8_t regAddr, uint8_t *data)
{
    esp_err_t err;
    uint8_t addrRead, addrWrite;
    // note about data (address) field: the ESP32 docs say to shift addresses one bit to the left,
    // but it appears that the addresses supplied in the MAX77818 data sheet already have been shifted.
    // keep this in mind when setting addresses from the datasheet.

    addrRead = static_cast<uint8_t>(((devAddr) | I2C_MASTER_READ));
    addrWrite = static_cast<uint8_t>(((devAddr) | I2C_MASTER_WRITE));

    m_i2c_cmd = i2c_cmd_link_create();
    ESP_ERROR_CHECK(i2c_master_start(m_i2c_cmd));
    ESP_ERROR_CHECK(i2c_master_write_byte(m_i2c_cmd, addrWrite, true));
    ESP_ERROR_CHECK(i2c_master_write_byte(m_i2c_cmd, regAddr, true));
    //ESP_ERROR_CHECK(i2c_master_read(m_i2c_cmd, data, 1, I2C_MASTER_LAST_NACK))
    ESP_ERROR_CHECK(i2c_master_stop(m_i2c_cmd));
    err = (i2c_master_cmd_begin(I2C_PORT_NBR, m_i2c_cmd, 100));
    if (err == ESP_OK)
    {
        ESP_LOGI(TAG, "i2cRead(): i2c_master_cmd_begin() successful.");
    }
    else
    {
        ESP_LOGE(TAG, "i2cRead(): error %x on i2c_master_cmd_begin.", err);
    }
    i2c_cmd_link_delete(m_i2c_cmd);

    return err;
}
If I uncomment the i2c_master_read line, then I get a time out. I'm sure it's my doing; I'm still trying to understand the protocol of the Maxim device. I am curious, though, how I'm supposed to introduce the read address into my code.

User avatar
mzimmers
Posts: 643
Joined: Wed Mar 07, 2018 11:54 pm
Location: USA

Re: error when trying to use I2C

Postby mzimmers » Tue Nov 06, 2018 7:13 pm

I think I'm slowly getting to the bottom of this...this code works:

Code: Select all

    addrRead = static_cast<uint8_t>(((devAddr) | I2C_MASTER_READ));
    addrWrite = static_cast<uint8_t>(((devAddr) | I2C_MASTER_WRITE));

    m_i2c_cmd = i2c_cmd_link_create();
    ESP_ERROR_CHECK(i2c_master_start(m_i2c_cmd));
    ESP_ERROR_CHECK(i2c_master_write_byte(m_i2c_cmd, addrWrite, true));
    ESP_ERROR_CHECK(i2c_master_write_byte(m_i2c_cmd, regAddr, true));
    ESP_ERROR_CHECK(i2c_master_start(m_i2c_cmd));
    ESP_ERROR_CHECK(i2c_master_write_byte(m_i2c_cmd, addrRead, true));
    ESP_ERROR_CHECK(i2c_master_read(m_i2c_cmd, data, 1, I2C_MASTER_LAST_NACK))
    ESP_ERROR_CHECK(i2c_master_stop(m_i2c_cmd));
    err = (i2c_master_cmd_begin(I2C_PORT_NBR, m_i2c_cmd, 100));
I think this is observing the protocol in the diagram...notice the extra i2c_master_start() call in the middle of the sequence. Seems weird, but at least it returns without error.

Now...to see if I can actually read the registers...

mikemoy
Posts: 626
Joined: Fri Jan 12, 2018 9:10 pm

Re: error when trying to use I2C

Postby mikemoy » Tue Nov 06, 2018 8:32 pm

Here is how I read a byte, and later how i read a word.

Code: Select all

esp_err_t readByte(uint8_t icAddress, uint8_t registerAddress, uint8_t *data)
{
	esp_err_t espRc;

	i2c_cmd_handle_t cmd = i2c_cmd_link_create();

	i2c_master_start(cmd);
	i2c_master_write_byte(cmd, icAddress << 1 | WRITE_BIT, ACK_CHECK_EN);
	i2c_master_write_byte(cmd, registerAddress, ACK_CHECK_EN);

	// Setup the read
	i2c_master_start(cmd);
	i2c_master_write_byte(cmd, icAddress << 1 | READ_BIT, ACK_CHECK_EN);
	i2c_master_read_byte(cmd, data, NACK_VAL);
	i2c_master_stop(cmd);

	// Shoot it out
	espRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);
	i2c_cmd_link_delete(cmd);

	return espRc;
}

Read Word

Code: Select all

esp_err_t readWord(uint8_t icAddress, uint8_t registerAddress, uint16_t *data)
{
	esp_err_t espRc;
	uint8_t msb, lsb;

	i2c_cmd_handle_t cmd = i2c_cmd_link_create();

	i2c_master_start(cmd);
	i2c_master_write_byte(cmd, icAddress << 1 | WRITE_BIT, ACK_CHECK_EN);
	i2c_master_write_byte(cmd, registerAddress, ACK_CHECK_EN);

	// Setup the read
	i2c_master_start(cmd);
	i2c_master_write_byte(cmd, icAddress << 1 | READ_BIT, ACK_CHECK_EN);
	i2c_master_read_byte(cmd, &msb, ACK_VAL);
	i2c_master_read_byte(cmd, &lsb, NACK_VAL);
	i2c_master_stop(cmd);

	// Shoot it out
	espRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);
	i2c_cmd_link_delete(cmd);

	 *data = (uint16_t)( (msb << 8) | lsb );

	return espRc;
}

User avatar
mzimmers
Posts: 643
Joined: Wed Mar 07, 2018 11:54 pm
Location: USA

Re: error when trying to use I2C

Postby mzimmers » Tue Nov 06, 2018 8:45 pm

Interesting...your read protocol includes that master_start in the middle of the message, too. Maybe that's not as unusual as I thought. Of course, my memory is probably somewhat faded; the last time I did any I2C stuff, Bush was president...

I'm still not sure I trust the readings I'm getting, but more experimentation will tell.

mikemoy
Posts: 626
Joined: Fri Jan 12, 2018 9:10 pm

Re: error when trying to use I2C

Postby mikemoy » Tue Nov 06, 2018 8:53 pm

ya... when it comes to reading you first write to the chip basically telling it Hey, i want to read from this register next, then you issue the restart, because if you'd issue a stop, you would have effectively told the chip were done, which we are not yet. After the restart, then you issue the read I.E. "READ_BIT" . then when your done you issue the stop to complete the process.

User avatar
fly135
Posts: 606
Joined: Wed Jan 03, 2018 8:33 pm
Location: Orlando, FL

Re: error when trying to use I2C

Postby fly135 » Tue Nov 06, 2018 9:48 pm

mzimmers wrote:Interesting...your read protocol includes that master_start in the middle of the message, too. Maybe that's not as unusual as I thought. Of course, my memory is probably somewhat faded; the last time I did any I2C stuff, Bush was president...

I'm still not sure I trust the readings I'm getting, but more experimentation will tell.
I had to look into this some more. I'm using some wrapper code that another consultant wrote for the company before I signed on. I also looked at the IDF docs. I noticed that the IDF docs example for a read doesn't set the sub-address, and doesn't have the two starts.

https://docs.espressif.com/projects/esp ... e4ce9f.png

You have the two starts and my wrapper code has it as well because you are programming the sub-address before the read.

John

User avatar
mzimmers
Posts: 643
Joined: Wed Mar 07, 2018 11:54 pm
Location: USA

Re: error when trying to use I2C

Postby mzimmers » Tue Nov 06, 2018 9:53 pm

Hi John - yeah, that made it a bit of a challenge to map the ESP calls to the Maxim device protocol. Fortunately, staring at the Maxim drawing long enough eventually got it to sink in. What you're referring to as sub-addresses are called "registers" in the Maxim data sheet. Not all I2C devices have multiple registers, I guess, and the example in the ESP docs is a rather simple one.

User avatar
fly135
Posts: 606
Joined: Wed Jan 03, 2018 8:33 pm
Location: Orlando, FL

Re: error when trying to use I2C

Postby fly135 » Tue Nov 06, 2018 10:01 pm

mzimmers wrote:Hi John - yeah, that made it a bit of a challenge to map the ESP calls to the Maxim device protocol. Fortunately, staring at the Maxim drawing long enough eventually got it to sink in. What you're referring to as sub-addresses are called "registers" in the Maxim data sheet. Not all I2C devices have multiple registers, I guess, and the example in the ESP docs is a rather simple one.
Seems like every I2C chip I've used had registers. The docs probably would be more helpful if the example had them as well.

John A

User avatar
mzimmers
Posts: 643
Joined: Wed Mar 07, 2018 11:54 pm
Location: USA

Re: (solved) error when trying to use I2C

Postby mzimmers » Tue Dec 18, 2018 4:30 pm

Well, I'm seeing problems with my I2C again. This might be due to hardware changes, but I thought I'd post here to see if anyone had an idea on what might be going on.

My call to i2c_master_cmd_begin() is returning ESP_ERR_TIMEOUT. There are 3 instances of this return code in the routine, but I traced my occurrence to here (beginning at line 1271 in 3.1.1):

Code: Select all

        portBASE_TYPE evt_res = xQueueReceive(p_i2c->cmd_evt_queue, &evt, wait_time);
        if (evt_res == pdTRUE) {
            if (evt.type == I2C_CMD_EVT_DONE) {
                if (p_i2c->status == I2C_STATUS_TIMEOUT) {
                    // If the I2C slave are powered off or the SDA/SCL are connected to ground, for example,
                    // I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case.
                    i2c_hw_fsm_reset(i2c_num);
                    clear_bus_cnt = 0;
		    ret = ESP_ERR_TIMEOUT;
I should point out that my calls return (almost) immediately, even though I specify a relatively long wait time. Again, it's very possible that this is due to a hardware error of some kind, but based on what I've posted, does anyone have an idea what might be happening?

Thanks...

Who is online

Users browsing this forum: No registered users and 90 guests