diff --git a/epicardium/FreeRTOSConfig.h b/epicardium/FreeRTOSConfig.h
index f1d3aa46915e9c4373d281a1a4ab37707a918bf9..b731f6a9abdee7556f073936d86aba649e72a8d1 100644
--- a/epicardium/FreeRTOSConfig.h
+++ b/epicardium/FreeRTOSConfig.h
@@ -1,11 +1,10 @@
 #ifndef FREERTOS_CONFIG_H
 #define FREERTOS_CONFIG_H
 
-#define  MXC_ASSERT_ENABLE
-#include "mxc_assert.h"
-
 #include "max32665.h"
 
+#include <assert.h>
+
 /* CMSIS keeps a global updated with current system clock in Hz */
 #define configCPU_CLOCK_HZ          ((unsigned long)96000000)
 
@@ -69,7 +68,7 @@
 #define xPortSysTickHandler   SysTick_Handler
 
 /* Assert */
-#define configASSERT(x)       MXC_ASSERT(x)
+#define configASSERT(x)       assert(x)
 
 /* Tickless idle hooks */
 typedef uint32_t TickType_t;
diff --git a/epicardium/main.c b/epicardium/main.c
index 95319203b53b33b0c099d0b7ecaa50f3ea3e50d8..3dbd4bbf5a0ac00f0712bfca66854c8d682c3f81 100644
--- a/epicardium/main.c
+++ b/epicardium/main.c
@@ -64,8 +64,7 @@ int main(void)
 		    NULL,
 		    tskIDLE_PRIORITY + 3,
 		    NULL) != pdPASS) {
-		LOG_CRIT("startup", "Failed to create %s task!", "Serial");
-		abort();
+		panic("Failed to create %s task!", "Serial");
 	}
 
 	/* PMIC */
@@ -76,8 +75,7 @@ int main(void)
 		    NULL,
 		    tskIDLE_PRIORITY + 4,
 		    NULL) != pdPASS) {
-		LOG_CRIT("startup", "Failed to create %s task!", "PMIC");
-		abort();
+		panic("Failed to create %s task!", "PMIC");
 	}
 
 	/* BHI160 */
@@ -88,8 +86,7 @@ int main(void)
 		    NULL,
 		    tskIDLE_PRIORITY + 1,
 		    NULL) != pdPASS) {
-		LOG_CRIT("startup", "Failed to create %s task!", "BHI160");
-		abort();
+		panic("Failed to create %s task!", "BHI160");
 	}
 
 	/* MAX30001 */
@@ -100,8 +97,7 @@ int main(void)
 		    NULL,
 		    tskIDLE_PRIORITY + 1,
 		    NULL) != pdPASS) {
-		LOG_CRIT("startup", "Failed to create %s task!", "MAX30001");
-		abort();
+		panic("Failed to create %s task!", "MAX30001");
 	}
 	/* API */
 	if (xTaskCreate(
@@ -111,12 +107,7 @@ int main(void)
 		    NULL,
 		    tskIDLE_PRIORITY + 2,
 		    &dispatcher_task_id) != pdPASS) {
-		LOG_CRIT(
-			"startup",
-			"Failed to create %s task!",
-			"API Dispatcher"
-		);
-		abort();
+		panic("Failed to create %s task!", "API Dispatcher");
 	}
 
 	/* BLE */
@@ -128,8 +119,7 @@ int main(void)
 			    NULL,
 			    tskIDLE_PRIORITY + 3,
 			    NULL) != pdPASS) {
-			LOG_CRIT("startup", "Failed to create %s task!", "BLE");
-			abort();
+			panic("Failed to create %s task!", "BLE");
 		}
 	}
 
@@ -141,8 +131,7 @@ int main(void)
 		    NULL,
 		    tskIDLE_PRIORITY + 1,
 		    NULL) != pdPASS) {
-		LOG_CRIT("startup", "Failed to create %s task!", "LED");
-		abort();
+		panic("Failed to create %s task!", "LED");
 	}
 
 	/* Lifecycle */
@@ -153,8 +142,7 @@ int main(void)
 		    NULL,
 		    tskIDLE_PRIORITY + 3,
 		    NULL) != pdPASS) {
-		LOG_CRIT("startup", "Failed to create %s task!", "Lifecycle");
-		abort();
+		panic("Failed to create %s task!", "Lifecycle");
 	}
 
 	/*
@@ -165,6 +153,5 @@ int main(void)
 	LOG_DEBUG("startup", "Starting FreeRTOS ...");
 	vTaskStartScheduler();
 
-	LOG_CRIT("startup", "FreeRTOS did not start due to unknown error!");
-	abort();
+	panic("FreeRTOS did not start due to unknown error!");
 }
diff --git a/epicardium/modules/bhi.c b/epicardium/modules/bhi.c
index a40a73eb64a6503d47319c9bc25603f766e822cd..b88e1dc217d087e93d286a488a81ccef3cac619c 100644
--- a/epicardium/modules/bhi.c
+++ b/epicardium/modules/bhi.c
@@ -1,3 +1,4 @@
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -259,14 +260,14 @@ bhi160_handle_packet(bhy_data_type_t data_type, bhy_data_generic_t *sensor_data)
 		wakeup = true;
 		/* fall through */
 	case VS_ID_TIMESTAMP_MSW:
