11/*
2- * This file is part of the MicroPython project, http://micropython.org/
2+ * This file is part of the MicroPython project, http://micropython.org/
33 *
44 * The MIT License (MIT)
55 *
3030#include "extmod/modmachine.h"
3131#include "machine_i2c.h"
3232
33- #include "driver/i2c .h"
33+ #include "driver/i2c_master .h"
3434#include "hal/i2c_ll.h"
3535
3636#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
4949
5050#define I2C_DEFAULT_TIMEOUT_US (50000) // 50ms
5151
52+ // ---------------- Internal data structures ----------------
5253typedef struct _machine_hw_i2c_obj_t {
5354 mp_obj_base_t base ;
54- i2c_port_t port : 8 ;
55- gpio_num_t scl : 8 ;
56- gpio_num_t sda : 8 ;
55+ i2c_master_bus_handle_t bus_handle ;
56+ i2c_master_dev_handle_t dev_handle ;
57+ uint8_t port ;
58+ gpio_num_t scl ;
59+ gpio_num_t sda ;
5760} machine_hw_i2c_obj_t ;
5861
5962static machine_hw_i2c_obj_t machine_hw_i2c_obj [I2C_NUM_MAX ];
6063
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 );
64+ // ---------------- Initialization ----------------
65+ static void machine_hw_i2c_init (machine_hw_i2c_obj_t * self ,
66+ uint32_t freq ,
67+ uint32_t timeout_us ,
68+ bool first_init ) {
69+
70+ // 1. If already initialized, uninstall the old driver first
71+ if (!first_init && self -> bus_handle ) {
72+ i2c_master_bus_rm_device (self -> dev_handle );
73+ i2c_del_master_bus (self -> bus_handle );
74+ self -> bus_handle = NULL ;
75+ self -> dev_handle = NULL ;
6476 }
65- i2c_config_t conf = {
66- . mode = I2C_MODE_MASTER ,
67- . sda_io_num = self -> sda ,
68- .sda_pullup_en = GPIO_PULLUP_ENABLE ,
77+
78+ // 2. Configure the bus
79+ i2c_master_bus_config_t bus_cfg = {
80+ .i2c_port = self -> port ,
6981 .scl_io_num = self -> scl ,
70- .scl_pullup_en = GPIO_PULLUP_ENABLE ,
71- .master .clk_speed = freq ,
82+ .sda_io_num = self -> sda ,
83+ .clk_source = I2C_CLK_SRC_DEFAULT ,
84+ .glitch_ignore_cnt = 7 ,
85+ .flags .enable_internal_pullup = true,
7286 };
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 );
87+ ESP_ERROR_CHECK (i2c_new_master_bus (& bus_cfg , & self -> bus_handle ));
88+
89+ // 3. Add a device (placeholder address; will be changed dynamically later)
90+ i2c_device_config_t dev_cfg = {
91+ .dev_addr_length = I2C_ADDR_BIT_LEN_7 ,
92+ .device_address = 0x00 , // Placeholder
93+ .scl_speed_hz = freq ,
94+ };
95+ ESP_ERROR_CHECK (i2c_master_bus_add_device (self -> bus_handle , & dev_cfg , & self -> dev_handle ));
7796}
7897
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 ) {
98+ int machine_hw_i2c_transfer (mp_obj_base_t * self_in ,
99+ uint16_t addr ,
100+ size_t n ,
101+ mp_machine_i2c_buf_t * bufs ,
102+ unsigned int flags )
103+ {
80104 machine_hw_i2c_obj_t * self = MP_OBJ_TO_PTR (self_in );
81105
82- i2c_cmd_handle_t cmd = i2c_cmd_link_create ();
106+ /* 0. Probe the address to see if any device responds */
107+ esp_err_t err = i2c_master_probe (self -> bus_handle , addr , 1000 );
108+ if (err != ESP_OK ) {
109+ return - MP_ENODEV ; /* No device at address, return immediately */
110+ }
111+ /* 1. Create a temporary device handle for this transaction */
112+ i2c_device_config_t dev_cfg = {
113+ .dev_addr_length = I2C_ADDR_BIT_LEN_7 ,
114+ .device_address = addr ,
115+ .scl_speed_hz = 100000 , /* Use bus frequency */
116+ };
117+ i2c_master_dev_handle_t dev_handle ;
118+ err = i2c_master_bus_add_device (self -> bus_handle , & dev_cfg , & dev_handle );
119+ if (err != ESP_OK ) {
120+ return - MP_ENODEV ;
121+ }
122+
83123 int data_len = 0 ;
84124
125+ /* 2. If WRITE1 segment exists, perform the write first */
85126 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);
127+ if (bufs -> len ) {
128+ err = i2c_master_transmit (dev_handle ,
129+ bufs -> buf ,
130+ bufs -> len ,
131+ 1000 ); /* Block with 1 s timeout */
132+ if (err != ESP_OK ) goto cleanup ;
133+ }
89134 data_len += bufs -> len ;
90135 -- n ;
91136 ++ bufs ;
92137 }
138+ if (flags & MP_MACHINE_I2C_FLAG_READ ) {
139+ /* 3. Main loop: remaining segments */
140+ for (; n -- ; ++ bufs ) {
141+ if (bufs -> len == 0 ) continue ;
142+ err = i2c_master_receive (dev_handle ,
143+ bufs -> buf ,
144+ //bufs->len,
145+ 1 ,
146+ 1000 );
147+ if (err != ESP_OK ) break ;
93148
94- i2c_master_start (cmd );
95- i2c_master_write_byte (cmd , addr << 1 | (flags & MP_MACHINE_I2C_FLAG_READ ), true);
149+ data_len += bufs -> len ;
150+ }
151+ } else {
152+ // Write operation logic
153+ size_t total_len = 0 ;
154+ mp_machine_i2c_buf_t * original_bufs = bufs ; // Save original pointer
155+ size_t yuann = n ;
96156
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- }
157+ // Calculate total length
158+ for (; n -- ; ++ bufs ) {
159+ total_len += bufs -> len ;
104160 }
105- data_len += bufs -> len ;
106- }
107161
108- if (flags & MP_MACHINE_I2C_FLAG_STOP ) {
109- i2c_master_stop (cmd );
110- }
162+ // Reset pointer
163+ bufs = original_bufs ;
164+ // Reset n
165+ n = yuann ;
166+ // Dynamically allocate write_buf
167+ uint8_t * write_buf = (uint8_t * )malloc (total_len );
168+ if (write_buf == NULL ) return - MP_ENOMEM ;
111169
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 );
170+ // Copy data into write_buf
171+ size_t index = 0 ;
172+ for (; n -- ; ++ bufs ) {
173+ memcpy (write_buf + index , bufs -> buf , bufs -> len );
174+ index += bufs -> len ;
175+ }
115176
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 );
177+ // Transmit data
178+ err = i2c_master_transmit ( dev_handle , write_buf , total_len , 1000 ) ;
179+ if (err != ESP_OK ) goto cleanup ;
180+
181+ // Free dynamically allocated memory
182+ free ( write_buf );
122183 }
123184
185+ cleanup :
186+ /* 4. Immediately destroy the temporary handle */
187+ i2c_master_bus_rm_device (dev_handle );
188+
189+ /* 5. Map errors */
190+ if (err == ESP_FAIL ) return - MP_ENODEV ;
191+ if (err == ESP_ERR_TIMEOUT ) return - MP_ETIMEDOUT ;
192+ if (err != ESP_OK ) return - abs (err );
193+
124194 return data_len ;
125195}
126196
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 ) {
197+ // ---------------- Print ----------------
198+ static void machine_hw_i2c_print ( const mp_print_t * print ,
199+ mp_obj_t self_in ,
200+ mp_print_kind_t kind ) {
131201 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 ));
202+ mp_printf (print , "I2C(%u, scl=%u, sda=%u)" ,
203+ self -> port , self -> scl , self -> sda );
136204}
137205
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 ) {
206+ // ---------------- Constructor ----------------
207+ mp_obj_t machine_hw_i2c_make_new (const mp_obj_type_t * type ,
208+ size_t n_args , size_t n_kw ,
209+ const mp_obj_t * all_args ) {
139210 // Create a SoftI2C instance if no id is specified (or is -1) but other arguments are given
140211 if (n_args != 0 ) {
141212 MP_MACHINE_I2C_CHECK_FOR_LEGACY_SOFTI2C_CONSTRUCTION (n_args , n_kw , all_args );
142213 }
143-
144- // Parse args
145214 enum { ARG_id , ARG_scl , ARG_sda , ARG_freq , ARG_timeout };
146215 static const mp_arg_t allowed_args [] = {
147216 { MP_QSTR_id , MP_ARG_INT , {.u_int = I2C_NUM_0 } },
@@ -151,48 +220,40 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_
151220 { MP_QSTR_timeout , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = I2C_DEFAULT_TIMEOUT_US } },
152221 };
153222 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 );
223+ mp_arg_parse_all_kw_array (n_args , n_kw , all_args ,
224+ MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
155225
156- // Get I2C bus
157226 mp_int_t i2c_id = args [ARG_id ].u_int ;
158-
159- // Check if the I2C bus is valid
160227 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 );
228+ mp_raise_msg_varg (& mp_type_ValueError ,
229+ MP_ERROR_TEXT ("I2C(%d) doesn't exist" ), i2c_id );
162230 }
163231
164- // Get static peripheral object
165- machine_hw_i2c_obj_t * self = (machine_hw_i2c_obj_t * )& machine_hw_i2c_obj [i2c_id ];
232+ machine_hw_i2c_obj_t * self = & machine_hw_i2c_obj [i2c_id ];
166233
167- bool first_init = false;
168- if (self -> base .type == NULL ) {
169- // Created for the first time, set default pins
234+ bool first_init = (self -> base .type == NULL );
235+ if (first_init ) {
170236 self -> base .type = & machine_i2c_type ;
171237 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;
238+ self -> scl = (i2c_id == I2C_NUM_0 ) ? MICROPY_HW_I2C0_SCL : MICROPY_HW_I2C1_SCL ;
239+ self -> sda = (i2c_id == I2C_NUM_0 ) ? MICROPY_HW_I2C0_SDA : MICROPY_HW_I2C1_SDA ;
180240 }
181241
182- // Set SCL/SDA pins if given
183242 if (args [ARG_scl ].u_obj != MP_OBJ_NULL ) {
184243 self -> scl = machine_pin_get_id (args [ARG_scl ].u_obj );
185244 }
186245 if (args [ARG_sda ].u_obj != MP_OBJ_NULL ) {
187246 self -> sda = machine_pin_get_id (args [ARG_sda ].u_obj );
188247 }
189248
190- // Initialise the I2C peripheral
191- machine_hw_i2c_init (self , args [ARG_freq ].u_int , args [ARG_timeout ].u_int , first_init );
192-
249+ machine_hw_i2c_init (self ,
250+ args [ARG_freq ].u_int ,
251+ args [ARG_timeout ].u_int ,
252+ first_init );
193253 return MP_OBJ_FROM_PTR (self );
194254}
195255
256+ // ---------------- Protocol table ----------------
196257static const mp_machine_i2c_p_t machine_hw_i2c_p = {
197258 .transfer_supports_write1 = true,
198259 .transfer = machine_hw_i2c_transfer ,
@@ -206,6 +267,6 @@ MP_DEFINE_CONST_OBJ_TYPE(
206267 print , machine_hw_i2c_print ,
207268 protocol , & machine_hw_i2c_p ,
208269 locals_dict , & mp_machine_i2c_locals_dict
209- );
270+ );
210271
211- #endif
272+ #endif // MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
0 commit comments