diff --git a/stmhal/hal/src/stm32f4xx_hal.c b/stmhal/hal/src/stm32f4xx_hal.c
index 6df59f9f9a74515f4685b27afb0e94d505d6847d..672422553e1b30c05dd166c63b3eb1ad4528186e 100644
--- a/stmhal/hal/src/stm32f4xx_hal.c
+++ b/stmhal/hal/src/stm32f4xx_hal.c
@@ -281,11 +281,13 @@ uint32_t HAL_GetTick(void)
   */
 void HAL_Delay(__IO uint32_t Delay)
 {
-  uint32_t timingdelay;
-  
-  timingdelay = HAL_GetTick() + Delay;
-  while(HAL_GetTick() < timingdelay)
-  {
+  uint32_t start = HAL_GetTick();
+
+  // Note that the following works (due to the magic of 2's complement numbers)
+  // even when Delay causes wraparound.
+
+  while (HAL_GetTick() - start <= Delay) {
+    __WFI();  // enter sleep mode, waiting for interrupt
   }
 }
 
diff --git a/stmhal/main.c b/stmhal/main.c
index 4b502fcf2422d6b0ffb8ded0a4e4456e341a6d7a..865b4fa59c2b265b5efe6c4e7c0c05464e7a1be8 100644
--- a/stmhal/main.c
+++ b/stmhal/main.c
@@ -72,10 +72,10 @@ void flash_error(int n) {
     for (int i = 0; i < n; i++) {
         led_state(PYB_LED_R1, 1);
         led_state(PYB_LED_R2, 0);
-        sys_tick_delay_ms(250);
+        HAL_Delay(250);
         led_state(PYB_LED_R1, 0);
         led_state(PYB_LED_R2, 1);
-        sys_tick_delay_ms(250);
+        HAL_Delay(250);
     }
     led_state(PYB_LED_R2, 0);
 }
@@ -248,7 +248,6 @@ int main(void) {
 #endif
 
     // basic sub-system init
-    sys_tick_init();
     pendsv_init();
     led_init();
 
@@ -278,16 +277,16 @@ int main(void) {
     while (1) {
         led_state(led, 1);
         usart_tx_strn_cooked(pyb_usart_global_debug, "on\n", 3);
-        sys_tick_delay_ms(100);
+        HAL_Delay(100);
         led_state(led, 0);
         usart_tx_strn_cooked(pyb_usart_global_debug, "off\n", 4);
-        sys_tick_delay_ms(100);
+        HAL_Delay(100);
         led_state(led, 1);
         usart_tx_strn_cooked(pyb_usart_global_debug, "on\n", 3);
-        sys_tick_delay_ms(100);
+        HAL_Delay(100);
         led_state(led, 0);
         usart_tx_strn_cooked(pyb_usart_global_debug, "off\n", 4);
-        sys_tick_delay_ms(700);
+        HAL_Delay(700);
 
         led = (led % 4) + 1;
     }
@@ -362,7 +361,7 @@ soft_reset:
                 reset_filesystem = false;
                 break;
             }
-            sys_tick_delay_ms(10);
+            HAL_Delay(10);
         }
     }
 #endif
@@ -378,7 +377,7 @@ soft_reset:
 
             // LED on to indicate creation of LFS
             led_state(PYB_LED_R2, 1);
-            uint32_t stc = sys_tick_counter;
+            uint32_t start_tick = HAL_GetTick();
 
             res = f_mkfs("0:", 0, 0);
             if (res == FR_OK) {
@@ -400,7 +399,7 @@ soft_reset:
             f_close(&fp);
 
             // keep LED on for at least 200ms
-            sys_tick_wait_at_least(stc, 200);
+            sys_tick_wait_at_least(start_tick, 200);
             led_state(PYB_LED_R2, 0);
         } else {
             __fatal_error("could not access LFS");
@@ -424,7 +423,7 @@ soft_reset:
 
             // LED on to indicate creation of boot.py
             led_state(PYB_LED_R2, 1);
-            uint32_t stc = sys_tick_counter;
+            uint32_t start_tick = HAL_GetTick();
 
             FIL fp;
             f_open(&fp, "0:/boot.py", FA_WRITE | FA_CREATE_ALWAYS);
@@ -434,7 +433,7 @@ soft_reset:
             f_close(&fp);
 
             // keep LED on for at least 200ms
-            sys_tick_wait_at_least(stc, 200);
+            sys_tick_wait_at_least(start_tick, 200);
             led_state(PYB_LED_R2, 0);
         }
     }
@@ -550,7 +549,7 @@ soft_reset:
             }
             accel_read_nack();
             usb_hid_send_report(data);
-            sys_tick_delay_ms(15);
+            HAL_Delay(15);
         }
     }
 #endif
