diff --git a/stmhal/boards/STM32F7DISC/mpconfigboard.h b/stmhal/boards/STM32F7DISC/mpconfigboard.h
index dee42cb689f43f6014d3b8c2dd1fe816417113cf..6a0d46bf4c7d1ee03b02f22f334ef7b40c963cd1 100644
--- a/stmhal/boards/STM32F7DISC/mpconfigboard.h
+++ b/stmhal/boards/STM32F7DISC/mpconfigboard.h
@@ -47,6 +47,19 @@ void STM32F7DISC_board_early_init(void);
 #define MICROPY_HW_I2C1_SCL         (pin_B8)
 #define MICROPY_HW_I2C1_SDA         (pin_B9)
 
+#define MICROPY_HW_I2C3_SCL         (pin_H7)
+#define MICROPY_HW_I2C3_SDA         (pin_H8)
+
+// The STM32F7 uses a TIMINGR register which is configured using an Excel
+// Spreadsheet from AN4235: http://www.st.com/web/en/catalog/tools/PF258335
+// We use an array of baudrates and corresponding TIMINGR values.
+//
+// The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant
+// defined in the STM32F7Cube file Drivers/BSP/STM32F746G-Discovery/stm32f7456g_discovery.h
+#define MICROPY_HW_I2C_BAUDRATE_TIMING  {{100000, 0x40912732}}
+#define MICROPY_HW_I2C_BAUDRATE_DEFAULT 100000
+#define MICROPY_HW_I2C_BAUDRATE_MAX     100000
+
 // USRSW is pulled low. Pressing the button makes the input go high.
 #define MICROPY_HW_USRSW_PIN        (pin_I11)
 #define MICROPY_HW_USRSW_PULL       (GPIO_NOPULL)
diff --git a/stmhal/boards/STM32F7DISC/pins.csv b/stmhal/boards/STM32F7DISC/pins.csv
index 37d0edaf3a106e503c9241e09990de3d0e67a14a..917214ae752a679d1104e6681d4a8b852599e0de 100644
--- a/stmhal/boards/STM32F7DISC/pins.csv
+++ b/stmhal/boards/STM32F7DISC/pins.csv
@@ -26,12 +26,16 @@ TP1,PH2
 TP2,PI8
 TP3,PH15
 AUDIO_INT,PD6
+AUDIO_SDA,PH8
+AUDIO_SCL,PH7
 EXT_SDA,PB9
 EXT_SCL,PB8
 EXT_RST,PG3
 SD_SW,PC13
 LCD_BL_CTRL,PK3
 LCD_INT,PI13
+LCD_SDA,PH8
+LCD_SCL,PH7
 OTG_FS_POWER,PD5
 OTG_FS_OVER_CURRENT,PD4
 OTG_HS_OVER_CURRENT,PE3
diff --git a/stmhal/i2c.c b/stmhal/i2c.c
index 59f3a4fe4bbf736c1612ac96f1b653087333823f..af37abf44c981355476fc755f670dacebdca033e 100644
--- a/stmhal/i2c.c
+++ b/stmhal/i2c.c
@@ -37,9 +37,21 @@
 #include "i2c.h"
 #include MICROPY_HAL_H
 
-#if !defined(STM32F7)
-// The STM32F7 has Timing, where the F4 has ClockSpeed and DutyCycle, so we
-// need to figure that out before we can enable i2c
+#if !defined(MICROPY_HW_I2C_BAUDRATE_DEFAULT)
+#define MICROPY_HW_I2C_BAUDRATE_DEFAULT 400000
+#endif
+
+#if !defined(MICROPY_HW_I2C_BAUDRATE_MAX)
+#define MICROPY_HW_I2C_BAUDRATE_MAX 400000
+#endif
+
+#if !defined(I2C_NOSTRETCH_DISABLE)
+// Assumes that the F7 firmware is newer, so the F4 firmware will eventually
+// catchup. I2C_NOSTRETCH_DISABLED was renamed to I2C_NOSTRETCH_DISABLE
+// in the F7 so we use the F7 constant and provide a backwards compatabilty
+// #define here.
+#define I2C_NOSTRETCH_DISABLE I2C_NOSTRETCH_DISABLED
+#endif
 
 /// \moduleref pyb
 /// \class I2C - a two-wire serial protocol
@@ -138,6 +150,50 @@ STATIC const pyb_i2c_obj_t pyb_i2c_obj[] = {
     #endif
 };
 
+#if defined(MICROPY_HW_I2C_BAUDRATE_TIMING)
+// The STM32F0, F3, and F7 use a TIMINGR register rather than ClockSpeed and
+// DutyCycle.
+
+STATIC const struct {
+    uint32_t    baudrate;
+    uint32_t    timing;
+} pyb_i2c_baudrate_timing[] = MICROPY_HW_I2C_BAUDRATE_TIMING;
+
+#define NUM_BAUDRATE_TIMINGS MP_ARRAY_SIZE(pyb_i2c_baudrate_timing)
+
+STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) {
+    for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) {
+        if (pyb_i2c_baudrate_timing[i].baudrate == baudrate) {
+            init->Timing = pyb_i2c_baudrate_timing[i].timing;
+            return;
+        }
+    }
+    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+                                            "Unsupported I2C baudrate: %lu", baudrate));
+}
+
+STATIC uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) {
+    for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) {
+        if (pyb_i2c_baudrate_timing[i].timing == init->Timing) {
+            return pyb_i2c_baudrate_timing[i].baudrate;
+        }
+    }
+    return 0;
+}
+
+#else
+
+STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) {
+    init->ClockSpeed = baudrate;
+    init->DutyCycle = I2C_DUTYCYCLE_16_9;
+}
+
+STATIC uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) {
+    return init->ClockSpeed;
+}
+
+#endif // MICROPY_HW_I2C_BAUDRATE_TIMING
+
 void i2c_init0(void) {
     // reset the I2C1 handles
     #if defined(MICROPY_HW_I2C1_SCL)
@@ -276,7 +332,7 @@ 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, self->i2c->Init.ClockSpeed);
+            mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, i2c_get_baudrate(&self->i2c->Init));
         } else {
             mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f);
         }
@@ -295,7 +351,7 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, mp_uint_t n_args,
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_mode,     MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
         { MP_QSTR_addr,     MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x12} },
-        { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
+        { 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} },
     };
 
@@ -313,13 +369,13 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, mp_uint_t n_args,
         init->OwnAddress1 = (args[1].u_int << 1) & 0xfe;
     }
 
+    i2c_set_baudrate(init, MIN(args[2].u_int, MICROPY_HW_I2C_BAUDRATE_MAX));
     init->AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
-    init->ClockSpeed      = MIN(args[2].u_int, 400000);
     init->DualAddressMode = I2C_DUALADDRESS_DISABLED;
-    init->DutyCycle       = I2C_DUTYCYCLE_16_9;
     init->GeneralCallMode = args[3].u_bool ? I2C_GENERALCALL_ENABLED : I2C_GENERALCALL_DISABLED;
     init->NoStretchMode   = I2C_NOSTRETCH_DISABLED;
-    init->OwnAddress2     = 0xfe; // unused
+    init->OwnAddress2     = 0; // unused
+    init->NoStretchMode   = I2C_NOSTRETCH_DISABLE;
 
     // init the I2C bus
     i2c_init(self->i2c);
@@ -753,5 +809,3 @@ const mp_obj_type_t pyb_i2c_type = {
     .make_new = pyb_i2c_make_new,
     .locals_dict = (mp_obj_t)&pyb_i2c_locals_dict,
 };
-
-#endif // STM32F7
diff --git a/stmhal/main.c b/stmhal/main.c
index ea385030bc299bb5f63ab861fb6052c5715436d2..c1d85f978a1752956a6f1d9e2936f2ca129f53b9 100644
--- a/stmhal/main.c
+++ b/stmhal/main.c
@@ -471,8 +471,8 @@ soft_reset:
     rng_init0();
 #endif
 
-#if !defined(STM32F7) // Temp hack
     i2c_init0();
+#if !defined(STM32F7) // Temp hack
     spi_init0();
 #endif
     pyb_usb_init0();
diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c
index c32a8cfc31ff1dc95418810d069e152e4214db64..dcc0f3da10e7bd988f7dd182936ee36990c1284b 100644
--- a/stmhal/modpyb.c
+++ b/stmhal/modpyb.c
@@ -589,8 +589,8 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
 #if defined(MICROPY_HW_LED1)
     { MP_OBJ_NEW_QSTR(MP_QSTR_LED), (mp_obj_t)&pyb_led_type },
 #endif
-#if !defined(STM32F7) // Temp hack
     { MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_i2c_type },
+#if !defined(STM32F7) // Temp hack
     { MP_OBJ_NEW_QSTR(MP_QSTR_SPI), (mp_obj_t)&pyb_spi_type },
 #endif
     { MP_OBJ_NEW_QSTR(MP_QSTR_UART), (mp_obj_t)&pyb_uart_type },