Skip to content

Commit c45d97c

Browse files
esp32: Update machine_i2c.c.
Signed-off-by: Vincent1-python <pywei201209@163.com>
1 parent 4d1f904 commit c45d97c

File tree

1 file changed

+76
-97
lines changed

1 file changed

+76
-97
lines changed

ports/esp32/machine_i2c.c

Lines changed: 76 additions & 97 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
@@ -30,109 +31,93 @@
3031
#include "extmod/modmachine.h"
3132
#include "machine_i2c.h"
3233

33-
#include "driver/i2c.h"
34+
#include "driver/i2c_master.h"
3435
#include "hal/i2c_ll.h"
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

5241
typedef struct _machine_hw_i2c_obj_t {
5342
mp_obj_base_t base;
54-
i2c_port_t port : 8;
43+
i2c_master_bus_handle_t bus_handle;
44+
uint8_t port : 8;
5545
gpio_num_t scl : 8;
5646
gpio_num_t sda : 8;
47+
uint32_t freq;
48+
uint32_t timeout_us;
5749
} machine_hw_i2c_obj_t;
5850

5951
static machine_hw_i2c_obj_t machine_hw_i2c_obj[I2C_NUM_MAX];
6052

61-
static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq, uint32_t timeout_us, bool first_init) {
62-
if (!first_init) {
63-
i2c_driver_delete(self->port);
53+
static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, bool first_init) {
54+
55+
if (!first_init && self->bus_handle) {
56+
i2c_del_master_bus(self->bus_handle);
57+
self->bus_handle = NULL;
6458
}
65-
i2c_config_t conf = {
66-
.mode = I2C_MODE_MASTER,
67-
.sda_io_num = self->sda,
68-
.sda_pullup_en = GPIO_PULLUP_ENABLE,
59+
60+
i2c_master_bus_config_t bus_cfg = {
61+
.i2c_port = self->port,
6962
.scl_io_num = self->scl,
70-
.scl_pullup_en = GPIO_PULLUP_ENABLE,
71-
.master.clk_speed = freq,
63+
.sda_io_num = self->sda,
64+
.clk_source = I2C_CLK_SRC_DEFAULT,
65+
.glitch_ignore_cnt = 7,
66+
.flags.enable_internal_pullup = true,
7267
};
73-
i2c_param_config(self->port, &conf);
74-
int timeout = I2C_SCLK_FREQ / 1000000 * timeout_us;
75-
i2c_set_timeout(self->port, (timeout > I2C_LL_MAX_TIMEOUT) ? I2C_LL_MAX_TIMEOUT : timeout);
76-
i2c_driver_install(self->port, I2C_MODE_MASTER, 0, 0, 0);
68+
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_cfg, &self->bus_handle));
7769
}
7870

79-
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) {
8072
machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
8173

82-
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
83-
int data_len = 0;
84-
85-
if (flags & MP_MACHINE_I2C_FLAG_WRITE1) {
86-
i2c_master_start(cmd);
87-
i2c_master_write_byte(cmd, addr << 1, true);
88-
i2c_master_write(cmd, bufs->buf, bufs->len, true);
89-
data_len += bufs->len;
90-
--n;
91-
++bufs;
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);
77+
if (err != ESP_OK) {
78+
return -MP_ENODEV; // No device at address, return immediately
9279
}
9380

94-
i2c_master_start(cmd);
95-
i2c_master_write_byte(cmd, addr << 1 | (flags & MP_MACHINE_I2C_FLAG_READ), true);
96-
97-
for (; n--; ++bufs) {
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;
94+
}
95+
// 3. Transfer data
9896
if (flags & MP_MACHINE_I2C_FLAG_READ) {
99-
i2c_master_read(cmd, bufs->buf, bufs->len, n == 0 ? I2C_MASTER_LAST_NACK : I2C_MASTER_ACK);
97+
err = i2c_master_receive(dev_handle, buf, len, self->timeout_us / 1000);
10098
} else {
101-
if (bufs->len != 0) {
102-
i2c_master_write(cmd, bufs->buf, bufs->len, true);
103-
}
99+
err = i2c_master_transmit(dev_handle, buf, len, self->timeout_us / 1000);
100+
}
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;
106+
}
107+
if (err == ESP_ERR_TIMEOUT) {
108+
return -MP_ETIMEDOUT;
109+
}
110+
if (err != ESP_OK) {
111+
return -abs(err);
104112
}
105-
data_len += bufs->len;
106-
}
107-
108-
if (flags & MP_MACHINE_I2C_FLAG_STOP) {
109-
i2c_master_stop(cmd);
110-
}
111-
112-
// TODO proper timeout
113-
esp_err_t err = i2c_master_cmd_begin(self->port, cmd, 100 * (1 + data_len) / portTICK_PERIOD_MS);
114-
i2c_cmd_link_delete(cmd);
115-
116-
if (err == ESP_FAIL) {
117-
return -MP_ENODEV;
118-
} else if (err == ESP_ERR_TIMEOUT) {
119-
return -MP_ETIMEDOUT;
120-
} else if (err != ESP_OK) {
121-
return -abs(err);
122113
}
123-
124-
return data_len;
114+
return len;
125115
}
126116

