extmod/machine_i2c: Add init protocol method for generic I2C bindings.
Hardware I2C implementations must provide a .init() protocol method if they want to support reconfiguration. Otherwise the default is that i2c.init() raises an OSError (currently the case for all ports). mp_machine_soft_i2c_locals_dict is renamed to mp_machine_i2c_locals_dict to match the generic SPI bindings. Fixes issue #6623 (where calling .init() on a HW I2C would crash). Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
parent
3dcb551d89
commit
64180f0742
@ -300,45 +300,18 @@ STATIC int mp_machine_i2c_writeto(mp_obj_base_t *self, uint16_t addr, const uint
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings for I2C
|
||||
// MicroPython bindings for generic machine.I2C
|
||||
|
||||
STATIC void mp_machine_soft_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_machine_soft_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "SoftI2C(scl=" MP_HAL_PIN_FMT ", sda=" MP_HAL_PIN_FMT ", freq=%u)",
|
||||
mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda), 500000 / self->us_delay);
|
||||
}
|
||||
|
||||
STATIC void machine_i2c_obj_init_helper(machine_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_scl, ARG_sda, ARG_freq, ARG_timeout };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
|
||||
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
self->scl = mp_hal_get_pin_obj(args[ARG_scl].u_obj);
|
||||
self->sda = mp_hal_get_pin_obj(args[ARG_sda].u_obj);
|
||||
self->us_timeout = args[ARG_timeout].u_int;
|
||||
mp_hal_i2c_init(self, args[ARG_freq].u_int);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_machine_soft_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// create new soft I2C object
|
||||
machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t);
|
||||
self->base.type = &mp_machine_soft_i2c_type;
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
machine_i2c_obj_init_helper(self, n_args, args, &kw_args);
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t machine_i2c_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
machine_i2c_obj_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args);
|
||||
STATIC mp_obj_t machine_i2c_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
mp_obj_base_t *self = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]);
|
||||
mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t *)self->type->protocol;
|
||||
if (i2c_p->init == NULL) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("I2C operation not supported"));
|
||||
}
|
||||
i2c_p->init(self, n_args - 1, args + 1, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_init_obj, 1, machine_i2c_obj_init);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_init_obj, 1, machine_i2c_init);
|
||||
|
||||
STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) {
|
||||
mp_obj_base_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
@ -653,8 +626,45 @@ STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_readfrom_mem_into), MP_ROM_PTR(&machine_i2c_readfrom_mem_into_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_writeto_mem), MP_ROM_PTR(&machine_i2c_writeto_mem_obj) },
|
||||
};
|
||||
MP_DEFINE_CONST_DICT(mp_machine_i2c_locals_dict, machine_i2c_locals_dict_table);
|
||||
|
||||
MP_DEFINE_CONST_DICT(mp_machine_soft_i2c_locals_dict, machine_i2c_locals_dict_table);
|
||||
/******************************************************************************/
|
||||
// Implementation of soft I2C
|
||||
|
||||
STATIC void mp_machine_soft_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_machine_soft_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "SoftI2C(scl=" MP_HAL_PIN_FMT ", sda=" MP_HAL_PIN_FMT ", freq=%u)",
|
||||
mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda), 500000 / self->us_delay);
|
||||
}
|
||||
|
||||
STATIC void mp_machine_soft_i2c_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_scl, ARG_sda, ARG_freq, ARG_timeout };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
|
||||
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} },
|
||||
};
|
||||
|
||||
mp_machine_soft_i2c_obj_t *self = (mp_machine_soft_i2c_obj_t *)self_in;
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
self->scl = mp_hal_get_pin_obj(args[ARG_scl].u_obj);
|
||||
self->sda = mp_hal_get_pin_obj(args[ARG_sda].u_obj);
|
||||
self->us_timeout = args[ARG_timeout].u_int;
|
||||
mp_hal_i2c_init(self, args[ARG_freq].u_int);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_machine_soft_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// create new soft I2C object
|
||||
machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t);
|
||||
self->base.type = &mp_machine_soft_i2c_type;
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
mp_machine_soft_i2c_init(&self->base, n_args, args, &kw_args);
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
int mp_machine_soft_i2c_read(mp_obj_base_t *self_in, uint8_t *dest, size_t len, bool nack) {
|
||||
machine_i2c_obj_t *self = (machine_i2c_obj_t *)self_in;
|
||||
@ -684,6 +694,7 @@ int mp_machine_soft_i2c_write(mp_obj_base_t *self_in, const uint8_t *src, size_t
|
||||
}
|
||||
|
||||
STATIC const mp_machine_i2c_p_t mp_machine_soft_i2c_p = {
|
||||
.init = mp_machine_soft_i2c_init,
|
||||
.start = (int (*)(mp_obj_base_t *))mp_hal_i2c_start,
|
||||
.stop = (int (*)(mp_obj_base_t *))mp_hal_i2c_stop,
|
||||
.read = mp_machine_soft_i2c_read,
|
||||
@ -697,7 +708,7 @@ const mp_obj_type_t mp_machine_soft_i2c_type = {
|
||||
.print = mp_machine_soft_i2c_print,
|
||||
.make_new = mp_machine_soft_i2c_make_new,
|
||||
.protocol = &mp_machine_soft_i2c_p,
|
||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_soft_i2c_locals_dict,
|
||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_i2c_locals_dict,
|
||||
};
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_I2C
|
||||
|
@ -51,9 +51,12 @@ typedef struct _mp_machine_i2c_buf_t {
|
||||
} mp_machine_i2c_buf_t;
|
||||
|
||||
// I2C protocol
|
||||
// the first 4 methods can be NULL, meaning operation is not supported
|
||||
// transfer_single only needs to be set if transfer=mp_machine_i2c_transfer_adaptor
|
||||
// - init must be non-NULL
|
||||
// - start/stop/read/write can be NULL, meaning operation is not supported
|
||||
// - transfer must be non-NULL
|
||||
// - transfer_single only needs to be set if transfer=mp_machine_i2c_transfer_adaptor
|
||||
typedef struct _mp_machine_i2c_p_t {
|
||||
void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
int (*start)(mp_obj_base_t *obj);
|
||||
int (*stop)(mp_obj_base_t *obj);
|
||||
int (*read)(mp_obj_base_t *obj, uint8_t *dest, size_t len, bool nack);
|
||||
@ -71,7 +74,7 @@ typedef struct _mp_machine_soft_i2c_obj_t {
|
||||
} mp_machine_soft_i2c_obj_t;
|
||||
|
||||
extern const mp_obj_type_t mp_machine_soft_i2c_type;
|
||||
extern const mp_obj_dict_t mp_machine_soft_i2c_locals_dict;
|
||||
extern const mp_obj_dict_t mp_machine_i2c_locals_dict;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
@ -177,5 +177,5 @@ const mp_obj_type_t machine_hw_i2c_type = {
|
||||
.print = machine_hw_i2c_print,
|
||||
.make_new = machine_hw_i2c_make_new,
|
||||
.protocol = &machine_hw_i2c_p,
|
||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_soft_i2c_locals_dict,
|
||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_i2c_locals_dict,
|
||||
};
|
||||
|
@ -167,7 +167,7 @@ const mp_obj_type_t machine_hard_i2c_type = {
|
||||
.print = machine_hard_i2c_print,
|
||||
.make_new = machine_hard_i2c_make_new,
|
||||
.protocol = &machine_hard_i2c_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict,
|
||||
.locals_dict = (mp_obj_dict_t*)&mp_machine_i2c_locals_dict,
|
||||
};
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_I2C
|
||||
|
@ -273,7 +273,7 @@ const mp_obj_type_t machine_hard_i2c_type = {
|
||||
.print = machine_hard_i2c_print,
|
||||
.make_new = machine_hard_i2c_make_new,
|
||||
.protocol = &machine_hard_i2c_p,
|
||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_soft_i2c_locals_dict,
|
||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_i2c_locals_dict,
|
||||
};
|
||||
|
||||
#endif // MICROPY_HW_ENABLE_HW_I2C
|
||||
|
@ -134,5 +134,5 @@ const mp_obj_type_t machine_hard_i2c_type = {
|
||||
.print = machine_hard_i2c_print,
|
||||
.make_new = machine_hard_i2c_make_new,
|
||||
.protocol = &machine_hard_i2c_p,
|
||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_soft_i2c_locals_dict,
|
||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_i2c_locals_dict,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user