diff --git a/pycardium/mphalport.c b/pycardium/mphalport.c
index 60cd9df0cdf1e08a01ffd3df84772d9c6276e7ac..61ea9def213de5f4a9f87f727a5b394272d11e60 100644
--- a/pycardium/mphalport.c
+++ b/pycardium/mphalport.c
@@ -31,6 +31,17 @@ void pycardium_hal_init(void)
 	 * a character becomes available.
 	 */
 	epic_interrupt_enable(EPIC_INT_UART_RX);
+
+	/*
+	 * Configure SysTick timer.
+	 *
+	 * Reload is configured for 80ms.  This seems to be a reasonable value
+	 * to allow at least some sleep for common sleep times in apps.
+	 */
+	SysTick->LOAD = 7679999 & SysTick_LOAD_RELOAD_Msk;
+	SysTick->VAL  = 1;
+	SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk |
+			SysTick_CTRL_TICKINT_Msk;
 }
 
 /******************************************************************************
@@ -124,16 +135,80 @@ void mp_hal_set_interrupt_char(char c)
  * Time & Delay
  */
 
+static volatile uint32_t delay_overflows = 0;
+
+/*
+ * A delay implementation based on the SysTick timer.
+ */
+static void systick_delay_us(uint32_t us)
+{
+	if (us == 0) {
+		return;
+	}
+
+	uint32_t starttick = SysTick->VAL;
+	uint32_t ticks     = (uint32_t)(
+                ((uint64_t)us * (uint64_t)SystemCoreClock) / 1000000
+	);
+	uint32_t reload   = SysTick->LOAD + 1;
+	delay_overflows   = ticks / reload;
+	uint32_t lasttick = ticks % reload;
+
+	uint32_t endtick;
+	if (lasttick >= starttick) {
+		delay_overflows += 1;
+		endtick = reload - (lasttick - starttick);
+	} else {
+		endtick = starttick - lasttick;
+	}
+
+	while (delay_overflows > 0) {
+		mp_handle_pending();
+		/*
+		 * Overflow triggers the SysTick interrupt so we can sleep here.
+		 *
+		 * Note that this does **not** apply to the while-loop following
+		 * this one.
+		 */
+		__WFI();
+	}
+
+	while (SysTick->VAL > endtick) {
+		mp_handle_pending();
+	}
+}
+
+/*
+ * Interrupt handler needed for delay implementation.  If we ever define a more
+ * sophisticated SysTick_Handler, make sure to include a call to this function!
+ */
+static void systick_delay_handler(void)
+{
+	if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) {
+		if (delay_overflows > 0) {
+			delay_overflows--;
+		}
+	}
+}
+
+/* HAL function for MicroPython */
 void mp_hal_delay_ms(mp_uint_t ms)
 {
-	mxc_delay(ms * 1000);
+	systick_delay_us(ms * 1000);
 }
 
+/* HAL function for MicroPython */
 void mp_hal_delay_us(mp_uint_t us)
 {
-	mxc_delay(us);
+	systick_delay_us(us);
 }
 
+/*
+ * HAL function for MicroPython
+ *
+ * This function is not really used except in a debug code-path of
+ * `parse_compile_execute`.  Thus we need to define it as a stub.
+ */
 mp_uint_t mp_hal_ticks_ms(void)
 {
 	return 0;
@@ -163,3 +238,12 @@ int mp_hal_trng_read_int(void)
 	epic_trng_read((uint8_t *)&result, sizeof(result));
 	return result;
 }
+
+/******************************************************************************
+ * SysTick Handler
+ */
+void SysTick_Handler(void)
+{
+	/* Needed for delay implementation */
+	systick_delay_handler();
+}