diff --git a/stmhal/pybmodule.c b/stmhal/pybmodule.c
index f0a7ebb6dc4543c0370f952e0ab01a56acad97ff..b0395143941421d08f6d556bc4718bbce53769d2 100644
--- a/stmhal/pybmodule.c
+++ b/stmhal/pybmodule.c
@@ -116,7 +116,7 @@ STATIC mp_obj_t pyb_millis(void) {
 STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_millis_obj, pyb_millis);
 
 STATIC mp_obj_t pyb_delay(mp_obj_t count) {
-    sys_tick_delay_ms(mp_obj_get_int(count));
+    HAL_Delay(mp_obj_get_int(count));
     return mp_const_none;
 }
 
diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c
index 2eca892a9087bd565cc73e5ec9d7bfe7a8f67302..4f2e3dd9d58e03b01342524fa49714437cc06313 100644
--- a/stmhal/pyexec.c
+++ b/stmhal/pyexec.c
@@ -59,7 +59,7 @@ int stdin_rx_chr(void) {
         if (pyb_usart_global_debug != PYB_USART_NONE && usart_rx_any(pyb_usart_global_debug)) {
             return usart_rx_char(pyb_usart_global_debug);
         }
-        sys_tick_delay_ms(1);
+        HAL_Delay(1);
 #if 0
         if (storage_needs_flush()) {
             storage_flush();
@@ -142,7 +142,7 @@ int readline(vstr_t *line, const char *prompt) {
         } else {
             escape = 0;
         }
-        sys_tick_delay_ms(1);
+        HAL_Delay(1);
     }
 }
 
diff --git a/stmhal/systick.c b/stmhal/systick.c
index eda39c78885947ed5b1c6ba28ee2061574bc83cc..d6c914886a6e4fed3b1d663d3ad1e34b833dd1e9 100644
--- a/stmhal/systick.c
+++ b/stmhal/systick.c
@@ -2,47 +2,15 @@
 #include "misc.h"
 #include "systick.h"
 
-void sys_tick_init(void) {
-    // SysTick_Config is now called from HAL_RCC_ClockConfig, which is called
-    // from SystemClock_Config
-
-    // SysTick_Config sets the SysTick_IRQn to be the lowest priority, but
-    // we want it to be the highest priority, so fix things here.
-    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
-}
-
-void sys_tick_delay_ms(uint32_t delay_ms) {
-    sys_tick_wait_at_least(HAL_GetTick(), delay_ms);
-}
-
-// waits until at least delay_ms milliseconds have passed from the sampling of stc
-// handles overflow properl
-// assumes stc was taken from HAL_GetTick() some time before calling this function
-// eg stc <= HAL_GetTick() for the case of no wrap around of HAL_GetTick()
-void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms) {
-    // stc_wait is the value of HAL_GetTick() that we wait for
-    uint32_t stc_wait = stc + delay_ms;
-    if (stc_wait < stc) {
-        // stc_wait wrapped around
-        while (stc <= HAL_GetTick() || HAL_GetTick() < stc_wait) {
-            __WFI(); // enter sleep mode, waiting for interrupt
-        }
-    } else {
-        // stc_wait did not wrap around
-        while (stc <= HAL_GetTick() && HAL_GetTick() < stc_wait) {
-            __WFI(); // enter sleep mode, waiting for interrupt
-        }
-    }
+bool sys_tick_has_passed(uint32_t start_tick, uint32_t delay_ms) {
+    return HAL_GetTick() - start_tick >= delay_ms;
 }
 
-bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms) {
-    // stc_wait is the value of HAL_GetTick() that we wait for
-    uint32_t stc_wait = stc + delay_ms;
-    if (stc_wait < stc) {
-        // stc_wait wrapped around
-        return !(stc <= HAL_GetTick() || HAL_GetTick() < stc_wait);
-    } else {
-        // stc_wait did not wrap around
-        return !(stc <= HAL_GetTick() && HAL_GetTick() < stc_wait);
+// waits until at least delay_ms milliseconds have passed from the sampling of
+// startTick. Handles overflow properly. Assumes stc was taken from
+// HAL_GetTick() some time before calling this function.
+void sys_tick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) {
+    while (!sys_tick_has_passed(start_tick, delay_ms)) {
+        __WFI(); // enter sleep mode, waiting for interrupt
     }
 }
diff --git a/stmhal/systick.h b/stmhal/systick.h
index ce33e849b895e0e277ff48ddf21be042f32d462a..4df45cb9a751f35fa82fce8cbe0474b89954c64e 100644
--- a/stmhal/systick.h
+++ b/stmhal/systick.h
@@ -1,5 +1,2 @@
-void sys_tick_init(void);
-void SysTick_Handler(void);
-void sys_tick_delay_ms(uint32_t delay_ms);
 void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms);
 bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms);