3030#include "extmod/modmachine.h"
3131#include "machine_i2c.h"
3232
33- #include "driver/i2c_master .h"
33+ #include "driver/i2c .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 ----------------
5352typedef struct _machine_hw_i2c_obj_t {
5453 mp_obj_base_t base ;
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 ;
54+ i2c_port_t port : 8 ;
55+ gpio_num_t scl : 8 ;
56+ gpio_num_t sda : 8 ;
6057} machine_hw_i2c_obj_t ;
6158
6259static machine_hw_i2c_obj_t machine_hw_i2c_obj [I2C_NUM_MAX ];
6360
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, first remove the old driver
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 ;
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 );
7664 }
77-
78- // 2. Configure the bus
79- i2c_master_bus_config_t bus_cfg = {
80- .i2c_port = self -> port ,
81- .scl_io_num = self -> scl ,
65+ i2c_config_t conf = {
66+ .mode = I2C_MODE_MASTER ,
8267 .sda_io_num = self -> sda ,
83- .clk_source = I2C_CLK_SRC_DEFAULT ,
84- .glitch_ignore_cnt = 7 ,
85- .flags .enable_internal_pullup = true,
86- };
87- ESP_ERROR_CHECK (i2c_new_master_bus (& bus_cfg , & self -> bus_handle ));
88-
89- // 3. Add device (placeholder address, dynamically changed later during actual transmission)
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 ,
68+ .sda_pullup_en = GPIO_PULLUP_ENABLE ,
69+ .scl_io_num = self -> scl ,
70+ .scl_pullup_en = GPIO_PULLUP_ENABLE ,
71+ .master .clk_speed = freq ,
9472 };
95- ESP_ERROR_CHECK (i2c_master_bus_add_device (self -> bus_handle , & dev_cfg , & self -> dev_handle ));
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 );
9677}
9778
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- {
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 ) {
10480 machine_hw_i2c_obj_t * self = MP_OBJ_TO_PTR (self_in );
10581
106- /* 0. First, probe the address to see if a 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 directly */
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 the 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-
82+ i2c_cmd_handle_t cmd = i2c_cmd_link_create ();
12383 int data_len = 0 ;
12484
125- /* 2. If there is a WRITE1 segment, write it first */
12685 if (flags & MP_MACHINE_I2C_FLAG_WRITE1 ) {
127- if (bufs -> len ) {
128- err = i2c_master_transmit (dev_handle ,
129- bufs -> buf ,
130- bufs -> len ,
131- 1000 ); /* Blocking timeout 1 s */
132- if (err != ESP_OK ) goto cleanup ;
133- }
86+ i2c_master_start (cmd );
87+ i2c_master_write_byte (cmd , addr << 1 , true);
88+ i2c_master_write (cmd , bufs -> buf , bufs -> len , true);
13489 data_len += bufs -> len ;
13590 -- n ;
13691 ++ bufs ;
13792 }
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 ;
148-
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 the original pointer
155- size_t old_n = n ;
15693
157- // Calculate total length
158- for (; n -- ; ++ bufs ) {
159- total_len += bufs -> len ;
160- }
161-
162- // Reset pointer
163- bufs = original_bufs ;
164- // Reset n
165- n = old_n ;
166- // Dynamically allocate write_buf
167- uint8_t * write_buf = (uint8_t * )malloc (total_len );
168- if (write_buf == NULL ) return - MP_ENOMEM ;
94+ i2c_master_start (cmd );
95+ i2c_master_write_byte (cmd , addr << 1 | (flags & MP_MACHINE_I2C_FLAG_READ ), true);
16996
170- // Copy data to write_buf
171- size_t index = 0 ;
172- for (; n -- ; ++ bufs ) {
173- memcpy (write_buf + index , bufs -> buf , bufs -> len );
174- index += bufs -> len ;
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+ }
175104 }
105+ data_len += bufs -> len ;
106+ }
176107
177- // Send 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 );
108+ if (flags & MP_MACHINE_I2C_FLAG_STOP ) {
109+ i2c_master_stop (cmd );
183110 }
184111
185- cleanup :
186- /* 4. Immediately destroy the temporary handle */
187- i2c_master_bus_rm_device ( dev_handle );
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 );
188115
189- /* 5. Error mapping */
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 );
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 );
122+ }
193123
194124 return data_len ;
195125}
196126
197- // ---------------- Printing ----------------
198- static void machine_hw_i2c_print ( const mp_print_t * print ,
199- mp_obj_t self_in ,
200- mp_print_kind_t kind ) {
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 ) {
201131 machine_hw_i2c_obj_t * self = MP_OBJ_TO_PTR (self_in );
202- mp_printf (print , "I2C(%u, scl=%u, sda=%u)" ,
203- self -> port , self -> scl , self -> sda );
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 ));
204136}
205137
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 ) {
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 ) {
210139 // Create a SoftI2C instance if no id is specified (or is -1) but other arguments are given
211140 if (n_args != 0 ) {
212141 MP_MACHINE_I2C_CHECK_FOR_LEGACY_SOFTI2C_CONSTRUCTION (n_args , n_kw , all_args );
213142 }
143+
144+ // Parse args
214145 enum { ARG_id , ARG_scl , ARG_sda , ARG_freq , ARG_timeout };
215146 static const mp_arg_t allowed_args [] = {
216147 { MP_QSTR_id , MP_ARG_INT , {.u_int = I2C_NUM_0 } },
@@ -220,40 +151,48 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type,
220151 { MP_QSTR_timeout , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = I2C_DEFAULT_TIMEOUT_US } },
221152 };
222153 mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
223- mp_arg_parse_all_kw_array (n_args , n_kw , all_args ,
224- MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
154+ mp_arg_parse_all_kw_array (n_args , n_kw , all_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
225155
156+ // Get I2C bus
226157 mp_int_t i2c_id = args [ARG_id ].u_int ;
158+
159+ // Check if the I2C bus is valid
227160 if (!(I2C_NUM_0 <= i2c_id && i2c_id < I2C_NUM_MAX )) {
228- mp_raise_msg_varg (& mp_type_ValueError ,
229- MP_ERROR_TEXT ("I2C(%d) doesn't exist" ), i2c_id );
161+ mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("I2C(%d) doesn't exist" ), i2c_id );
230162 }
231163
232- machine_hw_i2c_obj_t * self = & machine_hw_i2c_obj [i2c_id ];
164+ // Get static peripheral object
165+ machine_hw_i2c_obj_t * self = (machine_hw_i2c_obj_t * )& machine_hw_i2c_obj [i2c_id ];
233166
234- bool first_init = (self -> base .type == NULL );
235- if (first_init ) {
167+ bool first_init = false;
168+ if (self -> base .type == NULL ) {
169+ // Created for the first time, set default pins
236170 self -> base .type = & machine_i2c_type ;
237171 self -> port = i2c_id ;
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 ;
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;
240180 }
241181
182+ // Set SCL/SDA pins if given
242183 if (args [ARG_scl ].u_obj != MP_OBJ_NULL ) {
243184 self -> scl = machine_pin_get_id (args [ARG_scl ].u_obj );
244185 }
245186 if (args [ARG_sda ].u_obj != MP_OBJ_NULL ) {
246187 self -> sda = machine_pin_get_id (args [ARG_sda ].u_obj );
247188 }
248189
249- machine_hw_i2c_init (self ,
250- args [ARG_freq ].u_int ,
251- args [ARG_timeout ].u_int ,
252- first_init );
190+ // Initialise the I2C peripheral
191+ machine_hw_i2c_init (self , args [ARG_freq ].u_int , args [ARG_timeout ].u_int , first_init );
192+
253193 return MP_OBJ_FROM_PTR (self );
254194}
255195
256- // ---------------- Protocol Table ----------------
257196static const mp_machine_i2c_p_t machine_hw_i2c_p = {
258197 .transfer_supports_write1 = true,
259198 .transfer = machine_hw_i2c_transfer ,
@@ -267,6 +206,6 @@ MP_DEFINE_CONST_OBJ_TYPE(
267206 print , machine_hw_i2c_print ,
268207 protocol , & machine_hw_i2c_p ,
269208 locals_dict , & mp_machine_i2c_locals_dict
270- );
209+ );
271210
272- #endif // MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
211+ #endif
0 commit comments