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:
parent
7165fbd8f4
commit
219245e10f
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user