Page 1 of 1

i2c read three segments error

Posted: Mon Jul 29, 2019 4:10 pm
by sarah.frei
Hey,

I'm working on an ESP32-WROOM-32D, in which I have a bootloader.
in my bootloader, I do not use OS and I use an i2c.

the write on my i2c is not a problem, but I can not read in three segments.
the command for segments read are the following:
  • Segment0
    • RSTART
    • WRITE
    • READ
    • END
  • Segment1
    • READ
    • READ
    • END
  • Segment2
    • STOP

Here is the code for my reading:

Code: Select all

	    // Segment 0
            p_i2c->rx_cnt = cmd->byte_num > p_i2c->rx_fifo_remain ? p_i2c->rx_fifo_remain : cmd->byte_num;
            cmd->byte_num -= p_i2c->rx_cnt;
            clear_int_status(i2c_num);
            I2C[i2c_num]->command[g_cmd_index_use].byte_num = p_i2c->rx_cnt;
            I2C[i2c_num]->command[g_cmd_index_use].ack_val = cmd->ack_val;
            I2C[i2c_num]->command[g_cmd_index_use+1].val = 0;
            I2C[i2c_num]->command[g_cmd_index_use+1].op_code = I2C_CMD_END;
            ESP_LOGI(I2C_TAG, "I2C_STATUS_READ");
            p_i2c->status = I2C_STATUS_READ;

            ESP_LOGI(I2C_TAG, "begin static start transfert");
            I2C[i2c_num]->int_clr.end_detect = 1;
            I2C[i2c_num]->int_ena.end_detect = 1;
            I2C[i2c_num]->ctr.trans_start = 0;
            I2C[i2c_num]->ctr.trans_start = 1;

            ets_delay_us(10);
            clear_int_status(i2c_num);
            
            ESP_LOGI(I2C_TAG, "rx_cnt %d", p_i2c->rx_cnt);
            uint8_t readValue = 0;
            uint8_t readIndex = 0;
            while (p_i2c->rx_cnt-- > 0) {
                readValue = READ_PERI_REG(I2C_DATA_APB_REG(i2c_num));
                rx_data[readIndex] = readValue;
                readIndex++;
                ESP_LOGI(I2C_TAG, "-----------------read value %d----------------", readValue);
            }

            // Segment 1
            i2c_master_read(cmdlink, &rx_data[1], 2, 0x0);
            i2c_master_read_byte(cmdlink, &rx_data[3], 0x1);
            i2c_master_stop(cmdlink);

            cmd = &g_cmd_desc[g_cmd_index_use];
            ESP_LOGI(I2C_TAG, "g_cmd_index_use %d, g_cmd_index %d, op_code %d", g_cmd_index_use,  g_cmd_index, cmd->op_code );

            I2C[i2c_num]->command[g_cmd_index_use].val = 0;
            I2C[i2c_num]->command[g_cmd_index_use].ack_en = cmd->ack_en;
            I2C[i2c_num]->command[g_cmd_index_use].ack_exp = cmd->ack_exp;
            I2C[i2c_num]->command[g_cmd_index_use].ack_val = cmd->ack_val;
            I2C[i2c_num]->command[g_cmd_index_use].byte_num = cmd->byte_num;
            I2C[i2c_num]->command[g_cmd_index_use].op_code = cmd->op_code;

            p_i2c->rx_cnt = cmd->byte_num > p_i2c->rx_fifo_remain ? p_i2c->rx_fifo_remain : cmd->byte_num;
            cmd->byte_num -= p_i2c->rx_cnt;
            
            clear_int_status(i2c_num);
            I2C[i2c_num]->command[g_cmd_index_use].byte_num = p_i2c->rx_cnt;
            I2C[i2c_num]->command[g_cmd_index_use].ack_val = cmd->ack_val;
            I2C[i2c_num]->command[g_cmd_index_use+1].val = 0;
            I2C[i2c_num]->command[g_cmd_index_use+1].op_code = I2C_CMD_END;

            ESP_LOGI(I2C_TAG, "begin static start transfert");
            I2C[i2c_num]->int_ena.end_detect = 1;
            I2C[i2c_num]->ctr.trans_start = 0;
            I2C[i2c_num]->ctr.trans_start = 1;

            ets_delay_us(10);
            clear_int_status(i2c_num);

            ESP_LOGI(I2C_TAG, "rx_cnt %d", p_i2c->rx_cnt);
            readValue = 0;
            readIndex = 0;
            while (p_i2c->rx_cnt-- > 0) {
                readValue = READ_PERI_REG(I2C_DATA_APB_REG(i2c_num));
                rx_data[readIndex] = readValue;
                readIndex++;
                ESP_LOGI(I2C_TAG, "-----------------read value %d----------------", readValue);
            }
reading the first segment works, I read the expected value. but for the second, I never receive the I2c_END_DETECT_INT interrupt and it seems that the master sends a STOP when it should not.
general.JPG
general.JPG (27.87 KiB) Viewed 6250 times
start.JPG
start.JPG (21.29 KiB) Viewed 6250 times
end.JPG
end.JPG (23.81 KiB) Viewed 6250 times
After reading segment0, the sda line is not released, and the slave does not send the rest of the data.
what I need to add / correct for the reading to go right?
Thanks for help

