diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index 84ce01e8f951a6335ad9e6a8a8c32e8579bd29c3..d2ca4122a1cf3102779dc54341b8492193008f2c 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -331,12 +331,17 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
 	hal_uart.c \
 	)
 
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l0 l4))
+SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
+	ll_usb.c \
+	)
+endif
+
 ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l4))
 SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
 	hal_sd.c \
 	ll_sdmmc.c \
 	ll_fmc.c \
-	ll_usb.c \
 	)
 endif
 
diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h
index 075791357c81f097738d2759d08a0b085e79509e..78ba46ced4651cfc9a6cefc02a6f291b57bb0a48 100644
--- a/ports/stm32/irq.h
+++ b/ports/stm32/irq.h
@@ -79,6 +79,17 @@ static inline void restore_irq_pri(uint32_t basepri) {
     __set_BASEPRI(basepri);
 }
 
+#else
+
+static inline uint32_t raise_irq_pri(uint32_t pri) {
+    return disable_irq();
+}
+
+// "state" should be the value returned from raise_irq_pri
+static inline void restore_irq_pri(uint32_t state) {
+    enable_irq(state);
+}
+
 #endif
 
 MP_DECLARE_CONST_FUN_OBJ_0(pyb_wfi_obj);
diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c
index 527118ba88f1a9c9c0a57eed43db162d0e441775..e320cc4db159df77abc01789618de5df49908e0d 100644
--- a/ports/stm32/powerctrlboot.c
+++ b/ports/stm32/powerctrlboot.c
@@ -98,6 +98,27 @@ void SystemClock_Config(void) {
 
     HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);
     HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
+
+    #if MICROPY_HW_ENABLE_RNG || MICROPY_HW_ENABLE_USB
+    // Enable the 48MHz internal oscillator
+    RCC->CRRCR |= RCC_CRRCR_HSI48ON;
+    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
+    SYSCFG->CFGR3 |= SYSCFG_CFGR3_ENREF_HSI48;
+    while (!(RCC->CRRCR & RCC_CRRCR_HSI48RDY)) {
+        // Wait for HSI48 to be ready
+    }
+
+    // Select RC48 as HSI48 for USB and RNG
+    RCC->CCIPR |= RCC_CCIPR_HSI48SEL;
+
+    #if MICROPY_HW_ENABLE_USB
+    // Synchronise HSI48 with 1kHz USB SoF
+    __HAL_RCC_CRS_CLK_ENABLE();
+    CRS->CR = 0x20 << CRS_CR_TRIM_Pos;
+    CRS->CFGR = 2 << CRS_CFGR_SYNCSRC_Pos | 0x22 << CRS_CFGR_FELIM_Pos
+        | __HAL_RCC_CRS_RELOADVALUE_CALCULATE(48000000, 1000) << CRS_CFGR_RELOAD_Pos;
+    #endif
+    #endif
 }
 
 #endif
diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c
index fd3aea6c1c6ba03a46fb499cc30abab8a8d6e8df..1e2712b05fbccb3ecfaef5399c2d50c81f05b7fd 100644
--- a/ports/stm32/stm32_it.c
+++ b/ports/stm32/stm32_it.c
@@ -298,6 +298,16 @@ void DebugMon_Handler(void) {
 /*  file (startup_stm32f4xx.s).                                               */
 /******************************************************************************/
 
+#if defined(STM32L0)
+
+#if MICROPY_HW_USB_FS
+void USB_IRQHandler(void) {
+    HAL_PCD_IRQHandler(&pcd_fs_handle);
+}
+#endif
+
+#else
+
 /**
   * @brief  This function handles USB-On-The-Go FS global interrupt request.
   * @param  None
@@ -405,6 +415,8 @@ void OTG_HS_WKUP_IRQHandler(void) {
 }
 #endif
 
+#endif // !defined(STM32L0)
+
 /**
   * @brief  This function handles PPP interrupt request.
   * @param  None
diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c
index 49f0deec71242f4790564504087d71c65d08cf24..b27ea51d87f5052992a53a4e580779eeb88c601c 100644
--- a/ports/stm32/usbd_cdc_interface.c
+++ b/ports/stm32/usbd_cdc_interface.c
@@ -140,11 +140,14 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, ui
             if (length & 1) {
                 // The actual connection state is delayed to give the host a chance to
                 // configure its serial port (in most cases to disable local echo)
-                PCD_HandleTypeDef *hpcd = cdc->base.usbd->pdev->pData;
-                USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
                 cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTING;
                 usbd_cdc_connect_tx_timer = 8; // wait for 8 SOF IRQs
-                USBx->GINTMSK |= USB_OTG_GINTMSK_SOFM;
+                #if defined(STM32L0)
+                USB->CNTR |= USB_CNTR_SOFM;
+                #else
+                PCD_HandleTypeDef *hpcd = cdc->base.usbd->pdev->pData;
+                hpcd->Instance->GINTMSK |= USB_OTG_GINTMSK_SOFM;
+                #endif
             } else {
                 cdc->connect_state = USBD_CDC_CONNECT_STATE_DISCONNECTED;
             }
@@ -216,7 +219,11 @@ 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)
+        USB->CNTR &= ~USB_CNTR_SOFM;
+        #else
         hpcd->Instance->GINTMSK &= ~USB_OTG_GINTMSK_SOFM;
+        #endif
         for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) {
             usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)usbd->cdc[i];
             if (cdc->connect_state == USBD_CDC_CONNECT_STATE_CONNECTING) {
diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c
index ed99700e9994f685710f50bdf0c870455eabb45f..8e62a9cc8c800b8ecbefbf6c623771d44813deb6 100644
--- a/ports/stm32/usbd_conf.c
+++ b/ports/stm32/usbd_conf.c
@@ -44,6 +44,11 @@ PCD_HandleTypeDef pcd_fs_handle;
 PCD_HandleTypeDef pcd_hs_handle;
 #endif
 
+#if defined(STM32L0)
+// The STM32L0xx has a single USB device-only instance
+#define USB_OTG_FS USB
+#endif
+
 /*******************************************************************************
                        PCD BSP Routines
 *******************************************************************************/
@@ -57,6 +62,8 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
     if (hpcd->Instance == USB_OTG_FS) {
         #if defined(STM32H7)
         const uint32_t otg_alt = GPIO_AF10_OTG1_FS;
+        #elif defined(STM32L0)
+        const uint32_t otg_alt = GPIO_AF0_USB;
         #else
         const uint32_t otg_alt = GPIO_AF10_OTG_FS;
         #endif
@@ -83,7 +90,11 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
         #endif
 
         // Enable USB FS Clocks
+        #if defined(STM32L0)
+        __HAL_RCC_USB_CLK_ENABLE();
+        #else
         __USB_OTG_FS_CLK_ENABLE();
+        #endif
 
         #if defined(STM32L4)
         // Enable VDDUSB
@@ -97,8 +108,13 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
         #endif
 
         // Configure and enable USB FS interrupt
+        #if defined(STM32L0)
+        NVIC_SetPriority(USB_IRQn, IRQ_PRI_OTG_FS);
+        HAL_NVIC_EnableIRQ(USB_IRQn);
+        #else
         NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS);
         HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
+        #endif
     }
     #if MICROPY_HW_USB_HS
     else if (hpcd->Instance == USB_OTG_HS) {
@@ -174,6 +190,10 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
   * @retval None
   */
 void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) {
+    #if defined(STM32L0)
+    __HAL_RCC_USB_CLK_DISABLE();
+    #else
+
     if (hpcd->Instance == USB_OTG_FS) {
         /* Disable USB FS Clocks */
         __USB_OTG_FS_CLK_DISABLE();
@@ -186,6 +206,8 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) {
         __SYSCFG_CLK_DISABLE();
     }
     #endif
+
+    #endif
 }
 
 /*******************************************************************************
@@ -339,9 +361,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
         #else
         pcd_fs_handle.Init.dev_endpoints = 4;
         #endif
-        pcd_fs_handle.Init.use_dedicated_ep1 = 0;
         pcd_fs_handle.Init.ep0_mps = 0x40;
-        pcd_fs_handle.Init.dma_enable = 0;
         pcd_fs_handle.Init.low_power_enable = 0;
         pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED;
         pcd_fs_handle.Init.Sof_enable = 0;
@@ -350,11 +370,15 @@ 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)
+        pcd_fs_handle.Init.use_dedicated_ep1 = 0;
+        pcd_fs_handle.Init.dma_enable = 0;
         #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
         pcd_fs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0
         #else
         pcd_fs_handle.Init.vbus_sensing_enable = 1;
         #endif
+        #endif
 
         // Link The driver to the stack
         pcd_fs_handle.pData = pdev;
@@ -363,6 +387,18 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
         // Initialize LL Driver
         HAL_PCD_Init(&pcd_fs_handle);
 
+        #if defined(STM32L0)
+        // 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
+        HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x01, PCD_SNG_BUF, 192); // MSC / HID
+        HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x81, PCD_SNG_BUF, 256); // MSC / HID
+        HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x02, PCD_SNG_BUF, 320); // unused
+        HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x82, PCD_SNG_BUF, 320); // CDC CMD
+        HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x03, PCD_SNG_BUF, 384); // CDC DATA
+        HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x83, PCD_SNG_BUF, 448); // CDC DATA
+        #else
+
         // We have 320 32-bit words in total to use here
         #if MICROPY_HW_USB_CDC_NUM == 2
         HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128);
@@ -379,6 +415,8 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
         HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 32); // CDC CMD
         HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 64); // CDC DATA
         #endif
+
+        #endif
     }
     #endif
     #if MICROPY_HW_USB_HS