Skip to content

Commit 84fd0e9

Browse files
Update machine_i2c.c
Signed-off-by: Vincent1-python <pywei201209@163.com>
1 parent 2fc1eee commit 84fd0e9

File tree

1 file changed

+51
-126
lines changed

1 file changed

+51
-126
lines changed

ports/esp32/machine_i2c.c

Lines changed: 51 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* The MIT License (MIT)
55
*
66
* Copyright (c) 2019 Damien P. George
7+
* Copyright (c) 2025 Vincent1-python
78
*
89
* Permission is hereby granted, free of charge, to any person obtaining a copy
910
* of this software and associated documentation files (the "Software"), to deal
@@ -35,44 +36,27 @@
3536

3637
#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
3738

38-
#if SOC_I2C_SUPPORT_XTAL
39-
#if CONFIG_XTAL_FREQ > 0
40-
#define I2C_SCLK_FREQ (CONFIG_XTAL_FREQ * 1000000)
41-
#else
42-
#error "I2C uses XTAL but no configured freq"
43-
#endif // CONFIG_XTAL_FREQ
44-
#elif SOC_I2C_SUPPORT_APB
45-
#define I2C_SCLK_FREQ APB_CLK_FREQ
46-
#else
47-
#error "unsupported I2C for ESP32 SoC variant"
48-
#endif
49-
5039
#define I2C_DEFAULT_TIMEOUT_US (50000) // 50ms
5140

52-
// ---------------- Internal data structures ----------------
5341
typedef struct _machine_hw_i2c_obj_t {
5442
mp_obj_base_t base;
5543
i2c_master_bus_handle_t bus_handle;
56-
i2c_master_dev_handle_t dev_handle;
5744
uint8_t port : 8;
5845
gpio_num_t scl : 8;
5946
gpio_num_t sda : 8;
47+
uint32_t freq;
48+
uint32_t timeout_us;
6049
} machine_hw_i2c_obj_t;
6150

6251
static machine_hw_i2c_obj_t machine_hw_i2c_obj[I2C_NUM_MAX];
6352

64-
// ---------------- Initialization ----------------
65-
static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq, uint32_t timeout_us, bool first_init) {
53+
static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, bool first_init) {
6654

67-
// 1. If already initialized, uninstall the old driver first
6855
if (!first_init && self->bus_handle) {
69-
i2c_master_bus_rm_device(self->dev_handle);
7056
i2c_del_master_bus(self->bus_handle);
7157
self->bus_handle = NULL;
72-
self->dev_handle = NULL;
7358
}
7459

75-
// 2. Configure the bus
7660
i2c_master_bus_config_t bus_cfg = {
7761
.i2c_port = self->port,
7862
.scl_io_num = self->scl,
@@ -82,126 +66,60 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq, uint3
8266
.flags.enable_internal_pullup = true,
8367
};
8468
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_cfg, &self->bus_handle));
85-
86-
// 3. Add a device (placeholder address; will be changed dynamically later)
87-
i2c_device_config_t dev_cfg = {
88-
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
89-
.device_address = 0x00, // Placeholder
90-
.scl_speed_hz = freq,
91-
};
92-
ESP_ERROR_CHECK(i2c_master_bus_add_device(self->bus_handle, &dev_cfg, &self->dev_handle));
9369
}
9470

95-
int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) {
71+
static int machine_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags) {
9672
machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
9773

98-
/* 0. Probe the address to see if any device responds */
99-
esp_err_t err = i2c_master_probe(self->bus_handle, addr, 1000);
74+
// 1. Probe the address to see if any device responds.
75+
// This test uses a fixed scl freq of 100_000.
76+
esp_err_t err = i2c_master_probe(self->bus_handle, addr, self->timeout_us / 1000);
10077
if (err != ESP_OK) {
101-
return -MP_ENODEV; /* No device at address, return immediately */
78+
return -MP_ENODEV; // No device at address, return immediately
10279
}
103-
/* 1. Create a temporary device handle for this transaction */
104-
i2c_device_config_t dev_cfg = {
105-
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
106-
.device_address = addr,
107-
.scl_speed_hz = 100000, /* Use bus frequency */
108-
};
109-
i2c_master_dev_handle_t dev_handle;
110-
err = i2c_master_bus_add_device(self->bus_handle, &dev_cfg, &dev_handle);
111-
if (err != ESP_OK) {
112-
return -MP_ENODEV;
113-
}
114-
115-
int data_len = 0;
11680

117-
/* 2. If WRITE1 segment exists, perform the write first */
118-
if (flags & MP_MACHINE_I2C_FLAG_WRITE1) {
119-
if (bufs->len) {
120-
err = i2c_master_transmit(dev_handle, bufs->buf, bufs->len, 1000); /* Block with 1 s timeout */
121-
if (err != ESP_OK) {
122-
goto cleanup;
123-
}
81+
if (len > 0) {
82+
// 2. Create a temporary device handle for this transaction
83+
// This step for every transaction can be omitted in
84+
// esp idf v5.5+, which supports handle address changing.
85+
i2c_device_config_t dev_cfg = {
86+
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
87+
.device_address = addr,
88+
.scl_speed_hz = self->freq,
89+
};
90+
i2c_master_dev_handle_t dev_handle;
91+
err = i2c_master_bus_add_device(self->bus_handle, &dev_cfg, &dev_handle);
92+
if (err != ESP_OK) {
93+
return -MP_ENODEV;
12494
}
125-
data_len += bufs->len;
126-
--n;
127-
++bufs;
128-
}
129-
if (flags & MP_MACHINE_I2C_FLAG_READ) {
130-
/* 3. Main loop: remaining segments */
131-
for (; n--; ++bufs) {
132-
if (bufs->len == 0) {
133-
continue;
134-
}
135-
err = i2c_master_receive(dev_handle, bufs->buf, bufs->len, 1000);
136-
if (err != ESP_OK) {
137-
break;
138-
}
139-
140-
data_len += bufs->len;
95+
// 3. Transfer data
96+
if (flags & MP_MACHINE_I2C_FLAG_READ) {
97+
err = i2c_master_receive(dev_handle, buf, len, self->timeout_us / 1000);
98+
} else if (len > 0) {
99+
err = i2c_master_transmit(dev_handle, buf, len, self->timeout_us / 1000);
141100
}
142-
} else {
143-
// Write operation logic
144-
size_t total_len = 0;
145-
mp_machine_i2c_buf_t *original_bufs = bufs; // Save original pointer
146-
size_t yuann = n;
147-
148-
// Calculate total length
149-
for (; n--; ++bufs) {
150-
total_len += bufs->len;
101+
// 4. Destroy the temporary handle
102+
i2c_master_bus_rm_device(dev_handle);
103+
// 5. Map errors
104+
if (err == ESP_FAIL) {
105+
return -MP_ENODEV;
151106
}
152-
153-
// Reset pointer
154-
bufs = original_bufs;
155-
// Reset n
156-
n = yuann;
157-
// Dynamically allocate write_buf
158-
uint8_t *write_buf = (uint8_t *)malloc(total_len);
159-
if (write_buf == NULL) {
160-
return -MP_ENOMEM;
107+
if (err == ESP_ERR_TIMEOUT) {
108+
return -MP_ETIMEDOUT;
161109
}
162-
163-
// Copy data into write_buf
164-
size_t index = 0;
165-
for (; n--; ++bufs) {
166-
memcpy(write_buf + index, bufs->buf, bufs->len);
167-
index += bufs->len;
168-
}
169-
170-
// Transmit data
171-
err = i2c_master_transmit(dev_handle, write_buf, total_len, 1000);
172110
if (err != ESP_OK) {
173-
goto cleanup;
111+
return -abs(err);
174112
}
175-
176-
// Free dynamically allocated memory
177-
free(write_buf);
178-
}
179-
180-
cleanup:
181-
/* 4. Immediately destroy the temporary handle */
182-
i2c_master_bus_rm_device(dev_handle);
183-
184-
/* 5. Map errors */
185-
if (err == ESP_FAIL) {
186-
return -MP_ENODEV;
187113
}
188-
if (err == ESP_ERR_TIMEOUT) {
189-
return -MP_ETIMEDOUT;
190-
}
191-
if (err != ESP_OK) {
192-
return -abs(err);
193-
}
194-
195-
return data_len;
114+
return len;
196115
}
197116

198-
// ---------------- Print ----------------
199117
static void machine_hw_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
200118
machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
201-
mp_printf(print, "I2C(%u, scl=%u, sda=%u)", self->port, self->scl, self->sda);
119+
mp_printf(print, "I2C(%u, scl=%u, sda=%u, freq=%u, timeout=%u)",
120+
self->port, self->scl, self->sda, self->freq, self->timeout_us);
202121
}
203122

204-
// ---------------- Constructor ----------------
205123
mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
206124
// Create a SoftI2C instance if no id is specified (or is -1) but other arguments are given
207125
if (n_args != 0) {
@@ -214,8 +132,8 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_
214132
{ MP_QSTR_id, MP_ARG_INT, {.u_int = I2C_NUM_0} },
215133
{ MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
216134
{ MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
217-
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
218-
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = I2C_DEFAULT_TIMEOUT_US} },
135+
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
136+
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
219137
};
220138
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
221139
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -233,6 +151,8 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_
233151
self->port = i2c_id;
234152
self->scl = (i2c_id == I2C_NUM_0) ? MICROPY_HW_I2C0_SCL : MICROPY_HW_I2C1_SCL;
235153
self->sda = (i2c_id == I2C_NUM_0) ? MICROPY_HW_I2C0_SDA : MICROPY_HW_I2C1_SDA;
154+
self->freq = 400000;
155+
self->timeout_us = I2C_DEFAULT_TIMEOUT_US;
236156
}
237157

238158
if (args[ARG_scl].u_obj != MP_OBJ_NULL) {
@@ -241,15 +161,20 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_
241161
if (args[ARG_sda].u_obj != MP_OBJ_NULL) {
242162
self->sda = machine_pin_get_id(args[ARG_sda].u_obj);
243163
}
164+
if (args[ARG_freq].u_int != -1) {
165+
self->freq = args[ARG_freq].u_int;
166+
}
167+
if (args[ARG_timeout].u_int != -1) {
168+
self->timeout_us = args[ARG_timeout].u_int;
169+
}
244170

245-
machine_hw_i2c_init(self, args[ARG_freq].u_int, args[ARG_timeout].u_int, first_init);
171+
machine_hw_i2c_init(self, first_init);
246172
return MP_OBJ_FROM_PTR(self);
247173
}
248174

249-
// ---------------- Protocol table ----------------
250175
static const mp_machine_i2c_p_t machine_hw_i2c_p = {
251-
.transfer_supports_write1 = true,
252-
.transfer = machine_hw_i2c_transfer,
176+
.transfer = mp_machine_i2c_transfer_adaptor,
177+
.transfer_single = machine_i2c_transfer_single,
253178
};
254179

255180
MP_DEFINE_CONST_OBJ_TYPE(

0 commit comments

Comments
 (0)