-		MXC_ASSERT(data_type == BHY_DATA_TYPE_SCALAR_U16);
+		assert(data_type == BHY_DATA_TYPE_SCALAR_U16);
 		timestamp = sensor_data->data_scalar_u16.data << 16;
 		break;
 	case VS_ID_TIMESTAMP_LSW_WAKEUP:
 		wakeup = true;
 		/* fall through */
 	case VS_ID_TIMESTAMP_LSW:
-		MXC_ASSERT(data_type == BHY_DATA_TYPE_SCALAR_U16);
+		assert(data_type == BHY_DATA_TYPE_SCALAR_U16);
 		timestamp = (timestamp & 0xFFFF0000) |
 			    sensor_data->data_scalar_u16.data;
 		break;
@@ -303,7 +304,7 @@ bhi160_handle_packet(bhy_data_type_t data_type, bhy_data_generic_t *sensor_data)
 			break;
 		}
 
-		MXC_ASSERT(data_type == BHY_DATA_TYPE_VECTOR);
+		assert(data_type == BHY_DATA_TYPE_VECTOR);
 		if (bhi160_streams[sensor_type].queue == NULL) {
 			break;
 		}
diff --git a/epicardium/modules/lifecycle.c b/epicardium/modules/lifecycle.c
index 650664d2e97ee15ecbd35199e176ded925a78bfb..a1f8627aa53d648bc67be12455052d6a19352910 100644
--- a/epicardium/modules/lifecycle.c
+++ b/epicardium/modules/lifecycle.c
@@ -364,10 +364,7 @@ void vLifecycleTask(void *pvParameters)
 	core1_mutex    = xSemaphoreCreateMutexStatic(&core1_mutex_data);
 
 	if (xSemaphoreTake(core1_mutex, 0) != pdTRUE) {
-		LOG_CRIT(
-			"lifecycle", "Failed to acquire mutex after creation."
-		);
-		vTaskDelay(portMAX_DELAY);
+		panic("lifecycle: Failed to acquire mutex after creation.");
 	}
 
 	LOG_DEBUG("lifecycle", "Booting core 1 ...");
diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build
index 21a04ba5ec8464979127f1572b56a979ba34f08b..022397ca26e3866ef9a72472a7621e4cd6dbfec2 100644
--- a/epicardium/modules/meson.build
+++ b/epicardium/modules/meson.build
@@ -14,6 +14,7 @@ module_sources = files(
   'light_sensor.c',
   'log.c',
   'max30001.c',
+  'panic.c',
   'personal_state.c',
   'pmic.c',
   'rtc.c',
diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h
index d5087864ae30ea1e4797abb106ba634b58280d4f..bf59566b3e7ef168977ccf7606d55f445961da86 100644
--- a/epicardium/modules/modules.h
+++ b/epicardium/modules/modules.h
@@ -8,6 +8,10 @@
 #include <stdint.h>
 #include <stdbool.h>
 
+/* ---------- Panic -------------------------------------------------------- */
+void panic(const char *format, ...)
+	__attribute__((noreturn, format(printf, 1, 2)));
+
 /* ---------- Dispatcher --------------------------------------------------- */
 void vApiDispatcher(void *pvParameters);
 void dispatcher_mutex_init(void);
@@ -31,6 +35,8 @@ void vSerialTask(void *pvParameters);
 void serial_enqueue_char(char chr);
 void serial_flush(void);
 extern TaskHandle_t serial_task_id;
+/* Turn off the print queue and do prints synchroneous from now on. */
+void serial_return_to_synchronous();
 
 // For the eSetBit xTaskNotify task semaphore trigger
 enum serial_notify{
diff --git a/epicardium/modules/panic.c b/epicardium/modules/panic.c
new file mode 100644
index 0000000000000000000000000000000000000000..aa27b4de5ae7a856ed6beee6e8cc29cdab43e1bf
--- /dev/null
+++ b/epicardium/modules/panic.c
@@ -0,0 +1,76 @@
+/*
+ * Panic
+ * =====
+ *
+ * Under some conditions the firmware should crash and reboot automatically.
+ * This module provides the necessary facilities to do so.
+ *
+ * Note that a panic should indicate **only** logic-errors in the firmware or
+ * unrecoverable hardware conditions.
+ */
+
+#include "modules/log.h"
+#include "modules/modules.h"
+
+#include "card10.h"
+#include "card10-version.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+void __attribute__((noreturn)) panic(const char *format, ...)
+{
+	/* Turn off interrupts.  We won't get back from here anyway. */
+	__asm volatile("cpsid	i" ::: "memory");
+
+	/*
+	 * Turn off asynchronous printing because that won't ever work from
+	 * here ...
+	 */
+	serial_return_to_synchronous();
+
+	printf("\x1b[31;1m           --- SYSTEM PANIC ---\n"
+	       "\x1b[0;31m         ---                  ---\n"
+	       "       ---                      ---\n"
+	       "\x1b[0m A fatal error occured:\n     \x1b[1m");
+
+	va_list ap;
+	va_start(ap, format);
+	vprintf(format, ap);
+	va_end(ap);
+
+	printf("\n"
+	       "\x1b[0m\n"
+	       " Firmware Version:\n"
+	       "\x1b[35m     %s\n",
+	       CARD10_VERSION);
+
+	printf("\x1b[0m\n"
+	       " Stack Trace:\n"
+	       "\x1b[36m     %p\n",
+	       __builtin_return_address(0));
+
+	printf("\x1b[33m\n"
+	       " Please report this error to the card10 firmware team!\n"
+	       "\x1b[0m -> https://git.card10.badge.events.ccc.de/card10/firmware/issues/new?issue <-\n"
+	       "\x1b[31m           --- ====== ===== ---\x1b[0m\n");
+
+	for (int i = 0; i < 96000000; i++) {
+		__asm volatile("nop");
+	}
+
+	card10_reset();
+}
+
+void __attribute__((noreturn)) __assert_func(
+	const char *file, int line, const char *func, const char *failedexpr
+) {
+	panic("Assertion failure:\n"
+	      "       \"%s\"\n"
+	      "       failed in \"%s:%d\",\n"
+	      "       function: %s()",
+	      failedexpr,
+	      file,
+	      line,
+	      func);
+}
diff --git a/epicardium/modules/serial.c b/epicardium/modules/serial.c
index 396d628dba562d8017600d23ec57df7ffaa64ea4..ef5b65edda24b9ce828afcec18cb84f2ff7f27ef 100644
--- a/epicardium/modules/serial.c
+++ b/epicardium/modules/serial.c
@@ -46,6 +46,11 @@ void serial_init()
 	);
 }
 
+void serial_return_to_synchronous()
+{
+	write_stream_buffer = NULL;
+}
+
 /*
  * API-call to write a string.  Output goes to both CDCACM and UART
  */
diff --git a/epicardium/support.c b/epicardium/support.c
index e6925203767dc84ddc44e7c56c9e932f8464f4a1..ac58cf03170eb09b1dc96b0a66b036a155bdc73f 100644
--- a/epicardium/support.c
+++ b/epicardium/support.c
@@ -117,5 +117,5 @@ void vApplicationGetTimerTaskMemory(
 
 void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName)
 {
-	LOG_CRIT("rtos", "Task \"%s\" overflowed stack!", pcTaskName);
+	panic("Task \"%s\" overflowed stack!", pcTaskName);
 }
diff --git a/lib/card10/card10.c b/lib/card10/card10.c
index 09cc44ff293b8001d7121be3b22b8939bc9fd0e8..43361ef06fbf76323516b68e5fdead7f7b9febd9 100644
--- a/lib/card10/card10.c
+++ b/lib/card10/card10.c
@@ -224,7 +224,7 @@ void card10_poll(void)
 	portexpander_poll();
 }
 
-void card10_reset(void)
+void __attribute__((noreturn)) card10_reset(void)
 {
 	printf("Resetting ...\n");
 	/*
@@ -235,6 +235,9 @@ void card10_reset(void)
 		__asm volatile("nop");
 	}
 	MXC_GCR->rstr0 = MXC_F_GCR_RSTR0_SYSTEM;
+
+	while (1)
+		__WFI();
 }
 
 void GPIO0_IRQHandler(void)
diff --git a/lib/card10/card10.h b/lib/card10/card10.h
index fc90fe67f47527cbdbcf2a0b30a9c9d53d70d3df..192058f02a76361323e10c50d2e20f6a5a26f427 100644
--- a/lib/card10/card10.h
+++ b/lib/card10/card10.h
@@ -15,5 +15,5 @@ void core1_start(void *isr);
 void core1_stop(void);
 
 void card10_poll(void);
-void card10_reset(void);
+void card10_reset(void) __attribute__((noreturn));
 #endif