mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 04:04:31 +02:00
Merge branch 'bugfix/i2c_master_clear_bus' into 'master'
fix i2c_master_clear_bus && add i2c_tool example test See merge request idf/esp-idf!3509
This commit is contained in:
@@ -1009,6 +1009,12 @@ example_test_006_01:
|
|||||||
- ESP32
|
- ESP32
|
||||||
- Example_ShieldBox
|
- Example_ShieldBox
|
||||||
|
|
||||||
|
example_test_007_01:
|
||||||
|
<<: *example_test_template
|
||||||
|
tags:
|
||||||
|
- ESP32
|
||||||
|
- Example_I2C_CCS811_SENSOR
|
||||||
|
|
||||||
UT_001_01:
|
UT_001_01:
|
||||||
<<: *unit_test_template
|
<<: *unit_test_template
|
||||||
tags:
|
tags:
|
||||||
|
@@ -80,6 +80,8 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
|
|||||||
#define I2C_MASTER_TOUT_CNUM_DEFAULT (8) /* I2C master timeout cycle number of I2C clock, after which the timeout interrupt will be triggered */
|
#define I2C_MASTER_TOUT_CNUM_DEFAULT (8) /* I2C master timeout cycle number of I2C clock, after which the timeout interrupt will be triggered */
|
||||||
#define I2C_ACKERR_CNT_MAX (10)
|
#define I2C_ACKERR_CNT_MAX (10)
|
||||||
#define I2C_FILTER_CYC_NUM_DEF (7) /* The number of apb cycles filtered by default*/
|
#define I2C_FILTER_CYC_NUM_DEF (7) /* The number of apb cycles filtered by default*/
|
||||||
|
#define I2C_CLR_BUS_SCL_NUM (9)
|
||||||
|
#define I2C_CLR_BUS_HALF_PERIOD_US (5)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t byte_num; /*!< cmd byte number */
|
uint8_t byte_num; /*!< cmd byte number */
|
||||||
@@ -525,7 +527,9 @@ esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode,
|
|||||||
static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
|
static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
|
||||||
{
|
{
|
||||||
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||||
|
const int scl_half_period = I2C_CLR_BUS_HALF_PERIOD_US; // use standard 100kHz data rate
|
||||||
int sda_in_sig = 0, scl_in_sig = 0;
|
int sda_in_sig = 0, scl_in_sig = 0;
|
||||||
|
int i = 0;
|
||||||
if (i2c_num == I2C_NUM_0) {
|
if (i2c_num == I2C_NUM_0) {
|
||||||
sda_in_sig = I2CEXT0_SDA_IN_IDX;
|
sda_in_sig = I2CEXT0_SDA_IN_IDX;
|
||||||
scl_in_sig = I2CEXT0_SCL_IN_IDX;
|
scl_in_sig = I2CEXT0_SCL_IN_IDX;
|
||||||
@@ -536,19 +540,27 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
|
|||||||
int scl_io = GPIO.func_in_sel_cfg[scl_in_sig].func_sel;
|
int scl_io = GPIO.func_in_sel_cfg[scl_in_sig].func_sel;
|
||||||
int sda_io = GPIO.func_in_sel_cfg[sda_in_sig].func_sel;
|
int sda_io = GPIO.func_in_sel_cfg[sda_in_sig].func_sel;
|
||||||
I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(scl_io)), I2C_SCL_IO_ERR_STR, ESP_ERR_INVALID_ARG);
|
I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(scl_io)), I2C_SCL_IO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||||
I2C_CHECK((GPIO_IS_VALID_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
|
I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||||
// We do not check whether the SDA line is low
|
|
||||||
// because after some serious interference, the bus may keep high all the time and the i2c bus is out of service.
|
|
||||||
gpio_set_direction(scl_io, GPIO_MODE_OUTPUT_OD);
|
gpio_set_direction(scl_io, GPIO_MODE_OUTPUT_OD);
|
||||||
gpio_set_direction(sda_io, GPIO_MODE_OUTPUT_OD);
|
gpio_set_direction(sda_io, GPIO_MODE_INPUT_OUTPUT_OD);
|
||||||
gpio_set_level(scl_io, 1);
|
// If a SLAVE device was in a read operation when the bus was interrupted, the SLAVE device is controlling SDA.
|
||||||
|
// The only bit during the 9 clock cycles of a READ byte the MASTER(ESP32) is guaranteed control over is during the ACK bit
|
||||||
|
// period. If the slave is sending a stream of ZERO bytes, it will only release SDA during the ACK bit period.
|
||||||
|
// So, this reset code needs to synchronize the bit stream with, Either, the ACK bit, Or a 1 bit to correctly generate
|
||||||
|
// a STOP condition.
|
||||||
|
gpio_set_level(scl_io, 0);
|
||||||
gpio_set_level(sda_io, 1);
|
gpio_set_level(sda_io, 1);
|
||||||
gpio_set_level(sda_io, 0);
|
ets_delay_us(scl_half_period);
|
||||||
for (int i = 0; i < 9; i++) {
|
while(!gpio_get_level(sda_io) && (i++ < I2C_CLR_BUS_SCL_NUM)) {
|
||||||
gpio_set_level(scl_io, 0);
|
|
||||||
gpio_set_level(scl_io, 1);
|
gpio_set_level(scl_io, 1);
|
||||||
|
ets_delay_us(scl_half_period);
|
||||||
|
gpio_set_level(scl_io, 0);
|
||||||
|
ets_delay_us(scl_half_period);
|
||||||
}
|
}
|
||||||
gpio_set_level(sda_io, 1);
|
gpio_set_level(sda_io,0); // setup for STOP
|
||||||
|
gpio_set_level(scl_io,1);
|
||||||
|
ets_delay_us(scl_half_period);
|
||||||
|
gpio_set_level(sda_io, 1); // STOP, SDA low -> high while SCL is HIGH
|
||||||
i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER);
|
i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@@ -1087,7 +1099,7 @@ esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t dat
|
|||||||
return i2c_master_read_static(cmd_handle, data, data_len, ack);
|
return i2c_master_read_static(cmd_handle, data, data_len, ack);
|
||||||
} else {
|
} else {
|
||||||
if(data_len == 1) {
|
if(data_len == 1) {
|
||||||
return i2c_master_read_byte(cmd_handle, data, I2C_MASTER_NACK);
|
return i2c_master_read_byte(cmd_handle, data, I2C_MASTER_NACK);
|
||||||
} else {
|
} else {
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
if((ret = i2c_master_read_static(cmd_handle, data, data_len - 1, I2C_MASTER_ACK)) != ESP_OK) {
|
if((ret = i2c_master_read_static(cmd_handle, data, data_len - 1, I2C_MASTER_ACK)) != ESP_OK) {
|
||||||
@@ -1095,7 +1107,7 @@ esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t dat
|
|||||||
}
|
}
|
||||||
return i2c_master_read_byte(cmd_handle, data + data_len - 1, I2C_MASTER_NACK);
|
return i2c_master_read_byte(cmd_handle, data + data_len - 1, I2C_MASTER_NACK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
|
static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
|
||||||
@@ -1306,7 +1318,7 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
|
|||||||
clear_bus_cnt++;
|
clear_bus_cnt++;
|
||||||
if(clear_bus_cnt >= I2C_ACKERR_CNT_MAX) {
|
if(clear_bus_cnt >= I2C_ACKERR_CNT_MAX) {
|
||||||
i2c_master_clear_bus(i2c_num);
|
i2c_master_clear_bus(i2c_num);
|
||||||
clear_bus_cnt = 0;
|
clear_bus_cnt = 0;
|
||||||
}
|
}
|
||||||
ret = ESP_FAIL;
|
ret = ESP_FAIL;
|
||||||
} else {
|
} else {
|
||||||
@@ -1400,4 +1412,4 @@ int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, Ti
|
|||||||
}
|
}
|
||||||
xSemaphoreGive(p_i2c->slv_rx_mux);
|
xSemaphoreGive(p_i2c->slv_rx_mux);
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
@@ -24,17 +24,10 @@ To run this example, you should have one ESP32 dev board (e.g. ESP32-WROVER Kit)
|
|||||||
|
|
||||||
**Note:** The following pin assignments are used by default, you can change them with `i2cconfig` command at any time.
|
**Note:** The following pin assignments are used by default, you can change them with `i2cconfig` command at any time.
|
||||||
|
|
||||||
| | SDA | SCL |
|
| | SDA | SCL | GND | Other | VCC |
|
||||||
| ---------------- | ------ | ------ |
|
| ---------------- | ------ | ------ | ---- | ----- | ---- |
|
||||||
| ESP32 I2C Master | GPIO18 | GPIO19 |
|
| ESP32 I2C Master | GPIO18 | GPIO19 | GND | GND | 3.3V |
|
||||||
| Sensor | SDA | SCL |
|
| Sensor | SDA | SCL | GND | WAK | VCC |
|
||||||
|
|
||||||
- master:
|
|
||||||
- GPIO18 is assigned as the data signal of I2C master port
|
|
||||||
- GPIO19 is assigned as the clock signal of I2C master port
|
|
||||||
|
|
||||||
- connection:
|
|
||||||
- connect SDA/SCL of CCS811 sensor with GPIO18/GPIO19
|
|
||||||
|
|
||||||
**Note: ** There’s no need to add an external pull-up resistors for SDA/SCL pin, because the driver will enable the internal pull-up resistors itself.
|
**Note: ** There’s no need to add an external pull-up resistors for SDA/SCL pin, because the driver will enable the internal pull-up resistors itself.
|
||||||
|
|
||||||
@@ -43,6 +36,8 @@ To run this example, you should have one ESP32 dev board (e.g. ESP32-WROVER Kit)
|
|||||||
Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu.
|
Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu.
|
||||||
|
|
||||||
- You can choose whether or not to save command history into flash in `Store command history in flash` option.
|
- You can choose whether or not to save command history into flash in `Store command history in flash` option.
|
||||||
|
- You can set the maximum number of command line arguments under `Maximum number of command line arguments` option.
|
||||||
|
- You can set the command line buffer length under `Command line buffer length` option.
|
||||||
|
|
||||||
### Build and Flash
|
### Build and Flash
|
||||||
|
|
||||||
@@ -199,9 +194,11 @@ esp32> i2cget -c 0x5b -r 0x02 -l 8
|
|||||||
* I don’t find any available address when running `i2cdetect` command.
|
* I don’t find any available address when running `i2cdetect` command.
|
||||||
* Make sure your wiring connection is right.
|
* Make sure your wiring connection is right.
|
||||||
* Some sensor will have a “wake up” pin, via which user can put the sensor into a sleep mode. So make sure your sensor in **not** in the sleep state.
|
* Some sensor will have a “wake up” pin, via which user can put the sensor into a sleep mode. So make sure your sensor in **not** in the sleep state.
|
||||||
* Have a try resetting you I2C device, and then re-run `i2cdetect`.
|
* Reset you I2C device, and then run `i2cdetect` again.
|
||||||
* I can’t get the right content when running `i2cdump` command.
|
* I can’t get the right content when running `i2cdump` command.
|
||||||
* Currently the `i2cdump` only support those who have the same content length of registers inside the I2C device. For example, if a device have three legal addresses, and the content length at these address are 1 byte, 2 bytes and 4 bytes. Then you should not expect this command to dump the register correctly.
|
* Currently the `i2cdump` only support those who have the same content length of registers inside the I2C device. For example, if a device have three register addresses, and the content length at these address are 1 byte, 2 bytes and 4 bytes. In this case you should not expect this command to dump the register correctly.
|
||||||
|
* I really input argument correctly, but the command line “discard” the last few arguements from time to time.
|
||||||
|
* Enlarge the maximum number of arguments in the menuconfig.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
45
examples/peripherals/i2c/i2c_tools/example_test.py
Normal file
45
examples/peripherals/i2c/i2c_tools/example_test.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
EXPECT_TIMEOUT = 20
|
||||||
|
|
||||||
|
try:
|
||||||
|
import IDF
|
||||||
|
except ImportError:
|
||||||
|
test_fw_path = os.getenv("TEST_FW_PATH")
|
||||||
|
if test_fw_path and test_fw_path not in sys.path:
|
||||||
|
sys.path.insert(0, test_fw_path)
|
||||||
|
import IDF
|
||||||
|
|
||||||
|
|
||||||
|
@IDF.idf_example_test(env_tag='Example_I2C_CCS811_SENSOR')
|
||||||
|
def test_i2ctools_example(env, extra_data):
|
||||||
|
# Get device under test, flash and start example. "i2ctool" must be defined in EnvConfig
|
||||||
|
dut = env.get_dut('i2ctools', 'examples/peripherals/i2c/i2c_tools')
|
||||||
|
dut.start_app()
|
||||||
|
dut.expect("esp32>", timeout=EXPECT_TIMEOUT)
|
||||||
|
# Get i2c address
|
||||||
|
dut.write("i2cdetect")
|
||||||
|
dut.expect("5b", timeout=EXPECT_TIMEOUT)
|
||||||
|
# Get chip ID
|
||||||
|
dut.write("i2cget -c 0x5b -r 0x20 -l 1")
|
||||||
|
dut.expect("0x81", timeout=EXPECT_TIMEOUT)
|
||||||
|
# Reset sensor
|
||||||
|
dut.write("i2cset -c 0x5b -r 0xFF 0x11 0xE5 0x72 0x8A")
|
||||||
|
dut.expect("OK", timeout=EXPECT_TIMEOUT)
|
||||||
|
# Get status
|
||||||
|
dut.write("i2cget -c 0x5b -r 0x00 -l 1")
|
||||||
|
dut.expect_any("0x10", timeout=EXPECT_TIMEOUT)
|
||||||
|
# Change work mode
|
||||||
|
dut.write("i2cset -c 0x5b -r 0xF4")
|
||||||
|
dut.expect("OK", timeout=EXPECT_TIMEOUT)
|
||||||
|
dut.write("i2cset -c 0x5b -r 0x01 0x10")
|
||||||
|
dut.expect("OK", timeout=EXPECT_TIMEOUT)
|
||||||
|
# Get new status
|
||||||
|
dut.write("i2cget -c 0x5b -r 0x00 -l 1")
|
||||||
|
dut.expect_any("0x98", "0x90", timeout=EXPECT_TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_i2ctools_example()
|
@@ -8,4 +8,18 @@ config STORE_HISTORY
|
|||||||
command history. If this option is enabled, initalizes a FAT filesystem
|
command history. If this option is enabled, initalizes a FAT filesystem
|
||||||
and uses it to store command history.
|
and uses it to store command history.
|
||||||
|
|
||||||
|
config MAX_CMD_ARGUMENTS
|
||||||
|
int "Maximum number of command line arguments"
|
||||||
|
default 16
|
||||||
|
range 8 256
|
||||||
|
help
|
||||||
|
maximum number of command line arguments to parse
|
||||||
|
|
||||||
|
config MAX_CMD_LENGTH
|
||||||
|
int "Command line buffer length"
|
||||||
|
default 256
|
||||||
|
range 256 512
|
||||||
|
help
|
||||||
|
length of command line buffer, in bytes
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@@ -255,7 +255,7 @@ static int do_i2cset_cmd(int argc, char **argv)
|
|||||||
/* Check chip address: "-c" option */
|
/* Check chip address: "-c" option */
|
||||||
int chip_addr = i2cset_args.chip_address->ival[0];
|
int chip_addr = i2cset_args.chip_address->ival[0];
|
||||||
/* Check register address: "-r" option */
|
/* Check register address: "-r" option */
|
||||||
int data_addr = -1;
|
int data_addr = 0;
|
||||||
if (i2cset_args.register_address->count) {
|
if (i2cset_args.register_address->count) {
|
||||||
data_addr = i2cset_args.register_address->ival[0];
|
data_addr = i2cset_args.register_address->ival[0];
|
||||||
}
|
}
|
||||||
@@ -267,7 +267,7 @@ static int do_i2cset_cmd(int argc, char **argv)
|
|||||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||||
i2c_master_start(cmd);
|
i2c_master_start(cmd);
|
||||||
i2c_master_write_byte(cmd, chip_addr << 1 | WRITE_BIT, ACK_CHECK_EN);
|
i2c_master_write_byte(cmd, chip_addr << 1 | WRITE_BIT, ACK_CHECK_EN);
|
||||||
if (data_addr != -1) {
|
if (i2cset_args.register_address->count) {
|
||||||
i2c_master_write_byte(cmd, data_addr, ACK_CHECK_EN);
|
i2c_master_write_byte(cmd, data_addr, ACK_CHECK_EN);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
|
@@ -86,8 +86,8 @@ static void initialize_console()
|
|||||||
|
|
||||||
/* Initialize the console */
|
/* Initialize the console */
|
||||||
esp_console_config_t console_config = {
|
esp_console_config_t console_config = {
|
||||||
.max_cmdline_args = 8,
|
.max_cmdline_args = CONFIG_MAX_CMD_ARGUMENTS,
|
||||||
.max_cmdline_length = 256,
|
.max_cmdline_length = CONFIG_MAX_CMD_LENGTH,
|
||||||
#if CONFIG_LOG_COLORS
|
#if CONFIG_LOG_COLORS
|
||||||
.hint_color = atoi(LOG_COLOR_CYAN)
|
.hint_color = atoi(LOG_COLOR_CYAN)
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user