diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h
index fb65a7374107c6e253f166b5b2f8ede45189f6d5..d5087864ae30ea1e4797abb106ba634b58280d4f 100644
--- a/epicardium/modules/modules.h
+++ b/epicardium/modules/modules.h
@@ -29,6 +29,7 @@ void return_to_menu(void);
 void serial_init();
 void vSerialTask(void *pvParameters);
 void serial_enqueue_char(char chr);
+void serial_flush(void);
 extern TaskHandle_t serial_task_id;
 
 // For the eSetBit xTaskNotify task semaphore trigger
diff --git a/epicardium/modules/serial.c b/epicardium/modules/serial.c
index 3292ab9330c973a83243b9aad0c3e7b63a6d0200..396d628dba562d8017600d23ec57df7ffaa64ea4 100644
--- a/epicardium/modules/serial.c
+++ b/epicardium/modules/serial.c
@@ -121,6 +121,92 @@ void epic_uart_write_str(const char *str, intptr_t length)
 	}
 }
 
+static void serial_flush_from_isr(void)
+{
+	uint8_t rx_data[32];
+	size_t received_bytes;
+
+	BaseType_t resched = pdFALSE;
+	BaseType_t woken   = pdFALSE;
+
+	uint32_t basepri = __get_BASEPRI();
+	taskENTER_CRITICAL_FROM_ISR();
+
+	do {
+		received_bytes = xStreamBufferReceiveFromISR(
+			write_stream_buffer,
+			(void *)rx_data,
+			sizeof(rx_data),
+			&woken
+		);
+		resched |= woken;
+
+		if (received_bytes == 0) {
+			break;
+		}
+
+		/*
+		 * The SDK-driver for UART is not reentrant
+		 * which means we need to perform UART writes
+		 * in a critical section.
+		 */
+
+		UART_Write(ConsoleUart, (uint8_t *)&rx_data, received_bytes);
+	} while (received_bytes > 0);
+
+	taskEXIT_CRITICAL_FROM_ISR(basepri);
+
+	portYIELD_FROM_ISR(&resched);
+}
+
+static void serial_flush_from_thread(void)
+{
+	uint8_t rx_data[32];
+	size_t received_bytes;
+
+	do {
+		taskENTER_CRITICAL();
+		received_bytes = xStreamBufferReceive(
+			write_stream_buffer,
+			(void *)rx_data,
+			sizeof(rx_data),
+			0
+		);
+		taskEXIT_CRITICAL();
+
+		if (received_bytes == 0) {
+			break;
+		}
+
+		/*
+		 * The SDK-driver for UART is not reentrant
+		 * which means we need to perform UART writes
+		 * in a critical section.
+		 */
+		taskENTER_CRITICAL();
+		UART_Write(ConsoleUart, (uint8_t *)&rx_data, received_bytes);
+		taskEXIT_CRITICAL();
+
+		cdcacm_write((uint8_t *)&rx_data, received_bytes);
+		ble_uart_write((uint8_t *)&rx_data, received_bytes);
+	} while (received_bytes > 0);
+}
+
+/*
+ * Flush all characters which are currently waiting to be printed.
+ *
+ * If this function is called from an ISR, it will only flush to hardware UART
+ * while a call from thread mode will flush to UART, CDC-ACM, and BLE Serial.
+ */
+void serial_flush(void)
+{
+	if (xPortIsInsideInterrupt()) {
+		serial_flush_from_isr();
+	} else {
+		serial_flush_from_thread();
+	}
+}
+
 /*
  * API-call to read a character from the queue.
  */
@@ -217,9 +303,6 @@ void vSerialTask(void *pvParameters)
 		.callback = uart_callback,
 	};
 
-	uint8_t rx_data[20];
-	size_t received_bytes;
-
 	while (1) {
 		int ret = UART_ReadAsync(ConsoleUart, &read_req);
 		if (ret != E_NO_ERROR && ret != E_BUSY) {
@@ -230,38 +313,7 @@ void vSerialTask(void *pvParameters)
 		ret = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
 
 		if (ret & SERIAL_WRITE_NOTIFY) {
-			do {
-				received_bytes = xStreamBufferReceive(
-					write_stream_buffer,
-					(void *)rx_data,
-					sizeof(rx_data),
-					0
-				);
-
-				if (received_bytes == 0) {
-					break;
-				}
-
-				/*
-				 * The SDK-driver for UART is not reentrant
-				 * which means we need to perform UART writes
-				 * in a critical section.
-				 */
-				taskENTER_CRITICAL();
-				UART_Write(
-					ConsoleUart,
-					(uint8_t *)&rx_data,
-					received_bytes
-				);
-				taskEXIT_CRITICAL();
-
-				cdcacm_write(
-					(uint8_t *)&rx_data, received_bytes
-				);
-				ble_uart_write(
-					(uint8_t *)&rx_data, received_bytes
-				);
-			} while (received_bytes > 0);
+			serial_flush_from_thread();
 		}
 
 		if (ret & SERIAL_READ_NOTIFY) {