@@ -180,9 +180,9 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
180180}
181181
182182// return value:
183- // >=0 - number of acks received
183+ // >=0 - success; for read it's 0, for write it's number of acks received
184184// <0 - error, with errno being the negative of the return value
185- int mp_machine_soft_i2c_writeto (mp_obj_base_t * self_in , uint16_t addr , const uint8_t * src , size_t len , bool stop ) {
185+ int mp_machine_soft_i2c_transfer (mp_obj_base_t * self_in , uint16_t addr , size_t n , mp_machine_i2c_buf_t * bufs , unsigned int flags ) {
186186 machine_i2c_obj_t * self = (machine_i2c_obj_t * )self_in ;
187187
188188 // start the I2C transaction
@@ -192,7 +192,7 @@ int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uin
192192 }
193193
194194 // write the slave address
195- ret = mp_hal_i2c_write_byte (self , addr << 1 );
195+ ret = mp_hal_i2c_write_byte (self , ( addr << 1 ) | ( flags & MP_MACHINE_I2C_FLAG_READ ) );
196196 if (ret < 0 ) {
197197 return ret ;
198198 } else if (ret != 0 ) {
@@ -201,69 +201,102 @@ int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uin
201201 return - MP_ENODEV ;
202202 }
203203
204- // write the buffer to the I2C memory
205- int num_acks = 0 ;
206- while (len -- ) {
207- ret = mp_hal_i2c_write_byte (self , * src ++ );
208- if (ret < 0 ) {
209- return ret ;
210- } else if (ret != 0 ) {
211- // nack received, stop sending
212- break ;
204+ int transfer_ret = 0 ;
205+ for (; n -- ; ++ bufs ) {
206+ size_t len = bufs -> len ;
207+ uint8_t * buf = bufs -> buf ;
208+ if (flags & MP_MACHINE_I2C_FLAG_READ ) {
209+ // read bytes from the slave into the given buffer(s)
210+ while (len -- ) {
211+ ret = mp_hal_i2c_read_byte (self , buf ++ , (n | len ) == 0 );
212+ if (ret != 0 ) {
213+ return ret ;
214+ }
215+ }
216+ } else {
217+ // write bytes from the given buffer(s) to the slave
218+ while (len -- ) {
219+ ret = mp_hal_i2c_write_byte (self , * buf ++ );
220+ if (ret < 0 ) {
221+ return ret ;
222+ } else if (ret != 0 ) {
223+ // nack received, stop sending
224+ n = 0 ;
225+ break ;
226+ }
227+ ++ transfer_ret ; // count the number of acks
228+ }
213229 }
214- ++ num_acks ;
215230 }
216231
217232 // finish the I2C transaction
218- if (stop ) {
233+ if (flags & MP_MACHINE_I2C_FLAG_STOP ) {
219234 ret = mp_hal_i2c_stop (self );
220235 if (ret != 0 ) {
221236 return ret ;
222237 }
223238 }
224239
225- return num_acks ;
240+ return transfer_ret ;
226241}
227242
228- // return value:
229- // 0 - success
230- // <0 - error, with errno being the negative of the return value
231- int mp_machine_soft_i2c_readfrom (mp_obj_base_t * self_in , uint16_t addr , uint8_t * dest , size_t len , bool stop ) {
232- machine_i2c_obj_t * self = (machine_i2c_obj_t * )self_in ;
233-
234- // start the I2C transaction
235- int ret = mp_hal_i2c_start (self );
236- if (ret != 0 ) {
237- return ret ;
238- }
239-
240- // write the slave address
241- ret = mp_hal_i2c_write_byte (self , (addr << 1 ) | 1 );
242- if (ret < 0 ) {
243- return ret ;
244- } else if (ret != 0 ) {
245- // nack received, release the bus cleanly
246- mp_hal_i2c_stop (self );
247- return - MP_ENODEV ;
248- }
249-
250- // read the bytes from the slave
251- while (len -- ) {
252- ret = mp_hal_i2c_read_byte (self , dest ++ , len == 0 );
253- if (ret != 0 ) {
254- return ret ;
243+ /******************************************************************************/
244+ // Generic helper functions
245+
246+ // For use by ports that require a single buffer of data for a read/write transfer
247+ int mp_machine_i2c_transfer_adaptor (mp_obj_base_t * self , uint16_t addr , size_t n , mp_machine_i2c_buf_t * bufs , unsigned int flags ) {
248+ size_t len ;
249+ uint8_t * buf ;
250+ if (n == 1 ) {
251+ // Use given single buffer
252+ len = bufs [0 ].len ;
253+ buf = bufs [0 ].buf ;
254+ } else {
255+ // Combine buffers into a single one
256+ len = 0 ;
257+ for (size_t i = 0 ; i < n ; ++ i ) {
258+ len += bufs [i ].len ;
259+ }
260+ buf = m_new (uint8_t , len );
261+ if (!(flags & MP_MACHINE_I2C_FLAG_READ )) {
262+ len = 0 ;
263+ for (size_t i = 0 ; i < n ; ++ i ) {
264+ memcpy (buf + len , bufs [i ].buf , bufs [i ].len );
265+ len += bufs [i ].len ;
266+ }
255267 }
256268 }
257269
258- // finish the I2C transaction
259- if (stop ) {
260- ret = mp_hal_i2c_stop (self );
261- if (ret != 0 ) {
262- return ret ;
270+ mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
271+ int ret = i2c_p -> transfer_single (self , addr , len , buf , flags );
272+
273+ if (n > 1 ) {
274+ if (flags & MP_MACHINE_I2C_FLAG_READ ) {
275+ // Copy data from single buffer to individual ones
276+ len = 0 ;
277+ for (size_t i = 0 ; i < n ; ++ i ) {
278+ memcpy (bufs [i ].buf , buf + len , bufs [i ].len );
279+ len += bufs [i ].len ;
280+ }
263281 }
282+ m_del (uint8_t , buf , len );
264283 }
265284
266- return 0 ; // success
285+ return ret ;
286+ }
287+
288+ STATIC int mp_machine_i2c_readfrom (mp_obj_base_t * self , uint16_t addr , uint8_t * dest , size_t len , bool stop ) {
289+ mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
290+ mp_machine_i2c_buf_t buf = {.len = len , .buf = dest };
291+ unsigned int flags = MP_MACHINE_I2C_FLAG_READ | (stop ? MP_MACHINE_I2C_FLAG_STOP : 0 );
292+ return i2c_p -> transfer (self , addr , 1 , & buf , flags );
293+ }
294+
295+ STATIC int mp_machine_i2c_writeto (mp_obj_base_t * self , uint16_t addr , const uint8_t * src , size_t len , bool stop ) {
296+ mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
297+ mp_machine_i2c_buf_t buf = {.len = len , .buf = (uint8_t * )src };
298+ unsigned int flags = stop ? MP_MACHINE_I2C_FLAG_STOP : 0 ;
299+ return i2c_p -> transfer (self , addr , 1 , & buf , flags );
267300}
268301
269302/******************************************************************************/
@@ -318,11 +351,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_init_obj, 1, machine_i2c_obj_init);
318351
319352STATIC mp_obj_t machine_i2c_scan (mp_obj_t self_in ) {
320353 mp_obj_base_t * self = MP_OBJ_TO_PTR (self_in );
321- mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
322354 mp_obj_t list = mp_obj_new_list (0 , NULL );
323355 // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved
324356 for (int addr = 0x08 ; addr < 0x78 ; ++ addr ) {
325- int ret = i2c_p -> writeto (self , addr , NULL , 0 , true);
357+ int ret = mp_machine_i2c_writeto (self , addr , NULL , 0 , true);
326358 if (ret == 0 ) {
327359 mp_obj_list_append (list , MP_OBJ_NEW_SMALL_INT (addr ));
328360 }
@@ -407,12 +439,11 @@ MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_write_obj, machine_i2c_write);
407439
408440STATIC mp_obj_t machine_i2c_readfrom (size_t n_args , const mp_obj_t * args ) {
409441 mp_obj_base_t * self = (mp_obj_base_t * )MP_OBJ_TO_PTR (args [0 ]);
410- mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
411442 mp_int_t addr = mp_obj_get_int (args [1 ]);
412443 vstr_t vstr ;
413444 vstr_init_len (& vstr , mp_obj_get_int (args [2 ]));
414445 bool stop = (n_args == 3 ) ? true : mp_obj_is_true (args [3 ]);
415- int ret = i2c_p -> readfrom (self , addr , (uint8_t * )vstr .buf , vstr .len , stop );
446+ int ret = mp_machine_i2c_readfrom (self , addr , (uint8_t * )vstr .buf , vstr .len , stop );
416447 if (ret < 0 ) {
417448 mp_raise_OSError (- ret );
418449 }
@@ -422,12 +453,11 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_obj, 3, 4, machine_i2c_
422453
423454STATIC mp_obj_t machine_i2c_readfrom_into (size_t n_args , const mp_obj_t * args ) {
424455 mp_obj_base_t * self = (mp_obj_base_t * )MP_OBJ_TO_PTR (args [0 ]);
425- mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
426456 mp_int_t addr = mp_obj_get_int (args [1 ]);
427457 mp_buffer_info_t bufinfo ;
428458 mp_get_buffer_raise (args [2 ], & bufinfo , MP_BUFFER_WRITE );
429459 bool stop = (n_args == 3 ) ? true : mp_obj_is_true (args [3 ]);
430- int ret = i2c_p -> readfrom (self , addr , bufinfo .buf , bufinfo .len , stop );
460+ int ret = mp_machine_i2c_readfrom (self , addr , bufinfo .buf , bufinfo .len , stop );
431461 if (ret < 0 ) {
432462 mp_raise_OSError (- ret );
433463 }
@@ -437,12 +467,11 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_into_obj, 3, 4, machine
437467
438468STATIC mp_obj_t machine_i2c_writeto (size_t n_args , const mp_obj_t * args ) {
439469 mp_obj_base_t * self = (mp_obj_base_t * )MP_OBJ_TO_PTR (args [0 ]);
440- mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
441470 mp_int_t addr = mp_obj_get_int (args [1 ]);
442471 mp_buffer_info_t bufinfo ;
443472 mp_get_buffer_raise (args [2 ], & bufinfo , MP_BUFFER_READ );
444473 bool stop = (n_args == 3 ) ? true : mp_obj_is_true (args [3 ]);
445- int ret = i2c_p -> writeto (self , addr , bufinfo .buf , bufinfo .len , stop );
474+ int ret = mp_machine_i2c_writeto (self , addr , bufinfo .buf , bufinfo .len , stop );
446475 if (ret < 0 ) {
447476 mp_raise_OSError (- ret );
448477 }
@@ -451,53 +480,87 @@ STATIC mp_obj_t machine_i2c_writeto(size_t n_args, const mp_obj_t *args) {
451480}
452481STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (machine_i2c_writeto_obj , 3 , 4 , machine_i2c_writeto );
453482
483+ STATIC mp_obj_t machine_i2c_writevto (size_t n_args , const mp_obj_t * args ) {
484+ mp_obj_base_t * self = (mp_obj_base_t * )MP_OBJ_TO_PTR (args [0 ]);
485+ mp_int_t addr = mp_obj_get_int (args [1 ]);
486+
487+ // Get the list of data buffer(s) to write
488+ size_t nitems ;
489+ const mp_obj_t * items ;
490+ mp_obj_get_array (args [2 ], & nitems , (mp_obj_t * * )& items );
491+
492+ // Get the stop argument
493+ bool stop = (n_args == 3 ) ? true : mp_obj_is_true (args [3 ]);
494+
495+ // Extract all buffer data, skipping zero-length buffers
496+ size_t alloc = nitems == 0 ? 1 : nitems ;
497+ size_t nbufs = 0 ;
498+ mp_machine_i2c_buf_t * bufs = mp_local_alloc (alloc * sizeof (mp_machine_i2c_buf_t ));
499+ for (; nitems -- ; ++ items ) {
500+ mp_buffer_info_t bufinfo ;
501+ mp_get_buffer_raise (* items , & bufinfo , MP_BUFFER_READ );
502+ if (bufinfo .len > 0 ) {
503+ bufs [nbufs ].len = bufinfo .len ;
504+ bufs [nbufs ++ ].buf = bufinfo .buf ;
505+ }
506+ }
507+
508+ // Make sure there is at least one buffer, empty if needed
509+ if (nbufs == 0 ) {
510+ bufs [0 ].len = 0 ;
511+ bufs [0 ].buf = NULL ;
512+ nbufs = 1 ;
513+ }
514+
515+ // Do the I2C transfer
516+ mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
517+ int ret = i2c_p -> transfer (self , addr , nbufs , bufs , stop ? MP_MACHINE_I2C_FLAG_STOP : 0 );
518+ mp_local_free (bufs );
519+
520+ if (ret < 0 ) {
521+ mp_raise_OSError (- ret );
522+ }
523+
524+ // Return number of acks received
525+ return MP_OBJ_NEW_SMALL_INT (ret );
526+ }
527+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (machine_i2c_writevto_obj , 3 , 4 , machine_i2c_writevto );
528+
454529STATIC int read_mem (mp_obj_t self_in , uint16_t addr , uint32_t memaddr , uint8_t addrsize , uint8_t * buf , size_t len ) {
455530 mp_obj_base_t * self = (mp_obj_base_t * )MP_OBJ_TO_PTR (self_in );
456- mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
457531 uint8_t memaddr_buf [4 ];
458532 size_t memaddr_len = 0 ;
459533 for (int16_t i = addrsize - 8 ; i >= 0 ; i -= 8 ) {
460534 memaddr_buf [memaddr_len ++ ] = memaddr >> i ;
461535 }
462- int ret = i2c_p -> writeto (self , addr , memaddr_buf , memaddr_len , false);
536+ int ret = mp_machine_i2c_writeto (self , addr , memaddr_buf , memaddr_len , false);
463537 if (ret != memaddr_len ) {
464538 // must generate STOP
465- i2c_p -> writeto (self , addr , NULL , 0 , true);
539+ mp_machine_i2c_writeto (self , addr , NULL , 0 , true);
466540 return ret ;
467541 }
468- return i2c_p -> readfrom (self , addr , buf , len , true);
542+ return mp_machine_i2c_readfrom (self , addr , buf , len , true);
469543}
470544
471- #define MAX_MEMADDR_SIZE (4)
472- #define BUF_STACK_SIZE (12)
473-
474545STATIC int write_mem (mp_obj_t self_in , uint16_t addr , uint32_t memaddr , uint8_t addrsize , const uint8_t * buf , size_t len ) {
475546 mp_obj_base_t * self = (mp_obj_base_t * )MP_OBJ_TO_PTR (self_in );
476- mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
477547
478- // need some memory to create the buffer to send; try to use stack if possible
479- uint8_t buf2_stack [MAX_MEMADDR_SIZE + BUF_STACK_SIZE ];
480- uint8_t * buf2 ;
481- size_t buf2_alloc = 0 ;
482- if (len <= BUF_STACK_SIZE ) {
483- buf2 = buf2_stack ;
484- } else {
485- buf2_alloc = MAX_MEMADDR_SIZE + len ;
486- buf2 = m_new (uint8_t , buf2_alloc );
487- }
488-
489- // create the buffer to send
548+ // Create buffer with memory address
490549 size_t memaddr_len = 0 ;
550+ uint8_t memaddr_buf [4 ];
491551 for (int16_t i = addrsize - 8 ; i >= 0 ; i -= 8 ) {
492- buf2 [memaddr_len ++ ] = memaddr >> i ;
552+ memaddr_buf [memaddr_len ++ ] = memaddr >> i ;
493553 }
494- memcpy (buf2 + memaddr_len , buf , len );
495554
496- int ret = i2c_p -> writeto (self , addr , buf2 , memaddr_len + len , true);
497- if (buf2_alloc != 0 ) {
498- m_del (uint8_t , buf2 , buf2_alloc );
499- }
500- return ret ;
555+ // Create partial write buffers
556+ mp_machine_i2c_buf_t bufs [2 ] = {
557+ {.len = memaddr_len , .buf = memaddr_buf },
558+ {.len = len , .buf = (uint8_t * )buf },
559+ };
560+
561+ // Do I2C transfer
562+ mp_machine_i2c_p_t * i2c_p = (mp_machine_i2c_p_t * )self -> type -> protocol ;
563+ return i2c_p -> transfer (self , addr , 2 , bufs , MP_MACHINE_I2C_FLAG_STOP );
501564}
502565
503566STATIC const mp_arg_t machine_i2c_mem_allowed_args [] = {
@@ -584,6 +647,7 @@ STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = {
584647 { MP_ROM_QSTR (MP_QSTR_readfrom ), MP_ROM_PTR (& machine_i2c_readfrom_obj ) },
585648 { MP_ROM_QSTR (MP_QSTR_readfrom_into ), MP_ROM_PTR (& machine_i2c_readfrom_into_obj ) },
586649 { MP_ROM_QSTR (MP_QSTR_writeto ), MP_ROM_PTR (& machine_i2c_writeto_obj ) },
650+ { MP_ROM_QSTR (MP_QSTR_writevto ), MP_ROM_PTR (& machine_i2c_writevto_obj ) },
587651
588652 // memory operations
589653 { MP_ROM_QSTR (MP_QSTR_readfrom_mem ), MP_ROM_PTR (& machine_i2c_readfrom_mem_obj ) },
@@ -625,8 +689,7 @@ STATIC const mp_machine_i2c_p_t mp_machine_soft_i2c_p = {
625689 .stop = (int (* )(mp_obj_base_t * ))mp_hal_i2c_stop ,
626690 .read = mp_machine_soft_i2c_read ,
627691 .write = mp_machine_soft_i2c_write ,
628- .readfrom = mp_machine_soft_i2c_readfrom ,
629- .writeto = mp_machine_soft_i2c_writeto ,
692+ .transfer = mp_machine_soft_i2c_transfer ,
630693};
631694
632695const mp_obj_type_t machine_i2c_type = {
0 commit comments