diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index f74180d39714f448a044f88b188d5bdebd170b60..e868d6de1bc755bf7394dcaf0e439af926af00bc 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -79,6 +79,7 @@ CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
 CFLAGS_MCU_l0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0plus -mcpu=cortex-m0plus
 CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
 CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
+CFLAGS_MCU_wb = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
 
 CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA)
 CFLAGS += -D$(CMSIS_MCU)
@@ -335,7 +336,7 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
 	hal_uart.c \
 	)
 
-ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l0 l4))
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l0 l4 wb))
 SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
 	ll_usb.c \
 	)
@@ -361,7 +362,7 @@ endif
 ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx))
     SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c)
 else
-ifneq ($(MCU_SERIES),$(filter $(MCU_SERIES),l0))
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 f4 f7 h7 l4))
     SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c)
 endif
 endif
diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c
index 2c7371e010e646a77a9f51901c24e228473f89c5..8a3f743fe71578ed046cc2cae5e667866396e64b 100644
--- a/ports/stm32/dma.c
+++ b/ports/stm32/dma.c
@@ -34,6 +34,18 @@
 #include "dma.h"
 #include "irq.h"
 
+#if defined(STM32WB)
+
+// DMA is currently not implemented for this MCU
+
+void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data) {
+}
+
+void dma_deinit(const dma_descr_t *dma_descr) {
+}
+
+#else
+
 #define DMA_IDLE_ENABLED()  (dma_idle.enabled != 0)
 #define DMA_SYSTICK_LOG2    (3)
 #define DMA_SYSTICK_MASK    ((1 << DMA_SYSTICK_LOG2) - 1)
@@ -919,3 +931,5 @@ void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_a
 }
 
 #endif
+
+#endif // defined(STM32WB)
diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h
index 6d07a94ed99af0af0adcd9b19f764004b1daebb4..5a17276a49de2517d6744f7c431440b5601e8d69 100644
--- a/ports/stm32/dma.h
+++ b/ports/stm32/dma.h
@@ -73,7 +73,7 @@ extern const dma_descr_t dma_I2C_2_RX;
 extern const dma_descr_t dma_I2C_1_TX;
 extern const dma_descr_t dma_I2C_1_RX;
 
-#elif defined(STM32L4)
+#elif defined(STM32L4) || defined(STM32WB)
 
 extern const dma_descr_t dma_ADC_1_RX;
 extern const dma_descr_t dma_ADC_2_RX;
diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c
index 9a7295995a82720bd0a613db450b30de6f0537db..836b0c5954de685ae480b6c5b2c6a8d6fdf107e9 100644
--- a/ports/stm32/extint.c
+++ b/ports/stm32/extint.c
@@ -91,7 +91,7 @@
 #define EXTI_SWIER_BB(line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, SWIER)) * 32) + ((line) * 4)))
 #endif
 
-#if defined(STM32L4)
+#if defined(STM32L4) || defined(STM32WB)
 // The L4 MCU supports 40 Events/IRQs lines of the type configurable and direct.
 // Here we only support configurable line types.  Details, see page 330 of RM0351, Rev 1.
 // The USB_FS_WAKUP event is a direct type and there is no support for it.
@@ -140,6 +140,7 @@ STATIC mp_obj_t pyb_extint_callback_arg[EXTI_NUM_VECTORS];
 
 STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
     #if defined(STM32F0) || defined(STM32L0)
+
     EXTI0_1_IRQn,  EXTI0_1_IRQn,  EXTI2_3_IRQn,  EXTI2_3_IRQn,
     EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn,
     EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn,
@@ -155,11 +156,19 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
     RTC_IRQn,
     ADC1_COMP_IRQn,
     ADC1_COMP_IRQn,
+
     #else
+
     EXTI0_IRQn,     EXTI1_IRQn,     EXTI2_IRQn,     EXTI3_IRQn,     EXTI4_IRQn,
     EXTI9_5_IRQn,   EXTI9_5_IRQn,   EXTI9_5_IRQn,   EXTI9_5_IRQn,   EXTI9_5_IRQn,
     EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn,
     EXTI15_10_IRQn,
+    #if defined(STM32WB)
+    PVD_PVM_IRQn,
+    RTC_Alarm_IRQn,
+    TAMP_STAMP_LSECSS_IRQn,
+    RTC_WKUP_IRQn,
+    #else
     #if defined(STM32L4)
     PVD_PVM_IRQn,
     #else
