diff --git a/stmhal/accel.c b/stmhal/accel.c
index 339a93ea403083df5fa2d357485fabadb9b9a976..47c7a1a4946c8248db8b83d637e00d3165749788 100644
--- a/stmhal/accel.c
+++ b/stmhal/accel.c
@@ -12,6 +12,8 @@
 #include "i2c.h"
 #include "accel.h"
 
+#if MICROPY_HW_HAS_MMA7660
+
 #define MMA_ADDR (0x98)
 #define MMA_REG_X (0)
 #define MMA_REG_Y (1)
@@ -174,3 +176,5 @@ const mp_obj_type_t pyb_accel_type = {
     .make_new = pyb_accel_make_new,
     .locals_dict = (mp_obj_t)&pyb_accel_locals_dict,
 };
+
+#endif // MICROPY_HW_HAS_MMA7660
diff --git a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h
index a626f4534bcb78e7d65915b351290f6eaa758628..b70b56d9ce7c42339cda5e8513c72824e3b072d7 100644
--- a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h
+++ b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h
@@ -17,8 +17,9 @@
 #define MICROPY_HW_ENABLE_TIMER     (1)
 #define MICROPY_HW_ENABLE_SERVO     (1)
 #define MICROPY_HW_ENABLE_DAC       (0)
-#define MICROPU_HW_ENABLE_I2C1      (0)
-#define MICROPU_HW_ENABLE_SPI1      (0)
+#define MICROPY_HW_ENABLE_I2C1      (0)
+#define MICROPY_HW_ENABLE_SPI1      (0)
+#define MICROPY_HW_ENABLE_SPI3      (0)
 
 // USRSW is pulled low. Pressing the button makes the input go high.
 #define MICROPY_HW_USRSW_PIN        (pin_B11)
diff --git a/stmhal/boards/PYBV10/mpconfigboard.h b/stmhal/boards/PYBV10/mpconfigboard.h
index 9386c04a2de27950c03b61e39f1f6d7de703f3b7..00c6a1acfc3a235bed041c8afd982f2a6c9be0a1 100644
--- a/stmhal/boards/PYBV10/mpconfigboard.h
+++ b/stmhal/boards/PYBV10/mpconfigboard.h
@@ -13,6 +13,9 @@
 #define MICROPY_HW_ENABLE_TIMER     (1)
 #define MICROPY_HW_ENABLE_SERVO     (1)
 #define MICROPY_HW_ENABLE_DAC       (1)
+#define MICROPY_HW_ENABLE_I2C1      (1)
+#define MICROPY_HW_ENABLE_SPI1      (1)
+#define MICROPY_HW_ENABLE_SPI3      (0)
 
 // USRSW has no pullup or pulldown, and pressing the switch makes the input go low
 #define MICROPY_HW_USRSW_PIN        (pin_B3)
diff --git a/stmhal/boards/PYBV3/mpconfigboard.h b/stmhal/boards/PYBV3/mpconfigboard.h
index f47a01bc4cfe63208168a3164af6a63a4ee27d5a..02ad78a64c0076718f1860a82c0376a4e0174f05 100644
--- a/stmhal/boards/PYBV3/mpconfigboard.h
+++ b/stmhal/boards/PYBV3/mpconfigboard.h
@@ -13,6 +13,9 @@
 #define MICROPY_HW_ENABLE_TIMER     (1)
 #define MICROPY_HW_ENABLE_SERVO     (1)
 #define MICROPY_HW_ENABLE_DAC       (0)
+#define MICROPY_HW_ENABLE_I2C1      (1)
+#define MICROPY_HW_ENABLE_SPI1      (1)
+#define MICROPY_HW_ENABLE_SPI3      (0)
 
 // USRSW has no pullup or pulldown, and pressing the switch makes the input go low
 #define MICROPY_HW_USRSW_PIN        (pin_A13)
diff --git a/stmhal/boards/PYBV4/mpconfigboard.h b/stmhal/boards/PYBV4/mpconfigboard.h
index 1846491c3aa9eddbb3a040ed9c252220ac83f66a..550f1633f9799a8eed2c4d53557915d5a931f426 100644
--- a/stmhal/boards/PYBV4/mpconfigboard.h
+++ b/stmhal/boards/PYBV4/mpconfigboard.h
@@ -13,6 +13,9 @@
 #define MICROPY_HW_ENABLE_TIMER     (1)
 #define MICROPY_HW_ENABLE_SERVO     (1)
 #define MICROPY_HW_ENABLE_DAC       (1)
+#define MICROPY_HW_ENABLE_I2C1      (1)
+#define MICROPY_HW_ENABLE_SPI1      (1)
+#define MICROPY_HW_ENABLE_SPI3      (0)
 
 // USRSW has no pullup or pulldown, and pressing the switch makes the input go low
 #define MICROPY_HW_USRSW_PIN        (pin_B3)
@@ -20,7 +23,7 @@
 #define MICROPY_HW_USRSW_EXTI_MODE  (GPIO_MODE_IT_FALLING)
 #define MICROPY_HW_USRSW_PRESSED    (0)
 
-// LEDs
+// The pyboard has 4 LEDs
 #define MICROPY_HW_LED1             (pin_A13) // red
 #define MICROPY_HW_LED2             (pin_A14) // green
 #define MICROPY_HW_LED3             (pin_A15) // yellow
diff --git a/stmhal/boards/STM32F4DISC/mpconfigboard.h b/stmhal/boards/STM32F4DISC/mpconfigboard.h
index 3bfdfbfb804e520ac02c87569e00c455900bf41d..c83bb162bba306d837ce9130c46ff3f6e570d028 100644
--- a/stmhal/boards/STM32F4DISC/mpconfigboard.h
+++ b/stmhal/boards/STM32F4DISC/mpconfigboard.h
@@ -13,6 +13,9 @@
 #define MICROPY_HW_ENABLE_TIMER     (1)
 #define MICROPY_HW_ENABLE_SERVO     (0)
 #define MICROPY_HW_ENABLE_DAC       (0)
+#define MICROPY_HW_ENABLE_I2C1      (1)
+#define MICROPY_HW_ENABLE_SPI1      (1)
+#define MICROPY_HW_ENABLE_SPI3      (0)
 
 // USRSW is pulled low. Pressing the button makes the input go high.
 #define MICROPY_HW_USRSW_PIN        (pin_A0)
diff --git a/stmhal/i2c.c b/stmhal/i2c.c
index 4d2710d8e5d0f229fb575df7d9d385727b60d6d2..e1dd83d2f808e1ad15cd20ea1d0bf71439c0ff44 100644
--- a/stmhal/i2c.c
+++ b/stmhal/i2c.c
@@ -13,17 +13,17 @@
 #include "genhdr/pins.h"
 #include "i2c.h"
 
-#if !defined(MICROPU_HW_ENABLE_I2C1)
-#define MICROPY_HW_ENABLE_I2C1      (1)
-#endif
-
+#if MICROPY_HW_ENABLE_I2C1
 I2C_HandleTypeDef I2CHandle1 = {.Instance = NULL};
+#endif
 I2C_HandleTypeDef I2CHandle2 = {.Instance = NULL};
 
 void i2c_init0(void) {
     // reset the I2C1 handles
+#if MICROPY_HW_ENABLE_I2C1
     memset(&I2CHandle1, 0, sizeof(I2C_HandleTypeDef));
     I2CHandle1.Instance = I2C1;
+#endif
     memset(&I2CHandle2, 0, sizeof(I2C_HandleTypeDef));
     I2CHandle2.Instance = I2C2;
 }
