Skip to content

Commit 30adcd6

Browse files
committed
[update] extmod folder
1 parent 440d191 commit 30adcd6

29 files changed

+663
-343
lines changed

extmod/machine_i2c.c

Lines changed: 148 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -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

319352
STATIC 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

408440
STATIC 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

423454
STATIC 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

438468
STATIC 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
}
452481
STATIC 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+
454529
STATIC 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-
474545
STATIC 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

503566
STATIC 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

632695
const mp_obj_type_t machine_i2c_type = {

extmod/machine_i2c.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,24 @@
2828

2929
#include "py/obj.h"
3030

31+
#define MP_MACHINE_I2C_FLAG_READ (0x01) // if not set then it's a write
32+
#define MP_MACHINE_I2C_FLAG_STOP (0x02)
33+
34+
typedef struct _mp_machine_i2c_buf_t {
35+
size_t len;
36+
uint8_t *buf;
37+
} mp_machine_i2c_buf_t;
38+
3139
// I2C protocol
3240
// the first 4 methods can be NULL, meaning operation is not supported
41+
// transfer_single only needs to be set if transfer=mp_machine_i2c_transfer_adaptor
3342
typedef struct _mp_machine_i2c_p_t {
3443
int (*start)(mp_obj_base_t *obj);
3544
int (*stop)(mp_obj_base_t *obj);
3645
int (*read)(mp_obj_base_t *obj, uint8_t *dest, size_t len, bool nack);
3746
int (*write)(mp_obj_base_t *obj, const uint8_t *src, size_t len);
38-
int (*readfrom)(mp_obj_base_t *obj, uint16_t addr, uint8_t *dest, size_t len, bool stop);
39-
int (*writeto)(mp_obj_base_t *obj, uint16_t addr, const uint8_t *src, size_t len, bool stop);
47+
int (*transfer)(mp_obj_base_t *obj, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
48+
int (*transfer_single)(mp_obj_base_t *obj, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags);
4049
} mp_machine_i2c_p_t;
4150

4251
typedef struct _mp_machine_soft_i2c_obj_t {
@@ -50,7 +59,7 @@ typedef struct _mp_machine_soft_i2c_obj_t {
5059
extern const mp_obj_type_t machine_i2c_type;
5160
extern const mp_obj_dict_t mp_machine_soft_i2c_locals_dict;
5261

53-
int mp_machine_soft_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop);
54-
int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop);
62+
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);
63+
int mp_machine_soft_i2c_transfer(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
5564

5665
#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H

0 commit comments

Comments
 (0)