i2c read three segments error

sarah.frei
Posts: 2
Joined: Mon Jul 29, 2019 11:24 am

i2c read three segments error

Postby sarah.frei » Mon Jul 29, 2019 4:10 pm

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 5994 times
start.JPG
start.JPG (21.29 KiB) Viewed 5994 times
end.JPG
end.JPG (23.81 KiB) Viewed 5994 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

ESP_houwenxiang
Posts: 118
Joined: Tue Jun 26, 2018 3:09 am

Re: i2c read three segments error

Postby ESP_houwenxiang » 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
wookooho

sarah.frei
Posts: 2
Joined: Mon Jul 29, 2019 11:24 am

Re: i2c read three segments error

Postby sarah.frei » Wed Jul 31, 2019 10:56 am

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;

mohamed.raad
Posts: 2
Joined: Wed Jul 31, 2019 11:57 am

Re: i2c read three segments error

Postby mohamed.raad » Wed Jul 31, 2019 12:01 pm

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.

mohamed.raad
Posts: 2
Joined: Wed Jul 31, 2019 11:57 am

Re: i2c read three segments error

Postby mohamed.raad » Wed Jul 31, 2019 12:06 pm

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.

ESP_houwenxiang
Posts: 118
Joined: Tue Jun 26, 2018 3:09 am

Re: i2c read three segments error

Postby ESP_houwenxiang » Thu Aug 01, 2019 4:21 am

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.
wookooho

Who is online

Users browsing this forum: No registered users and 119 guests