127-
/******************************************************************************/
128-
// MicroPython bindings for machine API
129-
130117
static void machine_hw_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
131118
machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
132-
int h, l;
133-
i2c_get_period(self->port, &h, &l);
134-
mp_printf(print, "I2C(%u, scl=%u, sda=%u, freq=%u)",
135-
self->port, self->scl, self->sda, I2C_SCLK_FREQ / (h + l));
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);
136121
}
137122

138123
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) {
@@ -147,55 +132,49 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_
147132
{ MP_QSTR_id, MP_ARG_INT, {.u_int = I2C_NUM_0} },
148133
{ MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
149134
{ MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
150-
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
151-
{ 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} },
152137
};
153138
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
154139
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
155140

156-
// Get I2C bus
157141
mp_int_t i2c_id = args[ARG_id].u_int;
158-
159-
// Check if the I2C bus is valid
160142
if (!(I2C_NUM_0 <= i2c_id && i2c_id < I2C_NUM_MAX)) {
161143
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C(%d) doesn't exist"), i2c_id);
162144
}
163145

164-
// Get static peripheral object
165-
machine_hw_i2c_obj_t *self = (machine_hw_i2c_obj_t *)&machine_hw_i2c_obj[i2c_id];
146+
machine_hw_i2c_obj_t *self = &machine_hw_i2c_obj[i2c_id];
166147

167-
bool first_init = false;
168-
if (self->base.type == NULL) {
169-
// Created for the first time, set default pins
148+
bool first_init = (self->base.type == NULL);
149+
if (first_init) {
170150
self->base.type = &machine_i2c_type;
171151
self->port = i2c_id;
172-
if (self->port == I2C_NUM_0) {
173-
self->scl = MICROPY_HW_I2C0_SCL;
174-
self->sda = MICROPY_HW_I2C0_SDA;
175-
} else {
176-
self->scl = MICROPY_HW_I2C1_SCL;
177-
self->sda = MICROPY_HW_I2C1_SDA;
178-
}
179-
first_init = true;
152+
self->scl = (i2c_id == I2C_NUM_0) ? MICROPY_HW_I2C0_SCL : MICROPY_HW_I2C1_SCL;
153+
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;
180156
}
181157

182-
// Set SCL/SDA pins if given
183158
if (args[ARG_scl].u_obj != MP_OBJ_NULL) {
184159
self->scl = machine_pin_get_id(args[ARG_scl].u_obj);
185160
}
186161
if (args[ARG_sda].u_obj != MP_OBJ_NULL) {
187162
self->sda = machine_pin_get_id(args[ARG_sda].u_obj);
188163
}
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+
}
189170

190-
// Initialise the I2C peripheral
191-
machine_hw_i2c_init(self, args[ARG_freq].u_int, args[ARG_timeout].u_int, first_init);
192-
171+
machine_hw_i2c_init(self, first_init);
193172
return MP_OBJ_FROM_PTR(self);
194173
}
195174

196175
static const mp_machine_i2c_p_t machine_hw_i2c_p = {
197-
.transfer_supports_write1 = true,
198-
.transfer = machine_hw_i2c_transfer,
176+
.transfer = mp_machine_i2c_transfer_adaptor,
177+
.transfer_single = machine_i2c_transfer_single,
199178
};
200179

201180
MP_DEFINE_CONST_OBJ_TYPE(
@@ -208,4 +187,4 @@ MP_DEFINE_CONST_OBJ_TYPE(
208187
locals_dict, &mp_machine_i2c_locals_dict
209188
);
210189

211-
#endif
190+
#endif // MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C

0 commit comments

Comments
 (0)