Re: i2c read three segments error

Posted: Wed Jul 31, 2019 9:38 am
by ESP_houwenxiang
Hi, sarah.frei

Each hardware WRITE or READ command should be followed by an EDN command. So the reading code should be like this

RSTART
WRITE
END
READ
END
READ
END
READ
END (This END command can be omitted)
STOP

Re: i2c read three segments error

Posted: Wed Jul 31, 2019 10:56 am
by sarah.frei
ESP_houwenxiang wrote:
Wed Jul 31, 2019 9:38 am
Hi, sarah.frei

Each hardware WRITE or READ command should be followed by an EDN command. So the reading code should be like this

RSTART
WRITE
END
READ
END
READ
END
READ
END (This END command can be omitted)
STOP
Hello,
Thanks for reply,

indeed an END command is sent after each WRITE or READ command.
Before the transmission of the command (I2C[i2c_num]->ctr.trans_start = 1) the following code is used to add the command END:

Code: Select all

           
I2C[i2c_num]->command[g_cmd_index_use+1].val = 0;
I2C[i2c_num]->command[g_cmd_index_use+1].op_code = I2C_CMD_END;

Re: i2c read three segments error

Posted: Wed Jul 31, 2019 12:01 pm
by mohamed.raad
Hello ESP_houwenxiang

As you can see there is a END command after each Read command in segment 1. Please check the code.

Code: Select all

            // Segment 1
            i2c_master_read(cmdlink, &rx_data[1], 2, 0x0);
            i2c_master_read_byte(cmdlink, &rx_data[3], 0x1);
            i2c_master_stop(cmdlink);

            cmd = &g_cmd_desc[g_cmd_index_use];
            ESP_LOGI(I2C_TAG, "g_cmd_index_use %d, g_cmd_index %d, op_code %d", g_cmd_index_use,  g_cmd_index, cmd->op_code );

            I2C[i2c_num]->command[g_cmd_index_use].val = 0;
            I2C[i2c_num]->command[g_cmd_index_use].ack_en = cmd->ack_en;
            I2C[i2c_num]->command[g_cmd_index_use].ack_exp = cmd->ack_exp;
            I2C[i2c_num]->command[g_cmd_index_use].ack_val = cmd->ack_val;
            I2C[i2c_num]->command[g_cmd_index_use].byte_num = cmd->byte_num;
            I2C[i2c_num]->command[g_cmd_index_use].op_code = cmd->op_code;

            p_i2c->rx_cnt = cmd->byte_num > p_i2c->rx_fifo_remain ? p_i2c->rx_fifo_remain : cmd->byte_num;
            cmd->byte_num -= p_i2c->rx_cnt;
            
            clear_int_status(i2c_num);
            I2C[i2c_num]->command[g_cmd_index_use].byte_num = p_i2c->rx_cnt;
            I2C[i2c_num]->command[g_cmd_index_use].ack_val = cmd->ack_val;
            I2C[i2c_num]->command[g_cmd_index_use+1].val = 0;
            I2C[i2c_num]->command[g_cmd_index_use+1].op_code = I2C_CMD_END;

            ESP_LOGI(I2C_TAG, "begin static start transfert");
            I2C[i2c_num]->int_ena.end_detect = 1;
            I2C[i2c_num]->ctr.trans_start = 0;
            I2C[i2c_num]->ctr.trans_start = 1;

            ets_delay_us(10);
            clear_int_status(i2c_num);

            ESP_LOGI(I2C_TAG, "rx_cnt %d", p_i2c->rx_cnt);
            readValue = 0;
            readIndex = 0;
            while (p_i2c->rx_cnt-- > 0) {
                readValue = READ_PERI_REG(I2C_DATA_APB_REG(i2c_num));
                rx_data[readIndex] = readValue;
                readIndex++;
                ESP_LOGI(I2C_TAG, "-----------------read value %d----------------", readValue);
            }

As Sarah described, when the master read operation is ongoing the SDA line is held for some reason by ESP32 master.

Re: i2c read three segments error

Posted: Wed Jul 31, 2019 12:06 pm
by mohamed.raad
Hi ESP_houwenxiang,

As you can see in the code, in segment 1 there is always a END command after each read operation.

It is done through " I2C[i2c_num]->command[g_cmd_index_use+1].op_code = I2C_CMD_END; "

What we see is the SDA line behaves erratically during the 2nd read operation of the segment 1.

Re: i2c read three segments error

Posted: Thu Aug 01, 2019 4:21 am
by ESP_houwenxiang
Can you provide the debug log?

Code: Select all

ESP_LOGI(I2C_TAG, "g_cmd_index_use %d, g_cmd_index %d, op_code %d", g_cmd_index_use,  g_cmd_index, cmd->op_code );
When the EDN command is sent, we should fill in the next command from the first command register.