extmod/machine_i2c: Add support for the addrsize parameter in mem xfers.

The memory read/write I2C functions now take an optional keyword-only
parameter that specifies the number of bits in the memory address.
Only mem-addrs that are a multiple of 8-bits are supported (otherwise
the behaviour is undefined).

Due to the integer type used for the address, for values larger than 32
bits, only 32 bits of address will be sent, and the rest will be padded
with 0s. Right now no exception is raised when that happens. For values
smaller than 8, no address is sent. Also no exception then.

Tested with a VL6180 sensor, which has 16-bit register addresses.

Due to code refactoring, this patch reduces stmhal and esp8266 builds
by about 50 bytes.
This commit is contained in:
Radomir Dopieralski 2016-09-19 20:53:08 +02:00 committed by Damien George
parent 7165fbd8f4
commit 219245e10f
2 changed files with 64 additions and 75 deletions

View File

@ -170,8 +170,7 @@ methods are convenience functions to communicate with such devices.
Read `nbytes` from the slave specified by `addr` starting from the memory
address specified by `memaddr`.
The argument `addrsize` specifies the address size in bits (on ESP8266
this argument is not recognised and the address size is always 8 bits).
The argument `addrsize` specifies the address size in bits.
Returns a `bytes` object with the data read.
.. method:: I2C.readfrom_mem_into(addr, memaddr, buf, \*, addrsize=8)

View File

@ -128,24 +128,6 @@ STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) {
return !ret;
}
STATIC void mp_hal_i2c_write(machine_i2c_obj_t *self, uint8_t addr, uint8_t *data, size_t len) {
mp_hal_i2c_start(self);
if (!mp_hal_i2c_write_byte(self, addr << 1)) {
goto er;
}
while (len--) {
if (!mp_hal_i2c_write_byte(self, *data++)) {
goto er;
}
}
mp_hal_i2c_stop(self);
return;
er:
mp_hal_i2c_stop(self);
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
}
STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack) {
mp_hal_i2c_delay(self);
mp_hal_i2c_scl_low(self);
@ -172,33 +154,27 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
return 1; // success
}
STATIC void mp_hal_i2c_read(machine_i2c_obj_t *self, uint8_t addr, uint8_t *data, size_t len) {
mp_hal_i2c_start(self);
if (!mp_hal_i2c_write_byte(self, (addr << 1) | 1)) {
goto er;
// addr is the device address, memaddr is a memory address sent big-endian
STATIC int mp_hal_i2c_write_addresses(machine_i2c_obj_t *self, uint8_t addr,
uint32_t memaddr, uint8_t addrsize) {
if (!mp_hal_i2c_write_byte(self, addr << 1)) {
return 0; // error
}
while (len--) {
if (!mp_hal_i2c_read_byte(self, data++, len == 0)) {
goto er;
for (int16_t i = addrsize - 8; i >= 0; i -= 8) {
if (!mp_hal_i2c_write_byte(self, memaddr >> i)) {
return 0; // error
}
}
mp_hal_i2c_stop(self);
return;
er:
mp_hal_i2c_stop(self);
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
return 1; // success
}
STATIC void mp_hal_i2c_write_mem(machine_i2c_obj_t *self, uint8_t addr, uint16_t memaddr, const uint8_t *src, size_t len) {
STATIC void mp_hal_i2c_write_mem(machine_i2c_obj_t *self, uint8_t addr,
uint32_t memaddr, uint8_t addrsize, const uint8_t *src, size_t len) {
// start the I2C transaction
mp_hal_i2c_start(self);
// write the slave address and the memory address within the slave
if (!mp_hal_i2c_write_byte(self, addr << 1)) {
goto er;
}
if (!mp_hal_i2c_write_byte(self, memaddr)) {
if (!mp_hal_i2c_write_addresses(self, addr, memaddr, addrsize)) {
goto er;
}
@ -218,20 +194,30 @@ er:
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
}
STATIC void mp_hal_i2c_read_mem(machine_i2c_obj_t *self, uint8_t addr, uint16_t memaddr, uint8_t *dest, size_t len) {
STATIC void mp_hal_i2c_read_mem(machine_i2c_obj_t *self, uint8_t addr,
uint32_t memaddr, uint8_t addrsize, uint8_t *dest, size_t len) {
// start the I2C transaction
mp_hal_i2c_start(self);
// write the slave address and the memory address within the slave
if (!mp_hal_i2c_write_byte(self, addr << 1)) {
goto er;
}
if (!mp_hal_i2c_write_byte(self, memaddr)) {
goto er;
if (addrsize) {
// write the slave address and the memory address within the slave
if (!mp_hal_i2c_write_addresses(self, addr, memaddr, addrsize)) {
goto er;
}
// i2c_read will do a repeated start, and then read the I2C memory
mp_hal_i2c_start(self);
}
// i2c_read will do a repeated start, and then read the I2C memory
mp_hal_i2c_read(self, addr, dest, len);
if (!mp_hal_i2c_write_byte(self, (addr << 1) | 1)) {
goto er;
}
while (len--) {
if (!mp_hal_i2c_read_byte(self, dest++, len == 0)) {
goto er;
}
}
mp_hal_i2c_stop(self);
return;
er:
@ -239,6 +225,14 @@ er:
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
}
STATIC void mp_hal_i2c_write(machine_i2c_obj_t *self, uint8_t addr, const uint8_t *src, size_t len) {
mp_hal_i2c_write_mem(self, addr, 0, 0, src, len);
}
STATIC void mp_hal_i2c_read(machine_i2c_obj_t *self, uint8_t addr, uint8_t *dest, size_t len) {
mp_hal_i2c_read_mem(self, addr, 0, 0, dest, len);
}
/******************************************************************************/
// MicroPython bindings for I2C
@ -367,68 +361,64 @@ STATIC mp_obj_t machine_i2c_writeto(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_writeto_obj, machine_i2c_writeto);
STATIC const mp_arg_t machine_i2c_mem_allowed_args[] = {
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_arg, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
};
STATIC mp_obj_t machine_i2c_readfrom_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_addr, ARG_memaddr, ARG_n, ARG_addrsize };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_n, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
//{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, TODO
};
machine_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);
// create the buffer to store data into
vstr_t vstr;
vstr_init_len(&vstr, args[ARG_n].u_int);
vstr_init_len(&vstr, mp_obj_get_int(args[ARG_n].u_obj));
// do the transfer
mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int, (uint8_t*)vstr.buf, vstr.len);
mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int,
args[ARG_addrsize].u_int, (uint8_t*)vstr.buf, vstr.len);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_obj, 1, machine_i2c_readfrom_mem);
STATIC mp_obj_t machine_i2c_readfrom_mem_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
//{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, TODO
};
machine_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);
// get the buffer to store data into
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_WRITE);
// do the transfer
mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int, bufinfo.buf, bufinfo.len);
mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int,
args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_into_obj, 1, machine_i2c_readfrom_mem_into);
STATIC mp_obj_t machine_i2c_writeto_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
//{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, TODO
};
machine_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);
// get the buffer to write the data from
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ);
// do the transfer
mp_hal_i2c_write_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int, bufinfo.buf, bufinfo.len);
mp_hal_i2c_write_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int,
args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_mem_obj, 1, machine_i2c_writeto_mem);