@@ -177,6 +186,8 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
     TAMP_STAMP_IRQn,
     RTC_WKUP_IRQn,
     #endif
+
+    #endif
 };
 
 // Set override_callback_obj to true if you want to unconditionally set the
@@ -285,7 +296,9 @@ void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_
         pyb_extint_callback_arg[line] = MP_OBJ_FROM_PTR(pin);
 
         // Route the GPIO to EXTI
+        #if !defined(STM32WB)
         __HAL_RCC_SYSCFG_CLK_ENABLE();
+        #endif
         SYSCFG->EXTICR[line >> 2] =
             (SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03))))
             | ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03)));
@@ -320,7 +333,9 @@ void extint_set(const pin_obj_t *pin, uint32_t mode) {
         pyb_extint_callback_arg[line] = MP_OBJ_FROM_PTR(pin);
 
         // Route the GPIO to EXTI
+        #if !defined(STM32WB)
         __HAL_RCC_SYSCFG_CLK_ENABLE();
+        #endif
         SYSCFG->EXTICR[line >> 2] =
             (SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03))))
             | ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03)));
@@ -358,12 +373,16 @@ void extint_enable(uint line) {
     if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) {
         #if defined(STM32H7)
         EXTI_D1->IMR1 |= (1 << line);
+        #elif defined(STM32WB)
+        EXTI->IMR1 |= (1 << line);
         #else
         EXTI->IMR |= (1 << line);
         #endif
     } else {
         #if defined(STM32H7)
         EXTI_D1->EMR1 |= (1 << line);
+        #elif defined(STM32WB)
+        EXTI->EMR1 |= (1 << line);
         #else
         EXTI->EMR |= (1 << line);
         #endif
@@ -388,6 +407,9 @@ void extint_disable(uint line) {
     #if defined(STM32H7)
     EXTI_D1->IMR1 &= ~(1 << line);
     EXTI_D1->EMR1 &= ~(1 << line);
+    #elif defined(STM32WB)
+    EXTI->IMR1 &= ~(1 << line);
+    EXTI->EMR1 &= ~(1 << line);
     #else
     EXTI->IMR &= ~(1 << line);
     EXTI->EMR &= ~(1 << line);
@@ -407,7 +429,7 @@ void extint_swint(uint line) {
         return;
     }
     // we need 0 to 1 transition to trigger the interrupt
-#if defined(STM32L4) || defined(STM32H7)
+#if defined(STM32L4) || defined(STM32H7) || defined(STM32WB)
     EXTI->SWIER1 &= ~(1 << line);
     EXTI->SWIER1 |= (1 << line);
 #else
@@ -485,7 +507,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj,  extint_obj_swint);
 /// \classmethod regs()
 /// Dump the values of the EXTI registers.
 STATIC mp_obj_t extint_regs(void) {
-    #if defined(STM32L4)
+    #if defined(STM32L4) || defined(STM32WB)
     printf("EXTI_IMR1   %08x\n", (unsigned int)EXTI->IMR1);
     printf("EXTI_IMR2   %08x\n", (unsigned int)EXTI->IMR2);
     printf("EXTI_EMR1   %08x\n", (unsigned int)EXTI->EMR1);
diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h
index d275087c9e28f866ec6a12e6c32d747ab4cd149a..907af53dc22b1daaef0f7376a54dda6b233f82b4 100644
--- a/ports/stm32/extint.h
+++ b/ports/stm32/extint.h
@@ -46,7 +46,7 @@
 #if defined(STM32F0) || defined(STM32L4)
 #define EXTI_RTC_TIMESTAMP      (19)
 #define EXTI_RTC_WAKEUP         (20)
-#elif defined(STM32H7)
+#elif defined(STM32H7) || defined(STM32WB)
 #define EXTI_RTC_TIMESTAMP      (18)
 #define EXTI_RTC_WAKEUP         (19)
 #else
diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c
index aff85f7e3798b083f442531b407051a983164523..58cc012793b5d8b2ea58292f928f26c7588ace3a 100644
--- a/ports/stm32/flash.c
+++ b/ports/stm32/flash.c
@@ -68,7 +68,7 @@ static const flash_layout_t flash_layout[] = {
     { 0x08040000, 0x40000, 3 },
 };
 
-#elif defined(STM32L0) || defined(STM32L4)
+#elif defined(STM32L0) || defined(STM32L4) || defined(STM32WB)
 
 static const flash_layout_t flash_layout[] = {
     { (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 },
@@ -122,7 +122,7 @@ static uint32_t get_page(uint32_t addr) {
 }
 #endif
 
-#elif defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)
+#elif (defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)) || defined(STM32WB)
 
 static uint32_t get_page(uint32_t addr) {
     return (addr - FLASH_BASE) / FLASH_PAGE_SIZE;
@@ -175,7 +175,7 @@ void flash_erase(uint32_t flash_dest, uint32_t num_word32) {
     EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
     EraseInitStruct.PageAddress = flash_dest;
     EraseInitStruct.NbPages     = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE;
-    #elif defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)
+    #elif (defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)) || defined(STM32WB)
     __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
     EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
     EraseInitStruct.Page        = get_page(flash_dest);
@@ -247,7 +247,7 @@ void flash_erase_it(uint32_t flash_dest, uint32_t num_word32) {
 */
 
 void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
-    #if defined(STM32L4)
+    #if defined(STM32L4) || defined(STM32WB)
 
     // program the flash uint64 by uint64
     for (int i = 0; i < num_word32 / 2; i++) {
diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c
index 0a5f417040f9f35f4c7a242a5383887091574c19..470f3d086061e437d7907ac01870ccb72642a178 100644
--- a/ports/stm32/flashbdev.c
+++ b/ports/stm32/flashbdev.c
@@ -105,7 +105,8 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k
 
 #elif defined(STM32L432xx) || \
       defined(STM32L451xx) || defined(STM32L452xx) || defined(STM32L462xx) || \
-      defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx)
+      defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx) || \
+      defined(STM32WB)
 
 // The STM32L4xx doesn't have CCRAM, so we use SRAM2 for this, although
 // actual location and size is defined by the linker script.
diff --git a/ports/stm32/machine_uart.c b/ports/stm32/machine_uart.c
index 92343ba6d713f9494f9385791649a444fa46ebdd..5dbc133310b1f0dca5b44c8aa388932f37cf2bc2 100644
--- a/ports/stm32/machine_uart.c
+++ b/ports/stm32/machine_uart.c
@@ -489,7 +489,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar);
 // uart.sendbreak()
 STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
     pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
-    #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7)
+    #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB)
     self->uartx->RQR = USART_RQR_SBKRQ; // write-only register
     #else
     self->uartx->CR1 |= USART_CR1_SBK;
diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c
index 8d6dbf4fec49d3ff30c0e7e208703f4448b49c58..e45f81479bfb5dc9508bfaf999eec91f6b958ff5 100644
--- a/ports/stm32/modmachine.c
+++ b/ports/stm32/modmachine.c
@@ -61,7 +61,7 @@
 #define RCC_CSR_BORRSTF RCC_CSR_PORRSTF
 #endif
 
-#if defined(STM32L4)
+#if defined(STM32L4) || defined(STM32WB)
 // L4 does not have a POR, so use BOR instead
 #define RCC_CSR_PORRSTF RCC_CSR_BORRSTF
 #endif
@@ -305,7 +305,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
         return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple);
     } else {
         // set
-        #if defined(STM32F0) || defined(STM32L0) || defined(STM32L4)
+        #if defined(STM32F0) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB)
         mp_raise_NotImplementedError("machine.freq set not supported yet");
         #else
         mp_int_t sysclk = mp_obj_get_int(args[0]);
diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h
index 63d4238020d9a35b22bf73d84a738618411d043a..121b64d03866085191cb23e12aa6638ef2d00384 100644
--- a/ports/stm32/mpconfigboard_common.h
+++ b/ports/stm32/mpconfigboard_common.h
@@ -202,6 +202,15 @@
 #define MICROPY_HW_MAX_TIMER (17)
 #define MICROPY_HW_MAX_UART (6)
 
+// Configuration for STM32WB series
+#elif defined(STM32WB)
+
+#define MP_HAL_UNIQUE_ID_ADDRESS (UID_BASE)
+#define PYB_EXTI_NUM_VECTORS (20)
+#define MICROPY_HW_MAX_I2C (3)
+#define MICROPY_HW_MAX_TIMER (17)
+#define MICROPY_HW_MAX_UART (1)
+
 #else
 #error Unsupported MCU series
 #endif
diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c
index fe7772cf68b3182ebe92d52c2a1c9bc656021a68..ec4590b06bb494d3bce46eabf13558c38193c200 100644
--- a/ports/stm32/mphalport.c
+++ b/ports/stm32/mphalport.c
@@ -122,7 +122,7 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) {
     #elif defined(STM32L0)
     #define AHBxENR IOPENR
     #define AHBxENR_GPIOAEN_Pos RCC_IOPENR_IOPAEN_Pos
-    #elif defined(STM32L4)
+    #elif defined(STM32L4) || defined(STM32WB)
     #define AHBxENR AHB2ENR
     #define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR_GPIOAEN_Pos
     #endif
diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c
index 067e4c176e518ba314b18d005bf23af54d22063f..68a8bfdaf340a2edc6e51d0f2a6f933a9864130b 100644
--- a/ports/stm32/powerctrl.c
+++ b/ports/stm32/powerctrl.c
@@ -76,7 +76,7 @@ void powerctrl_check_enter_bootloader(void) {
     if ((bl_addr & 0xfff) == 0 && (RCC->RCC_SR & RCC_SR_SFTRSTF)) {
         // Reset by NVIC_SystemReset with bootloader data set -> branch to bootloader
         RCC->RCC_SR = RCC_SR_RMVF;
-        #if defined(STM32F0) || defined(STM32F4) || defined(STM32L4)
+        #if defined(STM32F0) || defined(STM32F4) || defined(STM32L4) || defined(STM32WB)
         __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
         #endif
         uint32_t r0 = BL_STATE[0];
@@ -84,7 +84,7 @@ void powerctrl_check_enter_bootloader(void) {
     }
 }
 
-#if !defined(STM32F0) && !defined(STM32L0)
+#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32WB)
 
 // Assumes that PLL is used as the SYSCLK source
 int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai) {
@@ -158,7 +158,7 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk
 
 #endif
 
-#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4)
+#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) && !defined(STM32WB)
 
 STATIC uint32_t calc_ahb_div(uint32_t wanted_div) {
     if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; }
@@ -333,7 +333,7 @@ void powerctrl_enter_stop_mode(void) {
     __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);
     #endif
 
-    #if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4)
+    #if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) && !defined(STM32WB)
     // takes longer to wake but reduces stop current
     HAL_PWREx_EnableFlashPowerDown();
     #endif
@@ -380,6 +380,9 @@ void powerctrl_enter_stop_mode(void) {
     #if defined(STM32H7)
     while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) {
     }
+    #elif defined(STM32WB)
+    while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK) {
+    }
     #else
     while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) {
     }
@@ -450,7 +453,7 @@ void powerctrl_enter_standby_mode(void) {
     PWR->CR2 |= PWR_CR2_CWUPF6 | PWR_CR2_CWUPF5 | PWR_CR2_CWUPF4 | PWR_CR2_CWUPF3 | PWR_CR2_CWUPF2 | PWR_CR2_CWUPF1;
     #elif defined(STM32H7)
     // TODO
-    #elif defined(STM32L4)
+    #elif defined(STM32L4) || defined(STM32WB)
     // clear all wake-up flags
     PWR->SCR |= PWR_SCR_CWUF5 | PWR_SCR_CWUF4 | PWR_SCR_CWUF3 | PWR_SCR_CWUF2 | PWR_SCR_CWUF1;
     // TODO
diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c
index de7c9d88a734aba38d007b19682122abd2119b8f..8884f596ed0093b182269c7fa5bdc768f0b21601 100644
--- a/ports/stm32/powerctrlboot.c
+++ b/ports/stm32/powerctrlboot.c
@@ -131,4 +131,50 @@ void SystemClock_Config(void) {
     #endif
 }
 
+#elif defined(STM32WB)
+
+void SystemClock_Config(void) {
+    // Enable the 32MHz external oscillator
+    RCC->CR |= RCC_CR_HSEON;
+    while (!(RCC->CR & RCC_CR_HSERDY)) {
+    }
+
+    // Use HSE and the PLL to get a 64MHz SYSCLK
+    #define PLLM (HSE_VALUE / 8000000) // VCO input is 8MHz
+    #define PLLN (24) // 24*8MHz = 192MHz
+    #define PLLQ (4) // f_Q = 48MHz
+    #define PLLR (3) // f_R = 64MHz
+    RCC->PLLCFGR =
+        (PLLR - 1) << RCC_PLLCFGR_PLLR_Pos | RCC_PLLCFGR_PLLREN
+        | (PLLQ - 1) << RCC_PLLCFGR_PLLQ_Pos | RCC_PLLCFGR_PLLQEN
+        | PLLN << RCC_PLLCFGR_PLLN_Pos
+        | (PLLM - 1) << RCC_PLLCFGR_PLLM_Pos
+        | 3 << RCC_PLLCFGR_PLLSRC_Pos;
+    RCC->CR |= RCC_CR_PLLON;
+    while (!(RCC->CR & RCC_CR_PLLRDY)) {
+        // Wait for PLL to lock
+    }
+    const uint32_t sysclk_src = 3;
+
+    // Set divider for HCLK2 to 2 so f_HCLK2 = 32MHz
+    RCC->EXTCFGR = 8 << RCC_EXTCFGR_C2HPRE_Pos;
+
+    // Set flash latency to 3 because SYSCLK > 54MHz
+    FLASH->ACR |= 3 << FLASH_ACR_LATENCY_Pos;
+
+    // Select SYSCLK source
+    RCC->CFGR |= sysclk_src << RCC_CFGR_SW_Pos;
+    while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != sysclk_src) {
+        // Wait for SYSCLK source to change
+    }
+
+    // Select PLLQ as 48MHz source for USB and RNG
+    RCC->CCIPR = 2 << RCC_CCIPR_CLK48SEL_Pos;
+
+    SystemCoreClockUpdate();
+
+    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);
+    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
+}
+
 #endif
diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c
index d0f444c21626955d1431ee56ae9d90598b9b3d03..4019617ac87f53cbf3b74c8ad7ea6a8844f17928 100644
--- a/ports/stm32/rtc.c
+++ b/ports/stm32/rtc.c
@@ -31,6 +31,14 @@
 #include "rtc.h"
 #include "irq.h"
 
+#if defined(STM32WB)
+#define RCC_CSR_LSION RCC_CSR_LSI1ON
+#define RCC_FLAG_LSIRDY RCC_FLAG_LSI1RDY
+#define RCC_OSCILLATORTYPE_LSI RCC_OSCILLATORTYPE_LSI1
+#define __HAL_RCC_LSI_ENABLE __HAL_RCC_LSI1_ENABLE
+#define __HAL_RCC_LSI_DISABLE __HAL_RCC_LSI1_DISABLE
+#endif
+
 /// \moduleref pyb
 /// \class RTC - real time clock
 ///
@@ -177,7 +185,7 @@ void rtc_init_finalise() {
 
     // fresh reset; configure RTC Calendar
     RTC_CalendarConfig();
-    #if defined(STM32L4)
+    #if defined(STM32L4) || defined(STM32WB)
     if(__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST) != RESET) {
     #else
     if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET) {
@@ -209,7 +217,7 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruc
 
     /*------------------------------ LSE Configuration -------------------------*/
     if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) {
-        #if !defined(STM32H7)
+        #if !defined(STM32H7) && !defined(STM32WB)
         // Enable Power Clock
         __HAL_RCC_PWR_CLK_ENABLE();
         #endif
@@ -218,7 +226,7 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruc
         HAL_PWR_EnableBkUpAccess();
         uint32_t tickstart = HAL_GetTick();
 
-        #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
+        #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB)
         //__HAL_RCC_PWR_CLK_ENABLE();
         // Enable write access to Backup domain
         //PWR->CR1 |= PWR_CR1_DBP;
@@ -298,7 +306,7 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) {
         // Exit Initialization mode
         hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
 
-        #if defined(STM32L0) || defined(STM32L4) || defined(STM32H7)
+        #if defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB)
         hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMOUTTYPE;
         hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType);
         #elif defined(STM32F7)
@@ -649,7 +657,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
         RTC->WPR = 0xff;
 
         // enable external interrupts on line EXTI_RTC_WAKEUP
-        #if defined(STM32L4)
+        #if defined(STM32L4) || defined(STM32WB)
         EXTI->IMR1 |= 1 << EXTI_RTC_WAKEUP;
         EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP;
         #elif defined(STM32H7)
@@ -662,7 +670,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
 
         // clear interrupt flags
         RTC->ISR &= ~RTC_ISR_WUTF;
-        #if defined(STM32L4)
+        #if defined(STM32L4) || defined(STM32WB)
         EXTI->PR1 = 1 << EXTI_RTC_WAKEUP;
         #elif defined(STM32H7)
         EXTI_D1->PR1 = 1 << EXTI_RTC_WAKEUP;
@@ -682,7 +690,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
         RTC->WPR = 0xff;
 
         // disable external interrupts on line EXTI_RTC_WAKEUP
-        #if defined(STM32L4)
+        #if defined(STM32L4) || defined(STM32WB)
         EXTI->IMR1 &= ~(1 << EXTI_RTC_WAKEUP);
         #elif defined(STM32H7)
         EXTI_D1->IMR1 |= 1 << EXTI_RTC_WAKEUP;
diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c
index 1e2712b05fbccb3ecfaef5399c2d50c81f05b7fd..16db92d1d7aa3bca6f93687de17d2c4e10c0a763 100644
--- a/ports/stm32/stm32_it.c
+++ b/ports/stm32/stm32_it.c
@@ -306,6 +306,14 @@ void USB_IRQHandler(void) {
 }
 #endif
 
+#elif defined(STM32WB)
+
+#if MICROPY_HW_USB_FS
+void USB_LP_IRQHandler(void) {
+    HAL_PCD_IRQHandler(&pcd_fs_handle);
+}
+#endif
+
 #else
 
 /**
diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c
index deb23e2f5f0c453eb4a60be1d7479f8563d8eb1b..0792d124d6153f642cb7f0faf409c646413719b4 100644
--- a/ports/stm32/system_stm32.c
+++ b/ports/stm32/system_stm32.c
@@ -78,6 +78,8 @@
 #include "py/mphal.h"
 #include "powerctrl.h"
 
+#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32L4)
+
 void __fatal_error(const char *msg);
 
 /**
@@ -392,3 +394,5 @@ void SystemClock_Config(void)
     NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, TICK_INT_PRIORITY, 0));
 #endif
 }
+
+#endif
diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c
index 0d46ea9473599a97ce70d0b67bdceb504ddf0a48..f577eb787fa0d55133147ec4339341caaf012849 100644
--- a/ports/stm32/uart.c
+++ b/ports/stm32/uart.c
@@ -81,7 +81,7 @@
 #define USART_CR2_IE_ALL (USART_CR2_IE_BASE)
 #define USART_CR3_IE_ALL (USART_CR3_IE_BASE | USART_CR3_WUFIE)
 
-#elif defined(STM32L4)
+#elif defined(STM32L4) || defined(STM32WB)
 #define USART_CR1_IE_ALL (USART_CR1_IE_BASE | USART_CR1_EOBIE | USART_CR1_RTOIE | USART_CR1_CMIE)
 #define USART_CR2_IE_ALL (USART_CR2_IE_BASE)
 #if defined(USART_CR3_TCBGTIE)
@@ -439,11 +439,13 @@ void uart_deinit(pyb_uart_obj_t *self) {
         __HAL_RCC_USART1_FORCE_RESET();
         __HAL_RCC_USART1_RELEASE_RESET();
         __HAL_RCC_USART1_CLK_DISABLE();
+    #if defined(USART2)
     } else if (self->uart_id == 2) {
         HAL_NVIC_DisableIRQ(USART2_IRQn);
         __HAL_RCC_USART2_FORCE_RESET();
         __HAL_RCC_USART2_RELEASE_RESET();
         __HAL_RCC_USART2_CLK_DISABLE();
+    #endif
     #if defined(USART3)
     } else if (self->uart_id == 3) {
         #if !defined(STM32F0)
@@ -653,7 +655,7 @@ int uart_rx_char(pyb_uart_obj_t *self) {
         return data;
     } else {
         // no buffering
-        #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7)
+        #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB)
         int data = self->uartx->RDR & self->char_mask;
         self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set
         return data;
@@ -779,7 +781,7 @@ void uart_irq_handler(mp_uint_t uart_id) {
             uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len;
             if (next_head != self->read_buf_tail) {
                 // only read data if room in buf
-                #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7)
+                #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB)
                 int data = self->uartx->RDR; // clears UART_FLAG_RXNE
                 self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set
                 #else
diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c
index b27ea51d87f5052992a53a4e580779eeb88c601c..e234230196cc7c53c04e91d9663925f8c043211a 100644
--- a/ports/stm32/usbd_cdc_interface.c
+++ b/ports/stm32/usbd_cdc_interface.c
@@ -142,7 +142,7 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, ui
                 // configure its serial port (in most cases to disable local echo)
                 cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTING;
                 usbd_cdc_connect_tx_timer = 8; // wait for 8 SOF IRQs
-                #if defined(STM32L0)
+                #if defined(STM32L0) || defined(STM32WB)
                 USB->CNTR |= USB_CNTR_SOFM;
                 #else
                 PCD_HandleTypeDef *hpcd = cdc->base.usbd->pdev->pData;
@@ -219,7 +219,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
         --usbd_cdc_connect_tx_timer;
     } else {
         usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData;
-        #if defined(STM32L0)
+        #if defined(STM32L0) || defined(STM32WB)
         USB->CNTR &= ~USB_CNTR_SOFM;
         #else
         hpcd->Instance->GINTMSK &= ~USB_OTG_GINTMSK_SOFM;
diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c
index 8e62a9cc8c800b8ecbefbf6c623771d44813deb6..437d96ae7877fbd682df22f2e4b61724086db8e1 100644
--- a/ports/stm32/usbd_conf.c
+++ b/ports/stm32/usbd_conf.c
@@ -44,7 +44,7 @@ PCD_HandleTypeDef pcd_fs_handle;
 PCD_HandleTypeDef pcd_hs_handle;
 #endif
 
-#if defined(STM32L0)
+#if defined(STM32L0) || defined(STM32WB)
 // The STM32L0xx has a single USB device-only instance
 #define USB_OTG_FS USB
 #endif
@@ -64,6 +64,8 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
         const uint32_t otg_alt = GPIO_AF10_OTG1_FS;
         #elif defined(STM32L0)
         const uint32_t otg_alt = GPIO_AF0_USB;
+        #elif defined(STM32WB)
+        const uint32_t otg_alt = GPIO_AF10_USB;
         #else
         const uint32_t otg_alt = GPIO_AF10_OTG_FS;
         #endif
@@ -90,7 +92,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
         #endif
 
         // Enable USB FS Clocks
-        #if defined(STM32L0)
+        #if defined(STM32L0) || defined(STM32WB)
         __HAL_RCC_USB_CLK_ENABLE();
         #else
         __USB_OTG_FS_CLK_ENABLE();
@@ -111,6 +113,9 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
         #if defined(STM32L0)
         NVIC_SetPriority(USB_IRQn, IRQ_PRI_OTG_FS);
         HAL_NVIC_EnableIRQ(USB_IRQn);
+        #elif defined(STM32WB)
+        NVIC_SetPriority(USB_LP_IRQn, IRQ_PRI_OTG_FS);
+        HAL_NVIC_EnableIRQ(USB_LP_IRQn);
         #else
         NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS);
         HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
@@ -190,7 +195,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
   * @retval None
   */
 void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) {
-    #if defined(STM32L0)
+    #if defined(STM32L0) || defined(STM32WB)
     __HAL_RCC_USB_CLK_DISABLE();
     #else
 
@@ -354,6 +359,10 @@ void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) {
 USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
     #if MICROPY_HW_USB_FS
     if (pdev->id ==  USB_PHY_FS_ID) {
+        #if defined(STM32WB)
+        PWR->CR2 |= PWR_CR2_USV; // USB supply is valid
+        #endif
+
         // Set LL Driver parameters
         pcd_fs_handle.Instance = USB_OTG_FS;
         #if MICROPY_HW_USB_CDC_NUM == 2
@@ -370,7 +379,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
         pcd_fs_handle.Init.lpm_enable = DISABLE;
         pcd_fs_handle.Init.battery_charging_enable = DISABLE;
         #endif
-        #if !defined(STM32L0)
+        #if !defined(STM32L0) && !defined(STM32WB)
         pcd_fs_handle.Init.use_dedicated_ep1 = 0;
         pcd_fs_handle.Init.dma_enable = 0;
         #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
@@ -387,7 +396,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
         // Initialize LL Driver
         HAL_PCD_Init(&pcd_fs_handle);
 
-        #if defined(STM32L0)
+        #if defined(STM32L0) || defined(STM32WB)
         // We have 512 16-bit words it total to use here (when using PCD_SNG_BUF)
         HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x00, PCD_SNG_BUF, 64); // EP0
         HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x80, PCD_SNG_BUF, 128); // EP0