diff --git a/Marlin/src/gcode/calibrate/M101_Task_Free_Mem_Chk.cpp b/Marlin/src/gcode/calibrate/M101_Task_Free_Mem_Chk.cpp
new file mode 100644
index 0000000000..3ffe8f98e7
--- /dev/null
+++ b/Marlin/src/gcode/calibrate/M101_Task_Free_Mem_Chk.cpp
@@ -0,0 +1,84 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+/**
+ * M101 Task Free Memory Watcher
+ *
+ * This code watches the free memory defined for each task in the FreeRTOS environment
+ * It is useful to determine how much memory each task has available.
+ *
+ * Initial version... More Marlin-specific information to be added.
+ */
+
+#include "../../inc/MarlinConfig.h"
+#include "../gcode.h"
+#include "../../Marlin.h"
+#include
+#include "../../libs/hex_print_routines.h"
+
+#define MAX_TASKS 10
+
+void GcodeSuite::M101() {
+ TaskStatus_t TaskStatArray[MAX_TASKS];
+
+ unsigned n_tasks = uxTaskGetNumberOfTasks();
+ if (n_tasks > MAX_TASKS) {
+ SERIAL_PROTOCOLLNPAIR("?Too many tasks: ", n_tasks);
+ SERIAL_EOL();
+ return;
+ }
+
+ SERIAL_PROTOCOLLNPGM("M101 RTOS Task Info:");
+ /* Generate raw status information about each task. */
+ n_tasks = uxTaskGetSystemState( TaskStatArray, MAX_TASKS, NULL);
+
+ SERIAL_PROTOCOLLNPAIR("n_tasks: ", n_tasks);
+
+ /* For each populated position in the TaskStatArray array,
+ format the raw data as human readable ASCII data. */
+ for (unsigned x = 0; x < n_tasks; x++) {
+ char t_name[configMAX_TASK_NAME_LEN + 1]; // Pad out the task name so everything lines up nicely
+ strcpy(t_name, TaskStatArray[x].pcTaskName);
+ while (strlen(t_name) < configMAX_TASK_NAME_LEN)
+ strcat(t_name, "_");
+
+ SERIAL_PROTOCOL(x);
+ SERIAL_PROTOCOLPAIR(":", t_name);
+ SERIAL_PROTOCOLPAIR(" Task #: ", TaskStatArray[x].xTaskNumber);
+ SERIAL_PROTOCOLPAIR(" Current_Priority: ", TaskStatArray[x].uxCurrentPriority);
+ SERIAL_PROTOCOLPAIR(" Base_Priority: ", TaskStatArray[x].uxBasePriority);
+
+ SERIAL_PROTOCOLPGM(" Stack: ");
+ print_hex_address((const void * const) TaskStatArray[x].pxStackBase);
+ SERIAL_PROTOCOLPAIR(" Free_Mem: ", (unsigned int) TaskStatArray[x].usStackHighWaterMark);
+ SERIAL_PROTOCOLPGM(" State: ");
+ switch( TaskStatArray[x].eCurrentState ) {
+ case eRunning: SERIAL_PROTOCOLLNPGM("Running"); break;
+ case eReady: SERIAL_PROTOCOLLNPGM("Ready"); break;
+ case eBlocked: SERIAL_PROTOCOLLNPGM("Blocked"); break;
+ case eSuspended: SERIAL_PROTOCOLLNPGM("Suspended"); break;
+ case eDeleted: SERIAL_PROTOCOLLNPGM("Deleted"); break;
+ default: SERIAL_PROTOCOLLNPAIR("Corrupted:", TaskStatArray[x].eCurrentState);
+ break;
+ }
+ }
+}
diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index 063f32999f..864a933674 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -353,6 +353,7 @@ void GcodeSuite::process_parsed_command(
#if ENABLED(M100_FREE_MEMORY_WATCHER)
case 100: M100(); break; // M100: Free Memory Report
#endif
+ case 101: M101(); break; // M101: RTOS Task Free Memory Report
case 104: M104(); break; // M104: Set hot end temperature
case 109: M109(); break; // M109: Wait for hotend temperature to reach target
diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h
index 36d8fc3fc3..76cf38a5f5 100644
--- a/Marlin/src/gcode/gcode.h
+++ b/Marlin/src/gcode/gcode.h
@@ -114,6 +114,7 @@
* M85 - Set inactivity shutdown timer with parameter S. To disable set zero (default)
* M92 - Set planner.axis_steps_per_mm for one or more axes.
* M100 - Watch Free Memory (for debugging) (Requires M100_FREE_MEMORY_WATCHER)
+ * M101 - RTOS Task Free Memory report (for debugging)
* M104 - Set extruder target temp.
* M105 - Report current temperatures.
* M106 - Set print fan speed.
@@ -513,6 +514,7 @@ private:
static void M100();
#endif
+ static void M101();
static void M104();
static void M105();
static void M106();
diff --git a/Marlin/src/libs/hex_print_routines.cpp b/Marlin/src/libs/hex_print_routines.cpp
index ebf8bca7ec..7baacbe287 100644
--- a/Marlin/src/libs/hex_print_routines.cpp
+++ b/Marlin/src/libs/hex_print_routines.cpp
@@ -23,7 +23,10 @@
#include "../inc/MarlinConfig.h"
#include "../gcode/parser.h"
-#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(M100_FREE_MEMORY_WATCHER) || ENABLED(DEBUG_GCODE_PARSER)
+// Needed for M101 - RTOS Task Report. We can collapse this later, but for now it is nice to
+// always have the hex print functions available.
+//
+//#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(M100_FREE_MEMORY_WATCHER) || ENABLED(DEBUG_GCODE_PARSER)
#include "hex_print_routines.h"
@@ -78,4 +81,4 @@
void print_hex_word(const uint16_t w) { SERIAL_ECHO(hex_word(w)); }
void print_hex_address(const void * const w) { SERIAL_ECHO(hex_address(w)); }
-#endif // AUTO_BED_LEVELING_UBL || M100_FREE_MEMORY_WATCHER || DEBUG_GCODE_PARSER
+//#endif // AUTO_BED_LEVELING_UBL || M100_FREE_MEMORY_WATCHER || DEBUG_GCODE_PARSER