stm32/i2c: Support setting the I2C TIMINGR value via keyword arg.
On MCUs that have an I2C TIMINGR register, this can now be explicitly set via the "timingr" keyword argument to the I2C constructor, for both machine.I2C and pyb.I2C. This allows to configure precise timing values when the defaults are inadequate.
This commit is contained in:
parent
ddc657658a
commit
c769da1aaa
|
@ -187,15 +187,24 @@ STATIC void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, u
|
|||
/******************************************************************************/
|
||||
/* MicroPython bindings for machine API */
|
||||
|
||||
#if defined(STM32F0) || defined(STM32F7)
|
||||
#define MACHINE_I2C_TIMINGR (1)
|
||||
#else
|
||||
#define MACHINE_I2C_TIMINGR (0)
|
||||
#endif
|
||||
|
||||
mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
enum { ARG_id, ARG_scl, ARG_sda, ARG_freq, ARG_timeout };
|
||||
enum { ARG_id, ARG_scl, ARG_sda, ARG_freq, ARG_timeout, ARG_timingr };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_sda, MP_ARG_KW_ONLY | 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 = I2C_POLL_DEFAULT_TIMEOUT_US} },
|
||||
#if MACHINE_I2C_TIMINGR
|
||||
{ MP_QSTR_timingr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
#endif
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
@ -241,6 +250,13 @@ mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz
|
|||
// initialise the I2C peripheral
|
||||
machine_hard_i2c_init(self, args[ARG_freq].u_int, args[ARG_timeout].u_int);
|
||||
|
||||
#if MACHINE_I2C_TIMINGR
|
||||
// If given, explicitly set the TIMINGR value
|
||||
if (args[ARG_timingr].u_obj != mp_const_none) {
|
||||
self->i2c->TIMINGR = mp_obj_get_int_truncated(args[ARG_timingr].u_obj);
|
||||
}
|
||||
#endif
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
|
|
|
@ -135,6 +135,8 @@ const pyb_i2c_obj_t pyb_i2c_obj[] = {
|
|||
// The STM32F0, F3, F7, H7 and L4 use a TIMINGR register rather than ClockSpeed and
|
||||
// DutyCycle.
|
||||
|
||||
#define PYB_I2C_TIMINGR (1)
|
||||
|
||||
#if defined(STM32F746xx)
|
||||
|
||||
// The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant
|
||||
|
@ -213,6 +215,8 @@ uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) {
|
|||
|
||||
#else
|
||||
|
||||
#define PYB_I2C_TIMINGR (0)
|
||||
|
||||
#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL)
|
||||
#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FULL)
|
||||
|
||||
|
@ -564,7 +568,15 @@ STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
|
|||
mp_printf(print, "I2C(%u)", i2c_num);
|
||||
} else {
|
||||
if (in_master_mode(self)) {
|
||||
mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, pyb_i2c_get_baudrate(self->i2c));
|
||||
mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u"
|
||||
#if PYB_I2C_TIMINGR
|
||||
", timingr=0x%08x"
|
||||
#endif
|
||||
")", i2c_num, pyb_i2c_get_baudrate(self->i2c)
|
||||
#if PYB_I2C_TIMINGR
|
||||
, self->i2c->Init.Timing
|
||||
#endif
|
||||
);
|
||||
} else {
|
||||
mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f);
|
||||
}
|
||||
|
@ -586,6 +598,9 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, co
|
|||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_HW_I2C_BAUDRATE_DEFAULT} },
|
||||
{ MP_QSTR_gencall, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
{ MP_QSTR_dma, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
#if PYB_I2C_TIMINGR
|
||||
{ MP_QSTR_timingr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
#endif
|
||||
};
|
||||
|
||||
// parse args
|
||||
|
@ -602,7 +617,16 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, co
|
|||
init->OwnAddress1 = (args[1].u_int << 1) & 0xfe;
|
||||
}
|
||||
|
||||
i2c_set_baudrate(init, MIN(args[2].u_int, MICROPY_HW_I2C_BAUDRATE_MAX));
|
||||
// Set baudrate or timing value (if supported)
|
||||
#if PYB_I2C_TIMINGR
|
||||
if (args[5].u_obj != mp_const_none) {
|
||||
init->Timing = mp_obj_get_int_truncated(args[5].u_obj);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
i2c_set_baudrate(init, MIN(args[2].u_int, MICROPY_HW_I2C_BAUDRATE_MAX));
|
||||
}
|
||||
|
||||
init->AddressingMode = I2C_ADDRESSINGMODE_7BIT;
|
||||
init->DualAddressMode = I2C_DUALADDRESS_DISABLED;
|
||||
init->GeneralCallMode = args[3].u_bool ? I2C_GENERALCALL_ENABLED : I2C_GENERALCALL_DISABLED;
|
||||
|
|
Loading…
Reference in New Issue