diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c
index 2aebb9426e63b54e5a34c4fcb06c42a68b51717b..b423ec1c8c216db49e43f03b59520d807c609374 100644
--- a/ports/stm32/machine_i2c.c
+++ b/ports/stm32/machine_i2c.c
@@ -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);
 }
 
diff --git a/ports/stm32/pyb_i2c.c b/ports/stm32/pyb_i2c.c
index 233cbba512f40e460915c9cb068c78e2da62dbac..8b816a25b135e66f9ef8e74e34b8ec23036b4fdd 100644
--- a/ports/stm32/pyb_i2c.c
+++ b/ports/stm32/pyb_i2c.c
@@ -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;