28
28
#include "py/mphal.h"
29
29
#include "py/mperrno.h"
30
30
#include "extmod/modmachine.h"
31
- #include "machine_i2c.h"
32
31
33
- #include "driver/i2c.h"
34
- #include "hal/i2c_ll.h"
32
+ #include "driver/i2c_master.h"
35
33
36
34
#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
37
35
38
- #if SOC_I2C_SUPPORT_XTAL
39
- #if CONFIG_XTAL_FREQ > 0
40
- #define I2C_SCLK_FREQ (CONFIG_XTAL_FREQ * 1000000)
36
+ #ifndef MICROPY_HW_I2C0_SCL
37
+ #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
38
+ #define MICROPY_HW_I2C0_SCL (GPIO_NUM_9)
39
+ #define MICROPY_HW_I2C0_SDA (GPIO_NUM_8)
40
+ #else
41
+ #define MICROPY_HW_I2C0_SCL (GPIO_NUM_18)
42
+ #define MICROPY_HW_I2C0_SDA (GPIO_NUM_19)
43
+ #endif
44
+ #endif
45
+
46
+ #ifndef MICROPY_HW_I2C1_SCL
47
+ #if CONFIG_IDF_TARGET_ESP32
48
+ #define MICROPY_HW_I2C1_SCL (GPIO_NUM_25)
49
+ #define MICROPY_HW_I2C1_SDA (GPIO_NUM_26)
41
50
#else
42
- #error "I2C uses XTAL but no configured freq"
43
- #endif // CONFIG_XTAL_FREQ
51
+ #define MICROPY_HW_I2C1_SCL (GPIO_NUM_9)
52
+ #define MICROPY_HW_I2C1_SDA (GPIO_NUM_8)
53
+ #endif
54
+ #endif
55
+
56
+ #if SOC_I2C_SUPPORT_XTAL
57
+ #define I2C_SCLK_FREQ XTAL_CLK_FREQ
44
58
#elif SOC_I2C_SUPPORT_APB
45
59
#define I2C_SCLK_FREQ APB_CLK_FREQ
46
60
#else
49
63
50
64
#define I2C_DEFAULT_TIMEOUT_US (50000) // 50ms
51
65
66
+ // ---------------- 内部数据结构 ----------------
52
67
typedef struct _machine_hw_i2c_obj_t {
53
68
mp_obj_base_t base ;
54
- i2c_port_t port : 8 ;
55
- gpio_num_t scl : 8 ;
56
- gpio_num_t sda : 8 ;
69
+ i2c_master_bus_handle_t bus_handle ;
70
+ i2c_master_dev_handle_t dev_handle ;
71
+ uint8_t port ;
72
+ gpio_num_t scl ;
73
+ gpio_num_t sda ;
57
74
} machine_hw_i2c_obj_t ;
58
75
59
76
static machine_hw_i2c_obj_t machine_hw_i2c_obj [I2C_NUM_MAX ];
60
77
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 );
78
+ // ---------------- 初始化 ----------------
79
+ static void machine_hw_i2c_init (machine_hw_i2c_obj_t * self ,
80
+ uint32_t freq ,
81
+ uint32_t timeout_us ,
82
+ bool first_init ) {
83
+
84
+ // 1. 若已初始化,先卸载旧驱动
85
+ if (!first_init && self -> bus_handle ) {
86
+ i2c_master_bus_rm_device (self -> dev_handle );
87
+ i2c_del_master_bus (self -> bus_handle );
88
+ self -> bus_handle = NULL ;
89
+ self -> dev_handle = NULL ;
64
90
}
65
- i2c_config_t conf = {
66
- . mode = I2C_MODE_MASTER ,
67
- . sda_io_num = self -> sda ,
68
- .sda_pullup_en = GPIO_PULLUP_ENABLE ,
91
+
92
+ // 2. 配置总线
93
+ i2c_master_bus_config_t bus_cfg = {
94
+ .i2c_port = self -> port ,
69
95
.scl_io_num = self -> scl ,
70
- .scl_pullup_en = GPIO_PULLUP_ENABLE ,
71
- .master .clk_speed = freq ,
96
+ .sda_io_num = self -> sda ,
97
+ .clk_source = I2C_CLK_SRC_DEFAULT ,
98
+ .glitch_ignore_cnt = 7 ,
99
+ .flags .enable_internal_pullup = true,
100
+ };
101
+ ESP_ERROR_CHECK (i2c_new_master_bus (& bus_cfg , & self -> bus_handle ));
102
+
103
+ // 3. 添加设备(占位地址,后面真正传输时再动态改)
104
+ i2c_device_config_t dev_cfg = {
105
+ .dev_addr_length = I2C_ADDR_BIT_LEN_7 ,
106
+ .device_address = 0x00 , // 占位
107
+ .scl_speed_hz = freq ,
72
108
};
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 );
109
+ ESP_ERROR_CHECK (i2c_master_bus_add_device (self -> bus_handle , & dev_cfg , & self -> dev_handle ));
77
110
}
78
111
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 ) {
112
+ int machine_hw_i2c_transfer (mp_obj_base_t * self_in ,
113
+ uint16_t addr ,
114
+ size_t n ,
115
+ mp_machine_i2c_buf_t * bufs ,
116
+ unsigned int flags )
117
+ {
80
118
machine_hw_i2c_obj_t * self = MP_OBJ_TO_PTR (self_in );
81
119
82
- i2c_cmd_handle_t cmd = i2c_cmd_link_create ();
120
+ /* 0. 先探测地址是否有设备回应 */
121
+ esp_err_t err = i2c_master_probe (self -> bus_handle , addr , 1000 );
122
+ if (err != ESP_OK ) {
123
+ return - MP_ENODEV ; /* 地址无设备,直接返回 */
124
+ }
125
+ /* 1. 为本次事务创建临时 device 句柄 */
126
+ i2c_device_config_t dev_cfg = {
127
+ .dev_addr_length = I2C_ADDR_BIT_LEN_7 ,
128
+ .device_address = addr ,
129
+ .scl_speed_hz = 100000 , /* 沿用总线频率即可 */
130
+ };
131
+ i2c_master_dev_handle_t dev_handle ;
132
+ err = i2c_master_bus_add_device (self -> bus_handle , & dev_cfg , & dev_handle );
133
+ if (err != ESP_OK ) {
134
+ return - MP_ENODEV ;
135
+ }
136
+
83
137
int data_len = 0 ;
84
138
139
+ /* 2. 若有 WRITE1 段,先写一段 */
85
140
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);
141
+ if (bufs -> len ) {
142
+ err = i2c_master_transmit (dev_handle ,
143
+ bufs -> buf ,
144
+ bufs -> len ,
145
+ 1000 ); /* 阻塞超时 1 s */
146
+ if (err != ESP_OK ) goto cleanup ;
147
+ }
89
148
data_len += bufs -> len ;
90
149
-- n ;
91
150
++ bufs ;
92
151
}
152
+ if (flags & MP_MACHINE_I2C_FLAG_READ ) {
153
+ /* 3. 主循环:剩余段 */
154
+ for (; n -- ; ++ bufs ) {
155
+ if (bufs -> len == 0 ) continue ;
156
+ err = i2c_master_receive (dev_handle ,
157
+ bufs -> buf ,
158
+ //bufs->len,
159
+ 1 ,
160
+ 1000 );
161
+ if (err != ESP_OK ) break ;
93
162
94
- i2c_master_start (cmd );
95
- i2c_master_write_byte (cmd , addr << 1 | (flags & MP_MACHINE_I2C_FLAG_READ ), true);
163
+ data_len += bufs -> len ;
164
+ }
165
+ } else {
166
+ // 写操作逻辑
167
+ size_t total_len = 0 ;
168
+ mp_machine_i2c_buf_t * original_bufs = bufs ; // 保存原始指针
169
+ size_t yuann = n ;
96
170
97
- for (; n -- ; ++ bufs ) {
98
- 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 );
100
- } else {
101
- if (bufs -> len != 0 ) {
102
- i2c_master_write (cmd , bufs -> buf , bufs -> len , true);
103
- }
171
+ // 计算总长度
172
+ for (; n -- ; ++ bufs ) {
173
+ total_len += bufs -> len ;
104
174
}
105
- data_len += bufs -> len ;
106
- }
107
175
108
- if (flags & MP_MACHINE_I2C_FLAG_STOP ) {
109
- i2c_master_stop (cmd );
110
- }
176
+ // 重置指针
177
+ bufs = original_bufs ;
178
+ // 重置n
179
+ n = yuann ;
180
+ // 动态分配 write_buf
181
+ uint8_t * write_buf = (uint8_t * )malloc (total_len );
182
+ if (write_buf == NULL ) return - MP_ENOMEM ;
183
+
184
+ // 复制数据到 write_buf
185
+ size_t index = 0 ;
186
+ for (; n -- ; ++ bufs ) {
187
+ memcpy (write_buf + index , bufs -> buf , bufs -> len );
188
+ index += bufs -> len ;
189
+ }
111
190
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 ) ;
191
+ // 发送数据
192
+ err = i2c_master_transmit ( dev_handle , write_buf , total_len , 1000 );
193
+ if ( err != ESP_OK ) goto cleanup ;
115
194
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 );
195
+ // 释放动态分配的内存
196
+ free (write_buf );
122
197
}
123
198
199
+ cleanup :
200
+ /* 4. 立即销毁临时句柄 */
201
+ i2c_master_bus_rm_device (dev_handle );
202
+
203
+ /* 5. 出错映射 */
204
+ if (err == ESP_FAIL ) return - MP_ENODEV ;
205
+ if (err == ESP_ERR_TIMEOUT ) return - MP_ETIMEDOUT ;
206
+ if (err != ESP_OK ) return - abs (err );
207
+
124
208
return data_len ;
125
209
}
126
210
127
- /******************************************************************************/
128
- // MicroPython bindings for machine API
129
-
130
- static void machine_hw_i2c_print ( const mp_print_t * print , mp_obj_t self_in , mp_print_kind_t kind ) {
211
+ // ---------------- 打印 ----------------
212
+ static void machine_hw_i2c_print ( const mp_print_t * print ,
213
+ mp_obj_t self_in ,
214
+ mp_print_kind_t kind ) {
131
215
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 ));
216
+ mp_printf (print , "I2C(%u, scl=%u, sda=%u)" ,
217
+ self -> port , self -> scl , self -> sda );
136
218
}
137
219
138
- 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 ) {
220
+ // ---------------- 构造函数 ----------------
221
+ mp_obj_t machine_hw_i2c_make_new (const mp_obj_type_t * type ,
222
+ size_t n_args , size_t n_kw ,
223
+ const mp_obj_t * all_args ) {
139
224
// Create a SoftI2C instance if no id is specified (or is -1) but other arguments are given
140
225
if (n_args != 0 ) {
141
226
MP_MACHINE_I2C_CHECK_FOR_LEGACY_SOFTI2C_CONSTRUCTION (n_args , n_kw , all_args );
142
227
}
143
-
144
- // Parse args
145
228
enum { ARG_id , ARG_scl , ARG_sda , ARG_freq , ARG_timeout };
146
229
static const mp_arg_t allowed_args [] = {
147
230
{ MP_QSTR_id , MP_ARG_INT , {.u_int = I2C_NUM_0 } },
@@ -151,48 +234,40 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_
151
234
{ MP_QSTR_timeout , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = I2C_DEFAULT_TIMEOUT_US } },
152
235
};
153
236
mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
154
- mp_arg_parse_all_kw_array (n_args , n_kw , all_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
237
+ mp_arg_parse_all_kw_array (n_args , n_kw , all_args ,
238
+ MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
155
239
156
- // Get I2C bus
157
240
mp_int_t i2c_id = args [ARG_id ].u_int ;
158
-
159
- // Check if the I2C bus is valid
160
241
if (!(I2C_NUM_0 <= i2c_id && i2c_id < I2C_NUM_MAX )) {
161
- mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("I2C(%d) doesn't exist" ), i2c_id );
242
+ mp_raise_msg_varg (& mp_type_ValueError ,
243
+ MP_ERROR_TEXT ("I2C(%d) doesn't exist" ), i2c_id );
162
244
}
163
245
164
- // Get static peripheral object
165
- machine_hw_i2c_obj_t * self = (machine_hw_i2c_obj_t * )& machine_hw_i2c_obj [i2c_id ];
246
+ machine_hw_i2c_obj_t * self = & machine_hw_i2c_obj [i2c_id ];
166
247
167
- bool first_init = false;
168
- if (self -> base .type == NULL ) {
169
- // Created for the first time, set default pins
248
+ bool first_init = (self -> base .type == NULL );
249
+ if (first_init ) {
170
250
self -> base .type = & machine_i2c_type ;
171
251
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;
252
+ self -> scl = (i2c_id == I2C_NUM_0 ) ? MICROPY_HW_I2C0_SCL : MICROPY_HW_I2C1_SCL ;
253
+ self -> sda = (i2c_id == I2C_NUM_0 ) ? MICROPY_HW_I2C0_SDA : MICROPY_HW_I2C1_SDA ;
180
254
}
181
255
182
- // Set SCL/SDA pins if given
183
256
if (args [ARG_scl ].u_obj != MP_OBJ_NULL ) {
184
257
self -> scl = machine_pin_get_id (args [ARG_scl ].u_obj );
185
258
}
186
259
if (args [ARG_sda ].u_obj != MP_OBJ_NULL ) {
187
260
self -> sda = machine_pin_get_id (args [ARG_sda ].u_obj );
188
261
}
189
262
190
- // Initialise the I2C peripheral
191
- machine_hw_i2c_init (self , args [ARG_freq ].u_int , args [ARG_timeout ].u_int , first_init );
192
-
263
+ machine_hw_i2c_init (self ,
264
+ args [ARG_freq ].u_int ,
265
+ args [ARG_timeout ].u_int ,
266
+ first_init );
193
267
return MP_OBJ_FROM_PTR (self );
194
268
}
195
269
270
+ // ---------------- 协议表 ----------------
196
271
static const mp_machine_i2c_p_t machine_hw_i2c_p = {
197
272
.transfer_supports_write1 = true,
198
273
.transfer = machine_hw_i2c_transfer ,
@@ -206,6 +281,6 @@ MP_DEFINE_CONST_OBJ_TYPE(
206
281
print , machine_hw_i2c_print ,
207
282
protocol , & machine_hw_i2c_p ,
208
283
locals_dict , & mp_machine_i2c_locals_dict
209
- );
284
+ );
210
285
211
- #endif
286
+ #endif // MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
0 commit comments