@@ -36,23 +36,26 @@ void i2c_init(I2C_HandleTypeDef *i2c) {
     GPIO_InitStructure.Pull = GPIO_NOPULL; // have external pull-up resistors on both lines
 
     const pin_obj_t *pins[2];
+    if (0) {
 #if MICROPY_HW_ENABLE_I2C1
-    if (i2c == &I2CHandle1) {
+    } else if (i2c == &I2CHandle1) {
         // X-skin: X9=PB6=SCL, X10=PB7=SDA
         pins[0] = &pin_B6;
         pins[1] = &pin_B7;
         GPIO_InitStructure.Alternate = GPIO_AF4_I2C1;
         // enable the I2C clock
         __I2C1_CLK_ENABLE();
-    } else
 #endif
-    if (i2c == &I2CHandle2) {
+    } else if (i2c == &I2CHandle2) {
         // Y-skin: Y9=PB10=SCL, Y10=PB11=SDA
         pins[0] = &pin_B10;
         pins[1] = &pin_B11;
         GPIO_InitStructure.Alternate = GPIO_AF4_I2C2;
         // enable the I2C clock
         __I2C2_CLK_ENABLE();
+    } else {
+        // I2C does not exist for this board (shouldn't get here, should be checked by caller)
+        return;
     }
 
     // init the GPIO lines
@@ -73,6 +76,8 @@ void i2c_init(I2C_HandleTypeDef *i2c) {
 
     if (HAL_I2C_Init(i2c) != HAL_OK) {
         // init error
+        // TODO should raise an exception, but this function is not necessarily going to be
+        // called via Python, so may not be properly wrapped in an NLR handler
         printf("HardwareError: HAL_I2C_Init failed\n");
         return;
     }
@@ -81,17 +86,20 @@ void i2c_init(I2C_HandleTypeDef *i2c) {
 /******************************************************************************/
 /* Micro Python bindings                                                      */
 
-#define PYB_NUM_I2C (2)
-
 typedef struct _pyb_i2c_obj_t {
     mp_obj_base_t base;
     I2C_HandleTypeDef *i2c;
 } pyb_i2c_obj_t;
 
-STATIC const pyb_i2c_obj_t pyb_i2c_obj[PYB_NUM_I2C] = {
+STATIC const pyb_i2c_obj_t pyb_i2c_obj[] = {
+#if MICROPY_HW_ENABLE_I2C1
     {{&pyb_i2c_type}, &I2CHandle1},
+#else
+    {{&pyb_i2c_type}, NULL},
+#endif
     {{&pyb_i2c_type}, &I2CHandle2}
 };
+#define PYB_NUM_I2C (sizeof(pyb_i2c_obj) / sizeof(pyb_i2c_obj[0]))
 
 STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
     // check arguments
@@ -101,7 +109,7 @@ STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
     machine_int_t i2c_id = mp_obj_get_int(args[0]) - 1;
 
     // check i2c number
-    if (!(0 <= i2c_id && i2c_id < PYB_NUM_I2C)) {
+    if (!(0 <= i2c_id && i2c_id < PYB_NUM_I2C && pyb_i2c_obj[i2c_id].i2c != NULL)) {
         nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "I2C bus %d does not exist", i2c_id + 1));
     }
 
diff --git a/stmhal/spi.c b/stmhal/spi.c
index 5e5049bef96edf1a0ba79757bb14a9b89bce4e86..b16cd83c8bf891fa7c45c3b0a4e7dac1a09b855d 100644
--- a/stmhal/spi.c
+++ b/stmhal/spi.c
@@ -13,22 +13,26 @@
 #include "genhdr/pins.h"
 #include "spi.h"
 
-#if !defined(MICROPU_HW_ENABLE_SPI1)
-#define MICROPY_HW_ENABLE_SPI1  (1)
-#endif
-
+#if MICROPY_HW_ENABLE_SPI1
 SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL};
+#endif
 SPI_HandleTypeDef SPIHandle2 = {.Instance = NULL};
+#if MICROPY_HW_ENABLE_SPI3
 SPI_HandleTypeDef SPIHandle3 = {.Instance = NULL};
+#endif
 
 void spi_init0(void) {
     // reset the SPI handles
+#if MICROPY_HW_ENABLE_SPI1
     memset(&SPIHandle1, 0, sizeof(SPI_HandleTypeDef));
     SPIHandle1.Instance = SPI1;
+#endif
     memset(&SPIHandle2, 0, sizeof(SPI_HandleTypeDef));
     SPIHandle2.Instance = SPI2;
+#if MICROPY_HW_ENABLE_SPI3
     memset(&SPIHandle3, 0, sizeof(SPI_HandleTypeDef));
     SPIHandle3.Instance = SPI3;
+#endif
 }
 
 // TODO allow to take a list of pins to use
@@ -40,36 +44,40 @@ void spi_init(SPI_HandleTypeDef *spi) {
     GPIO_InitStructure.Pull = GPIO_PULLUP; // ST examples use PULLUP
 
     const pin_obj_t *pins[4];
+    if (0) {
 #if MICROPY_HW_ENABLE_SPI1
-    if (spi->Instance == SPI1) {
+    } else if (spi->Instance == SPI1) {
         // X-skin: X5=PA4=SPI1_NSS, X6=PA5=SPI1_SCK, X7=PA6=SPI1_MISO, X8=PA7=SPI1_MOSI
         pins[0] = &pin_A4;
         pins[1] = &pin_A5;
         pins[2] = &pin_A6;
         pins[3] = &pin_A7;
         GPIO_InitStructure.Alternate = GPIO_AF5_SPI1;
-    } else
+        // enable the SPI clock
+        __SPI1_CLK_ENABLE();
 #endif
-    if (spi->Instance == SPI2) {
+    } else if (spi->Instance == SPI2) {
         // Y-skin: Y5=PB12=SPI2_NSS, Y6=PB13=SPI2_SCK, Y7=PB14=SPI2_MISO, Y8=PB15=SPI2_MOSI
         pins[0] = &pin_B12;
         pins[1] = &pin_B13;
         pins[2] = &pin_B14;
         pins[3] = &pin_B15;
         GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
-    } else
+        // enable the SPI clock
+        __SPI2_CLK_ENABLE();
 #if MICROPY_HW_ENABLE_SPI3
-    if (spi->Instance == SPI3) {
+    } else if (spi->Instance == SPI3) {
         pins[0] = &pin_A4;
         pins[1] = &pin_B3;
         pins[2] = &pin_B4;
         pins[3] = &pin_B5;
         GPIO_InitStructure.Alternate = GPIO_AF6_SPI3;
-    } else
+        // enable the SPI clock
+        __SPI3_CLK_ENABLE();
 #endif
-    {
-        // SPI does not exist for this board
-        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "SPI bus does not exist"));
+    } else {
+        // SPI does not exist for this board (shouldn't get here, should be checked by caller)
+        return;
     }
 
     for (uint i = 0; i < 4; i++) {
@@ -77,16 +85,7 @@ void spi_init(SPI_HandleTypeDef *spi) {
         HAL_GPIO_Init(pins[i]->gpio, &GPIO_InitStructure);
     }
 
-    // enable the SPI clock
-    if (spi->Instance == SPI1) {
-        __SPI1_CLK_ENABLE();
-    } else if (spi->Instance == SPI2) {
-        __SPI2_CLK_ENABLE();
-    } else if (spi->Instance == SPI3) {
-        __SPI3_CLK_ENABLE();
-    }
-
-    // init the I2C device
+    // init the SPI device
     if (HAL_SPI_Init(spi) != HAL_OK) {
         // init error
         // TODO should raise an exception, but this function is not necessarily going to be
@@ -98,29 +97,42 @@ void spi_init(SPI_HandleTypeDef *spi) {
 
 void spi_deinit(SPI_HandleTypeDef *spi) {
     HAL_SPI_DeInit(spi);
-    if (spi->Instance == SPI1) {
+    if (0) {
+#if MICROPY_HW_ENABLE_SPI1
+    } else if (spi->Instance == SPI1) {
         __SPI1_CLK_DISABLE();
+#endif
     } else if (spi->Instance == SPI2) {
         __SPI2_CLK_DISABLE();
+#if MICROPY_HW_ENABLE_SPI3
     } else if (spi->Instance == SPI3) {
         __SPI3_CLK_DISABLE();
+#endif
     }
 }
 
 /******************************************************************************/
 /* Micro Python bindings                                                      */
 
-#define PYB_NUM_SPI (2)
-
 typedef struct _pyb_spi_obj_t {
     mp_obj_base_t base;
     SPI_HandleTypeDef *spi;
 } pyb_spi_obj_t;
 
-STATIC const pyb_spi_obj_t pyb_spi_obj[PYB_NUM_SPI] = {
+STATIC const pyb_spi_obj_t pyb_spi_obj[] = {
+#if MICROPY_HW_ENABLE_SPI1
     {{&pyb_spi_type}, &SPIHandle1},
-    {{&pyb_spi_type}, &SPIHandle2}
+#else
+    {{&pyb_spi_type}, NULL},
+#endif
+    {{&pyb_spi_type}, &SPIHandle2},
+#if MICROPY_HW_ENABLE_SPI3
+    {{&pyb_spi_type}, &SPIHandle3},
+#else
+    {{&pyb_spi_type}, NULL},
+#endif
 };
+#define PYB_NUM_SPI (sizeof(pyb_spi_obj) / sizeof(pyb_spi_obj[0]))
 
 STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
     pyb_spi_obj_t *self = self_in;
@@ -223,7 +235,7 @@ STATIC mp_obj_t pyb_spi_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
     machine_int_t spi_id = mp_obj_get_int(args[0]) - 1;
 
     // check SPI number
-    if (!(0 <= spi_id && spi_id < PYB_NUM_SPI)) {
+    if (!(0 <= spi_id && spi_id < PYB_NUM_SPI && pyb_spi_obj[spi_id].spi != NULL)) {
         nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "SPI bus %d does not exist", spi_id + 1));
     }