From 1dafd1887e40399faf16e3455e3670ed3acfac52 Mon Sep 17 00:00:00 2001
From: Scott Lahteine <thinkyhead@users.noreply.github.com>
Date: Mon, 27 Sep 2021 13:46:42 -0500
Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Apply=20F()=20to=20various=20rep?=
 =?UTF-8?q?orts?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 Marlin/src/HAL/shared/Delay.cpp               | 36 +++++-----
 Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp   | 12 ++--
 Marlin/src/feature/max7219.cpp                | 41 ++++++-----
 Marlin/src/feature/max7219.h                  |  4 +-
 Marlin/src/feature/powerloss.cpp              |  8 +--
 Marlin/src/feature/powerloss.h                |  4 +-
 Marlin/src/feature/stepper_driver_safety.cpp  | 12 ++--
 Marlin/src/feature/twibus.cpp                 | 46 ++++++------
 Marlin/src/feature/twibus.h                   | 23 +++---
 Marlin/src/gcode/bedlevel/M420.cpp            |  2 +-
 Marlin/src/gcode/bedlevel/abl/G29.cpp         | 30 ++++----
 Marlin/src/gcode/calibrate/G28.cpp            | 14 ++--
 Marlin/src/gcode/calibrate/G33.cpp            | 44 ++++++------
 Marlin/src/gcode/calibrate/M100.cpp           | 14 ++--
 Marlin/src/gcode/config/M43.cpp               |  6 +-
 .../src/gcode/feature/network/M552-M554.cpp   | 10 +--
 Marlin/src/gcode/feature/powerloss/M1000.cpp  |  6 +-
 Marlin/src/gcode/feature/powerloss/M413.cpp   |  2 +-
 Marlin/src/gcode/feature/trinamic/M569.cpp    | 32 ++++-----
 Marlin/src/gcode/gcode.cpp                    |  4 +-
 Marlin/src/gcode/host/M115.cpp                | 70 +++++++++----------
 Marlin/src/gcode/host/M360.cpp                | 62 ++++++++--------
 Marlin/src/gcode/queue.cpp                    | 12 ++--
 Marlin/src/gcode/queue.h                      |  2 +-
 Marlin/src/libs/stopwatch.cpp                 | 18 ++---
 Marlin/src/libs/stopwatch.h                   | 11 ++-
 Marlin/src/libs/vector_3.cpp                  | 24 +++----
 Marlin/src/libs/vector_3.h                    |  4 +-
 Marlin/src/module/endstops.cpp                | 14 ++--
 Marlin/src/pins/pinsDebug.h                   |  8 +--
 30 files changed, 286 insertions(+), 289 deletions(-)

diff --git a/Marlin/src/HAL/shared/Delay.cpp b/Marlin/src/HAL/shared/Delay.cpp
index 32543c6d0ab..c64376d25d9 100644
--- a/Marlin/src/HAL/shared/Delay.cpp
+++ b/Marlin/src/HAL/shared/Delay.cpp
@@ -108,13 +108,14 @@
 
   #if ENABLED(MARLIN_DEV_MODE)
     void dump_delay_accuracy_check() {
-      auto report_call_time = [](PGM_P const name, PGM_P const unit, const uint32_t cycles, const uint32_t total, const bool do_flush=true) {
+      auto report_call_time = [](FSTR_P const name, FSTR_P const unit, const uint32_t cycles, const uint32_t total, const bool do_flush=true) {
         SERIAL_ECHOPGM("Calling ");
-        SERIAL_ECHOPGM_P(name);
+        SERIAL_ECHOF(name);
         SERIAL_ECHOLNPGM(" for ", cycles);
-        SERIAL_ECHOPGM_P(unit);
+        SERIAL_ECHOF(unit);
         SERIAL_ECHOLNPGM(" took: ", total);
-        SERIAL_ECHOPGM_P(unit);
+        SERIAL_CHAR(' ');
+        SERIAL_ECHOF(unit);
         if (do_flush) SERIAL_FLUSHTX();
       };
 
@@ -126,41 +127,42 @@
       constexpr uint32_t testValues[] = { 1, 5, 10, 20, 50, 100, 150, 200, 350, 500, 750, 1000 };
       for (auto i : testValues) {
         s = micros(); DELAY_US(i); e = micros();
-        report_call_time(PSTR("delay"), PSTR("us"), i, e - s);
+        report_call_time(F("delay"), F("us"), i, e - s);
       }
 
       if (HW_REG(_DWT_CTRL)) {
+        static FSTR_P cyc = F("cycles");
+        static FSTR_P dcd = F("DELAY_CYCLES directly ");
+
         for (auto i : testValues) {
           s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(i); e = HW_REG(_DWT_CYCCNT);
-          report_call_time(PSTR("runtime delay"), PSTR("cycles"), i, e - s);
+          report_call_time(F("runtime delay"), cyc, i, e - s);
         }
 
         // Measure the delay to call a real function compared to a function pointer
         s = HW_REG(_DWT_CYCCNT); delay_dwt(1); e = HW_REG(_DWT_CYCCNT);
-        report_call_time(PSTR("delay_dwt"), PSTR("cycles"), 1, e - s);
-
-        static PGMSTR(dcd, "DELAY_CYCLES directly ");
+        report_call_time(F("delay_dwt"), cyc, 1, e - s);
 
         s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES( 1); e = HW_REG(_DWT_CYCCNT);
-        report_call_time(dcd, PSTR("cycles"),  1, e - s, false);
+        report_call_time(dcd, cyc,  1, e - s, false);
 
         s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES( 5); e = HW_REG(_DWT_CYCCNT);
-        report_call_time(dcd, PSTR("cycles"),  5, e - s, false);
+        report_call_time(dcd, cyc,  5, e - s, false);
 
         s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(10); e = HW_REG(_DWT_CYCCNT);
-        report_call_time(dcd, PSTR("cycles"), 10, e - s, false);
+        report_call_time(dcd, cyc, 10, e - s, false);
 
         s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(20); e = HW_REG(_DWT_CYCCNT);
-        report_call_time(dcd, PSTR("cycles"), 20, e - s, false);
+        report_call_time(dcd, cyc, 20, e - s, false);
 
         s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(50); e = HW_REG(_DWT_CYCCNT);
-        report_call_time(dcd, PSTR("cycles"), 50, e - s, false);
+        report_call_time(dcd, cyc, 50, e - s, false);
 
         s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(100); e = HW_REG(_DWT_CYCCNT);
-        report_call_time(dcd, PSTR("cycles"), 100, e - s, false);
+        report_call_time(dcd, cyc, 100, e - s, false);
 
         s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(200); e = HW_REG(_DWT_CYCCNT);
-        report_call_time(dcd, PSTR("cycles"), 200, e - s, false);
+        report_call_time(dcd, cyc, 200, e - s, false);
       }
     }
   #endif // MARLIN_DEV_MODE
@@ -170,7 +172,7 @@
 
   void calibrate_delay_loop() {}
   #if ENABLED(MARLIN_DEV_MODE)
-    void dump_delay_accuracy_check() { SERIAL_ECHOPGM_P(PSTR("N/A on this platform")); }
+    void dump_delay_accuracy_check() { SERIAL_ECHOPGM("N/A on this platform"); }
   #endif
 
 #endif
diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
index 051cb6a4d64..d78a5e25786 100644
--- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
+++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
@@ -1609,7 +1609,7 @@ void unified_bed_leveling::smart_fill_mesh() {
     }
 
     if (DEBUGGING(LEVELING)) {
-      rotation.debug(PSTR("rotation matrix:\n"));
+      rotation.debug(F("rotation matrix:\n"));
       DEBUG_ECHOPAIR_F("LSF Results A=", lsf_results.A, 7);
       DEBUG_ECHOPAIR_F("  B=", lsf_results.B, 7);
       DEBUG_ECHOLNPAIR_F("  D=", lsf_results.D, 7);
@@ -1636,14 +1636,14 @@ void unified_bed_leveling::smart_fill_mesh() {
         auto normed = [&](const xy_pos_t &pos, const_float_t zadd) {
           return normal.x * pos.x + normal.y * pos.y + zadd;
         };
-        auto debug_pt = [](PGM_P const pre, const xy_pos_t &pos, const_float_t zadd) {
-          d_from(); SERIAL_ECHOPGM_P(pre);
+        auto debug_pt = [](FSTR_P const pre, const xy_pos_t &pos, const_float_t zadd) {
+          d_from(); SERIAL_ECHOF(pre);
           DEBUG_ECHO_F(normed(pos, zadd), 6);
           DEBUG_ECHOLNPAIR_F("   Z error = ", zadd - get_z_correction(pos), 6);
         };
-        debug_pt(PSTR("1st point: "), probe_pt[0], normal.z * z1);
-        debug_pt(PSTR("2nd point: "), probe_pt[1], normal.z * z2);
-        debug_pt(PSTR("3rd point: "), probe_pt[2], normal.z * z3);
+        debug_pt(F("1st point: "), probe_pt[0], normal.z * z1);
+        debug_pt(F("2nd point: "), probe_pt[1], normal.z * z2);
+        debug_pt(F("3rd point: "), probe_pt[2], normal.z * z3);
         d_from(); DEBUG_ECHOPGM("safe home with Z=");
         DEBUG_ECHOLNPAIR_F("0 : ", normed(safe_homing_xy, 0), 6);
         d_from(); DEBUG_ECHOPGM("safe home with Z=");
diff --git a/Marlin/src/feature/max7219.cpp b/Marlin/src/feature/max7219.cpp
index e13c6f5b973..474933aa194 100644
--- a/Marlin/src/feature/max7219.cpp
+++ b/Marlin/src/feature/max7219.cpp
@@ -124,11 +124,10 @@ uint8_t Max7219::suspended; // = 0;
   #define SIG_DELAY() DELAY_NS(250)
 #endif
 
-void Max7219::error(const char * const func, const int32_t v1, const int32_t v2/*=-1*/) {
+void Max7219::error(FSTR_P const func, const int32_t v1, const int32_t v2/*=-1*/) {
   #if ENABLED(MAX7219_ERRORS)
     SERIAL_ECHOPGM("??? Max7219::");
-    SERIAL_ECHOPGM_P(func);
-    SERIAL_CHAR('(');
+    SERIAL_ECHOF(func, AS_CHAR('('));
     SERIAL_ECHO(v1);
     if (v2 > 0) SERIAL_ECHOPGM(", ", v2);
     SERIAL_CHAR(')');
@@ -268,24 +267,24 @@ void Max7219::set(const uint8_t line, const uint8_t bits) {
 
 // Modify a single LED bit and send the changed line
 void Max7219::led_set(const uint8_t x, const uint8_t y, const bool on) {
-  if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(PSTR("led_set"), x, y);
+  if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_set"), x, y);
   if (BIT_7219(x, y) == on) return;
   XOR_7219(x, y);
   refresh_unit_line(LED_IND(x, y));
 }
 
 void Max7219::led_on(const uint8_t x, const uint8_t y) {
-  if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(PSTR("led_on"), x, y);
+  if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_on"), x, y);
   led_set(x, y, true);
 }
 
 void Max7219::led_off(const uint8_t x, const uint8_t y) {
-  if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(PSTR("led_off"), x, y);
+  if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_off"), x, y);
   led_set(x, y, false);
 }
 
 void Max7219::led_toggle(const uint8_t x, const uint8_t y) {
-  if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(PSTR("led_toggle"), x, y);
+  if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_toggle"), x, y);
   led_set(x, y, !BIT_7219(x, y));
 }
 
@@ -328,13 +327,13 @@ void Max7219::fill() {
 }
 
 void Max7219::clear_row(const uint8_t row) {
-  if (row >= MAX7219_Y_LEDS) return error(PSTR("clear_row"), row);
+  if (row >= MAX7219_Y_LEDS) return error(F("clear_row"), row);
   LOOP_L_N(x, MAX7219_X_LEDS) CLR_7219(x, row);
   send_row(row);
 }
 
 void Max7219::clear_column(const uint8_t col) {
-  if (col >= MAX7219_X_LEDS) return error(PSTR("set_column"), col);
+  if (col >= MAX7219_X_LEDS) return error(F("set_column"), col);
   LOOP_L_N(y, MAX7219_Y_LEDS) CLR_7219(col, y);
   send_column(col);
 }
@@ -345,7 +344,7 @@ void Max7219::clear_column(const uint8_t col) {
  * once with a single call to the function (if rotated 90° or 270°).
  */
 void Max7219::set_row(const uint8_t row, const uint32_t val) {
-  if (row >= MAX7219_Y_LEDS) return error(PSTR("set_row"), row);
+  if (row >= MAX7219_Y_LEDS) return error(F("set_row"), row);
   uint32_t mask = _BV32(MAX7219_X_LEDS - 1);
   LOOP_L_N(x, MAX7219_X_LEDS) {
     if (val & mask) SET_7219(x, row); else CLR_7219(x, row);
@@ -360,7 +359,7 @@ void Max7219::set_row(const uint8_t row, const uint32_t val) {
  * once with a single call to the function (if rotated 0° or 180°).
  */
 void Max7219::set_column(const uint8_t col, const uint32_t val) {
-  if (col >= MAX7219_X_LEDS) return error(PSTR("set_column"), col);
+  if (col >= MAX7219_X_LEDS) return error(F("set_column"), col);
   uint32_t mask = _BV32(MAX7219_Y_LEDS - 1);
   LOOP_L_N(y, MAX7219_Y_LEDS) {
     if (val & mask) SET_7219(col, y); else CLR_7219(col, y);
@@ -371,56 +370,56 @@ void Max7219::set_column(const uint8_t col, const uint32_t val) {
 
 void Max7219::set_rows_16bits(const uint8_t y, uint32_t val) {
   #if MAX7219_X_LEDS == 8
-    if (y > MAX7219_Y_LEDS - 2) return error(PSTR("set_rows_16bits"), y, val);
+    if (y > MAX7219_Y_LEDS - 2) return error(F("set_rows_16bits"), y, val);
     set_row(y + 1, val); val >>= 8;
     set_row(y + 0, val);
   #else // at least 16 bits on each row
-    if (y > MAX7219_Y_LEDS - 1) return error(PSTR("set_rows_16bits"), y, val);
+    if (y > MAX7219_Y_LEDS - 1) return error(F("set_rows_16bits"), y, val);
     set_row(y, val);
   #endif
 }
 
 void Max7219::set_rows_32bits(const uint8_t y, uint32_t val) {
   #if MAX7219_X_LEDS == 8
-    if (y > MAX7219_Y_LEDS - 4) return error(PSTR("set_rows_32bits"), y, val);
+    if (y > MAX7219_Y_LEDS - 4) return error(F("set_rows_32bits"), y, val);
     set_row(y + 3, val); val >>= 8;
     set_row(y + 2, val); val >>= 8;
     set_row(y + 1, val); val >>= 8;
     set_row(y + 0, val);
   #elif MAX7219_X_LEDS == 16
-    if (y > MAX7219_Y_LEDS - 2) return error(PSTR("set_rows_32bits"), y, val);
+    if (y > MAX7219_Y_LEDS - 2) return error(F("set_rows_32bits"), y, val);
     set_row(y + 1, val); val >>= 16;
     set_row(y + 0, val);
   #else // at least 24 bits on each row.  In the 3 matrix case, just display the low 24 bits
-    if (y > MAX7219_Y_LEDS - 1) return error(PSTR("set_rows_32bits"), y, val);
+    if (y > MAX7219_Y_LEDS - 1) return error(F("set_rows_32bits"), y, val);
     set_row(y, val);
   #endif
 }
 
 void Max7219::set_columns_16bits(const uint8_t x, uint32_t val) {
   #if MAX7219_Y_LEDS == 8
-    if (x > MAX7219_X_LEDS - 2) return error(PSTR("set_columns_16bits"), x, val);
+    if (x > MAX7219_X_LEDS - 2) return error(F("set_columns_16bits"), x, val);
     set_column(x + 0, val); val >>= 8;
     set_column(x + 1, val);
   #else // at least 16 bits in each column
-    if (x > MAX7219_X_LEDS - 1) return error(PSTR("set_columns_16bits"), x, val);
+    if (x > MAX7219_X_LEDS - 1) return error(F("set_columns_16bits"), x, val);
     set_column(x, val);
   #endif
 }
 
 void Max7219::set_columns_32bits(const uint8_t x, uint32_t val) {
   #if MAX7219_Y_LEDS == 8
-    if (x > MAX7219_X_LEDS - 4) return error(PSTR("set_rows_32bits"), x, val);
+    if (x > MAX7219_X_LEDS - 4) return error(F("set_rows_32bits"), x, val);
     set_column(x + 3, val); val >>= 8;
     set_column(x + 2, val); val >>= 8;
     set_column(x + 1, val); val >>= 8;
     set_column(x + 0, val);
   #elif MAX7219_Y_LEDS == 16
-    if (x > MAX7219_X_LEDS - 2) return error(PSTR("set_rows_32bits"), x, val);
+    if (x > MAX7219_X_LEDS - 2) return error(F("set_rows_32bits"), x, val);
     set_column(x + 1, val); val >>= 16;
     set_column(x + 0, val);
   #else // at least 24 bits on each row.  In the 3 matrix case, just display the low 24 bits
-    if (x > MAX7219_X_LEDS - 1) return error(PSTR("set_rows_32bits"), x, val);
+    if (x > MAX7219_X_LEDS - 1) return error(F("set_rows_32bits"), x, val);
     set_column(x, val);
   #endif
 }
diff --git a/Marlin/src/feature/max7219.h b/Marlin/src/feature/max7219.h
index 3e5b62db2f7..c25fef17306 100644
--- a/Marlin/src/feature/max7219.h
+++ b/Marlin/src/feature/max7219.h
@@ -42,6 +42,8 @@
  * a Max7219_Set_Row().    The opposite is true for rotations of 0 or 180 degrees.
  */
 
+#include "../inc/MarlinConfig.h"
+
 #ifndef MAX7219_ROTATE
   #define MAX7219_ROTATE 0
 #endif
@@ -140,7 +142,7 @@ public:
 
 private:
   static uint8_t suspended;
-  static void error(const char * const func, const int32_t v1, const int32_t v2=-1);
+  static void error(FSTR_P const func, const int32_t v1, const int32_t v2=-1);
   static void noop();
   static void set(const uint8_t line, const uint8_t bits);
   static void send_row(const uint8_t row);
diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp
index 9808113ecc1..bc19c9b18e7 100644
--- a/Marlin/src/feature/powerloss.cpp
+++ b/Marlin/src/feature/powerloss.cpp
@@ -130,7 +130,7 @@ void PrintJobRecovery::load() {
     (void)file.read(&info, sizeof(info));
     close();
   }
-  debug(PSTR("Load"));
+  debug(F("Load"));
 }
 
 /**
@@ -311,7 +311,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW
  */
 void PrintJobRecovery::write() {
 
-  debug(PSTR("Write"));
+  debug(F("Write"));
 
   open(false);
   file.seekSet(0);
@@ -575,8 +575,8 @@ void PrintJobRecovery::resume() {
 
 #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
 
-  void PrintJobRecovery::debug(PGM_P const prefix) {
-    DEBUG_ECHOPGM_P(prefix);
+  void PrintJobRecovery::debug(FSTR_P const prefix) {
+    DEBUG_ECHOF(prefix);
     DEBUG_ECHOLNPGM(" Job Recovery Info...\nvalid_head:", info.valid_head, " valid_foot:", info.valid_foot);
     if (info.valid_head) {
       if (info.valid_head == info.valid_foot) {
diff --git a/Marlin/src/feature/powerloss.h b/Marlin/src/feature/powerloss.h
index 6a13c92df79..76cb398af2a 100644
--- a/Marlin/src/feature/powerloss.h
+++ b/Marlin/src/feature/powerloss.h
@@ -204,9 +204,9 @@ class PrintJobRecovery {
     static inline bool valid() { return info.valid() && interrupted_file_exists(); }
 
     #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
-      static void debug(PGM_P const prefix);
+      static void debug(FSTR_P const prefix);
     #else
-      static inline void debug(PGM_P const) {}
+      static inline void debug(FSTR_P const) {}
     #endif
 
   private:
diff --git a/Marlin/src/feature/stepper_driver_safety.cpp b/Marlin/src/feature/stepper_driver_safety.cpp
index 8ba0968cd28..11b90954b4f 100644
--- a/Marlin/src/feature/stepper_driver_safety.cpp
+++ b/Marlin/src/feature/stepper_driver_safety.cpp
@@ -28,11 +28,11 @@
 
 static uint32_t axis_plug_backward = 0;
 
-void stepper_driver_backward_error(PGM_P str) {
+void stepper_driver_backward_error(FSTR_P const fstr) {
   SERIAL_ERROR_START();
-  SERIAL_ECHOPGM_P(str);
+  SERIAL_ECHOF(fstr);
   SERIAL_ECHOLNPGM(" driver is backward!");
-  ui.status_printf(2, F(S_FMT S_FMT), str, GET_TEXT(MSG_DRIVER_BACKWARD));
+  ui.status_printf(2, F(S_FMT S_FMT), FTOP(fstr), GET_TEXT(MSG_DRIVER_BACKWARD));
 }
 
 void stepper_driver_backward_check() {
@@ -45,7 +45,7 @@ void stepper_driver_backward_check() {
       delay(20); \
       if (READ(AXIS##_ENABLE_PIN) == false) { \
         SBI(axis_plug_backward, BIT); \
-        stepper_driver_backward_error(PSTR(STRINGIFY(AXIS))); \
+        stepper_driver_backward_error(F(STRINGIFY(AXIS))); \
       } \
     }while(0)
 
@@ -82,12 +82,12 @@ void stepper_driver_backward_check() {
 void stepper_driver_backward_report() {
   if (!axis_plug_backward) return;
 
-  auto _report_if_backward = [](PGM_P axis, uint8_t bit) {
+  auto _report_if_backward = [](FSTR_P const axis, uint8_t bit) {
     if (TEST(axis_plug_backward, bit))
       stepper_driver_backward_error(axis);
   };
 
-  #define REPORT_BACKWARD(axis, bit) TERN_(HAS_##axis##_ENABLE, _report_if_backward(PSTR(STRINGIFY(axis)), bit))
+  #define REPORT_BACKWARD(axis, bit) TERN_(HAS_##axis##_ENABLE, _report_if_backward(F(STRINGIFY(axis)), bit))
 
   REPORT_BACKWARD(X,   0);
   REPORT_BACKWARD(X2,  1);
diff --git a/Marlin/src/feature/twibus.cpp b/Marlin/src/feature/twibus.cpp
index 5f5209cdd48..55e4da75cfb 100644
--- a/Marlin/src/feature/twibus.cpp
+++ b/Marlin/src/feature/twibus.cpp
@@ -51,27 +51,27 @@ void TWIBus::address(const uint8_t adr) {
 
   addr = adr;
 
-  debug(PSTR("address"), adr);
+  debug(F("address"), adr);
 }
 
 void TWIBus::addbyte(const char c) {
   if (buffer_s >= COUNT(buffer)) return;
   buffer[buffer_s++] = c;
-  debug(PSTR("addbyte"), c);
+  debug(F("addbyte"), c);
 }
 
 void TWIBus::addbytes(char src[], uint8_t bytes) {
-  debug(PSTR("addbytes"), bytes);
+  debug(F("addbytes"), bytes);
   while (bytes--) addbyte(*src++);
 }
 
 void TWIBus::addstring(char str[]) {
-  debug(PSTR("addstring"), str);
+  debug(F("addstring"), str);
   while (char c = *str++) addbyte(c);
 }
 
 void TWIBus::send() {
-  debug(PSTR("send"), addr);
+  debug(F("send"), addr);
 
   Wire.beginTransmission(I2C_ADDRESS(addr));
   Wire.write(buffer, buffer_s);
@@ -81,20 +81,20 @@ void TWIBus::send() {
 }
 
 // static
-void TWIBus::echoprefix(uint8_t bytes, const char pref[], uint8_t adr) {
+void TWIBus::echoprefix(uint8_t bytes, FSTR_P const pref, uint8_t adr) {
   SERIAL_ECHO_START();
-  SERIAL_ECHOPGM_P(pref);
+  SERIAL_ECHOF(pref);
   SERIAL_ECHOPGM(": from:", adr, " bytes:", bytes, " data:");
 }
 
 // static
-void TWIBus::echodata(uint8_t bytes, const char pref[], uint8_t adr) {
+void TWIBus::echodata(uint8_t bytes, FSTR_P const pref, uint8_t adr) {
   echoprefix(bytes, pref, adr);
   while (bytes-- && Wire.available()) SERIAL_CHAR(Wire.read());
   SERIAL_EOL();
 }
 
-void TWIBus::echobuffer(const char pref[], uint8_t adr) {
+void TWIBus::echobuffer(FSTR_P const pref, uint8_t adr) {
   echoprefix(buffer_s, pref, adr);
   LOOP_L_N(i, buffer_s) SERIAL_CHAR(buffer[i]);
   SERIAL_EOL();
@@ -103,11 +103,11 @@ void TWIBus::echobuffer(const char pref[], uint8_t adr) {
 bool TWIBus::request(const uint8_t bytes) {
   if (!addr) return false;
 
-  debug(PSTR("request"), bytes);
+  debug(F("request"), bytes);
 
   // requestFrom() is a blocking function
   if (Wire.requestFrom(I2C_ADDRESS(addr), bytes) == 0) {
-    debug("request fail", I2C_ADDRESS(addr));
+    debug(F("request fail"), I2C_ADDRESS(addr));
     return false;
   }
 
@@ -115,10 +115,10 @@ bool TWIBus::request(const uint8_t bytes) {
 }
 
 void TWIBus::relay(const uint8_t bytes) {
-  debug(PSTR("relay"), bytes);
+  debug(F("relay"), bytes);
 
   if (request(bytes))
-    echodata(bytes, PSTR("i2c-reply"), addr);
+    echodata(bytes, F("i2c-reply"), addr);
 }
 
 uint8_t TWIBus::capture(char *dst, const uint8_t bytes) {
@@ -127,7 +127,7 @@ uint8_t TWIBus::capture(char *dst, const uint8_t bytes) {
   while (count < bytes && Wire.available())
     dst[count++] = Wire.read();
 
-  debug(PSTR("capture"), count);
+  debug(F("capture"), count);
 
   return count;
 }
@@ -140,12 +140,12 @@ void TWIBus::flush() {
 #if I2C_SLAVE_ADDRESS > 0
 
   void TWIBus::receive(uint8_t bytes) {
-    debug(PSTR("receive"), bytes);
-    echodata(bytes, PSTR("i2c-receive"), 0);
+    debug(F("receive"), bytes);
+    echodata(bytes, F("i2c-receive"), 0);
   }
 
   void TWIBus::reply(char str[]/*=nullptr*/) {
-    debug(PSTR("reply"), str);
+    debug(F("reply"), str);
 
     if (str) {
       reset();
@@ -170,18 +170,16 @@ void TWIBus::flush() {
 #if ENABLED(DEBUG_TWIBUS)
 
   // static
-  void TWIBus::prefix(const char func[]) {
-    SERIAL_ECHOPGM("TWIBus::");
-    SERIAL_ECHOPGM_P(func);
-    SERIAL_ECHOPGM(": ");
+  void TWIBus::prefix(FSTR_P const func) {
+    SERIAL_ECHOPGM("TWIBus::", func, ": ");
   }
-  void TWIBus::debug(const char func[], uint32_t adr) {
+  void TWIBus::debug(FSTR_P const func, uint32_t adr) {
     if (DEBUGGING(INFO)) { prefix(func); SERIAL_ECHOLN(adr); }
   }
-  void TWIBus::debug(const char func[], char c) {
+  void TWIBus::debug(FSTR_P const func, char c) {
     if (DEBUGGING(INFO)) { prefix(func); SERIAL_ECHOLN(c); }
   }
-  void TWIBus::debug(const char func[], char str[]) {
+  void TWIBus::debug(FSTR_P const func, char str[]) {
     if (DEBUGGING(INFO)) { prefix(func); SERIAL_ECHOLN(str); }
   }
 
diff --git a/Marlin/src/feature/twibus.h b/Marlin/src/feature/twibus.h
index 59391534824..2a8a7fef6ac 100644
--- a/Marlin/src/feature/twibus.h
+++ b/Marlin/src/feature/twibus.h
@@ -142,7 +142,7 @@ class TWIBus {
      *
      * @param bytes the number of bytes to request
      */
-    static void echoprefix(uint8_t bytes, const char prefix[], uint8_t adr);
+    static void echoprefix(uint8_t bytes, FSTR_P prefix, uint8_t adr);
 
     /**
      * @brief Echo data on the bus to serial
@@ -151,7 +151,7 @@ class TWIBus {
      *
      * @param bytes the number of bytes to request
      */
-    static void echodata(uint8_t bytes, const char prefix[], uint8_t adr);
+    static void echodata(uint8_t bytes, FSTR_P prefix, uint8_t adr);
 
     /**
      * @brief Echo data in the buffer to serial
@@ -160,7 +160,7 @@ class TWIBus {
      *
      * @param bytes the number of bytes to request
      */
-    void echobuffer(const char prefix[], uint8_t adr);
+    void echobuffer(FSTR_P prefix, uint8_t adr);
 
     /**
      * @brief Request data from the slave device and wait.
@@ -237,17 +237,16 @@ class TWIBus {
        * @brief Prints a debug message
        * @details Prints a simple debug message "TWIBus::function: value"
        */
-      static void prefix(const char func[]);
-      static void debug(const char func[], uint32_t adr);
-      static void debug(const char func[], char c);
-      static void debug(const char func[], char adr[]);
-      static inline void debug(const char func[], uint8_t v) { debug(func, (uint32_t)v); }
+      static void prefix(FSTR_P const func);
+      static void debug(FSTR_P const func, uint32_t adr);
+      static void debug(FSTR_P const func, char c);
+      static void debug(FSTR_P const func, char adr[]);
     #else
-      static inline void debug(const char[], uint32_t) {}
-      static inline void debug(const char[], char) {}
-      static inline void debug(const char[], char[]) {}
-      static inline void debug(const char[], uint8_t) {}
+      static inline void debug(FSTR_P const, uint32_t) {}
+      static inline void debug(FSTR_P const, char) {}
+      static inline void debug(FSTR_P const, char[]) {}
     #endif
+    static inline void debug(FSTR_P const func, uint8_t v) { debug(func, (uint32_t)v); }
 };
 
 extern TWIBus i2c;
diff --git a/Marlin/src/gcode/bedlevel/M420.cpp b/Marlin/src/gcode/bedlevel/M420.cpp
index 5dcef961eed..3c23e85a1df 100644
--- a/Marlin/src/gcode/bedlevel/M420.cpp
+++ b/Marlin/src/gcode/bedlevel/M420.cpp
@@ -195,7 +195,7 @@ void GcodeSuite::M420() {
   // V to print the matrix or mesh
   if (seenV) {
     #if ABL_PLANAR
-      planner.bed_level_matrix.debug(PSTR("Bed Level Correction Matrix:"));
+      planner.bed_level_matrix.debug(F("Bed Level Correction Matrix:"));
     #else
       if (leveling_is_valid()) {
         #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp
index 07aefe8aed8..f7afd93c819 100644
--- a/Marlin/src/gcode/bedlevel/abl/G29.cpp
+++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp
@@ -783,8 +783,8 @@ G29_TYPE GcodeSuite::G29() {
 
         float min_diff = 999;
 
-        auto print_topo_map = [&](PGM_P const title, const bool get_min) {
-          SERIAL_ECHOPGM_P(title);
+        auto print_topo_map = [&](FSTR_P const title, const bool get_min) {
+          SERIAL_ECHOF(title);
           for (int8_t yy = abl.grid_points.y - 1; yy >= 0; yy--) {
             LOOP_L_N(xx, abl.grid_points.x) {
               const int ind = abl.indexIntoAB[xx][yy];
@@ -802,19 +802,19 @@ G29_TYPE GcodeSuite::G29() {
           SERIAL_EOL();
         };
 
-        print_topo_map(PSTR("\nBed Height Topography:\n"
-                               "   +--- BACK --+\n"
-                               "   |           |\n"
-                               " L |    (+)    | R\n"
-                               " E |           | I\n"
-                               " F | (-) N (+) | G\n"
-                               " T |           | H\n"
-                               "   |    (-)    | T\n"
-                               "   |           |\n"
-                               "   O-- FRONT --+\n"
-                               " (0,0)\n"), true);
+        print_topo_map(F("\nBed Height Topography:\n"
+                           "   +--- BACK --+\n"
+                           "   |           |\n"
+                           " L |    (+)    | R\n"
+                           " E |           | I\n"
+                           " F | (-) N (+) | G\n"
+                           " T |           | H\n"
+                           "   |    (-)    | T\n"
+                           "   |           |\n"
+                           "   O-- FRONT --+\n"
+                           " (0,0)\n"), true);
         if (abl.verbose_level > 3)
-          print_topo_map(PSTR("\nCorrected Bed Height vs. Bed Topology:\n"), false);
+          print_topo_map(F("\nCorrected Bed Height vs. Bed Topology:\n"), false);
 
       } // abl.topography_map
 
@@ -825,7 +825,7 @@ G29_TYPE GcodeSuite::G29() {
       // For LINEAR and 3POINT leveling correct the current position
 
       if (abl.verbose_level > 0)
-        planner.bed_level_matrix.debug(PSTR("\n\nBed Level Correction Matrix:"));
+        planner.bed_level_matrix.debug(F("\n\nBed Level Correction Matrix:"));
 
       if (!abl.dryrun) {
         //
diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp
index cd6a3a760dd..95f2a9b1761 100644
--- a/Marlin/src/gcode/calibrate/G28.cpp
+++ b/Marlin/src/gcode/calibrate/G28.cpp
@@ -269,33 +269,33 @@ void GcodeSuite::G28() {
   #endif
 
   #if HAS_HOMING_CURRENT
-    auto debug_current = [](PGM_P const s, const int16_t a, const int16_t b) {
-      DEBUG_ECHOPGM_P(s); DEBUG_ECHOLNPGM(" current: ", a, " -> ", b);
+    auto debug_current = [](FSTR_P const s, const int16_t a, const int16_t b) {
+      DEBUG_ECHOF(s); DEBUG_ECHOLNPGM(" current: ", a, " -> ", b);
     };
     #if HAS_CURRENT_HOME(X)
       const int16_t tmc_save_current_X = stepperX.getMilliamps();
       stepperX.rms_current(X_CURRENT_HOME);
-      if (DEBUGGING(LEVELING)) debug_current(PSTR("X"), tmc_save_current_X, X_CURRENT_HOME);
+      if (DEBUGGING(LEVELING)) debug_current(F("X"), tmc_save_current_X, X_CURRENT_HOME);
     #endif
     #if HAS_CURRENT_HOME(X2)
       const int16_t tmc_save_current_X2 = stepperX2.getMilliamps();
       stepperX2.rms_current(X2_CURRENT_HOME);
-      if (DEBUGGING(LEVELING)) debug_current(PSTR("X2"), tmc_save_current_X2, X2_CURRENT_HOME);
+      if (DEBUGGING(LEVELING)) debug_current(F("X2"), tmc_save_current_X2, X2_CURRENT_HOME);
     #endif
     #if HAS_CURRENT_HOME(Y)
       const int16_t tmc_save_current_Y = stepperY.getMilliamps();
       stepperY.rms_current(Y_CURRENT_HOME);
-      if (DEBUGGING(LEVELING)) debug_current(PSTR("Y"), tmc_save_current_Y, Y_CURRENT_HOME);
+      if (DEBUGGING(LEVELING)) debug_current(F("Y"), tmc_save_current_Y, Y_CURRENT_HOME);
     #endif
     #if HAS_CURRENT_HOME(Y2)
       const int16_t tmc_save_current_Y2 = stepperY2.getMilliamps();
       stepperY2.rms_current(Y2_CURRENT_HOME);
-      if (DEBUGGING(LEVELING)) debug_current(PSTR("Y2"), tmc_save_current_Y2, Y2_CURRENT_HOME);
+      if (DEBUGGING(LEVELING)) debug_current(F("Y2"), tmc_save_current_Y2, Y2_CURRENT_HOME);
     #endif
     #if HAS_CURRENT_HOME(Z) && ENABLED(DELTA)
       const int16_t tmc_save_current_Z = stepperZ.getMilliamps();
       stepperZ.rms_current(Z_CURRENT_HOME);
-      if (DEBUGGING(LEVELING)) debug_current(PSTR("Z"), tmc_save_current_Z, Z_CURRENT_HOME);
+      if (DEBUGGING(LEVELING)) debug_current(F("Z"), tmc_save_current_Z, Z_CURRENT_HOME);
     #endif
   #endif
 
diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp
index 39494cde24e..8a9de498805 100644
--- a/Marlin/src/gcode/calibrate/G33.cpp
+++ b/Marlin/src/gcode/calibrate/G33.cpp
@@ -97,10 +97,9 @@ void ac_cleanup(TERN_(HAS_MULTI_HOTEND, const uint8_t old_tool_index)) {
   TERN_(HAS_MULTI_HOTEND, tool_change(old_tool_index, true));
 }
 
-void print_signed_float(PGM_P const prefix, const_float_t f) {
+void print_signed_float(FSTR_P const prefix, const_float_t f) {
   SERIAL_ECHOPGM("  ");
-  SERIAL_ECHOPGM_P(prefix);
-  SERIAL_CHAR(':');
+  SERIAL_ECHOF(prefix, AS_CHAR(':'));
   if (f >= 0) SERIAL_CHAR('+');
   SERIAL_ECHO_F(f, 2);
 }
@@ -111,24 +110,23 @@ void print_signed_float(PGM_P const prefix, const_float_t f) {
 static void print_calibration_settings(const bool end_stops, const bool tower_angles) {
   SERIAL_ECHOPGM(".Height:", delta_height);
   if (end_stops) {
-    print_signed_float(PSTR("Ex"), delta_endstop_adj.a);
-    print_signed_float(PSTR("Ey"), delta_endstop_adj.b);
-    print_signed_float(PSTR("Ez"), delta_endstop_adj.c);
+    print_signed_float(F("Ex"), delta_endstop_adj.a);
+    print_signed_float(F("Ey"), delta_endstop_adj.b);
+    print_signed_float(F("Ez"), delta_endstop_adj.c);
   }
   if (end_stops && tower_angles) {
-    SERIAL_ECHOPGM("  Radius:", delta_radius);
-    SERIAL_EOL();
+    SERIAL_ECHOLNPGM("  Radius:", delta_radius);
     SERIAL_CHAR('.');
     SERIAL_ECHO_SP(13);
   }
   if (tower_angles) {
-    print_signed_float(PSTR("Tx"), delta_tower_angle_trim.a);
-    print_signed_float(PSTR("Ty"), delta_tower_angle_trim.b);
-    print_signed_float(PSTR("Tz"), delta_tower_angle_trim.c);
+    print_signed_float(F("Tx"), delta_tower_angle_trim.a);
+    print_signed_float(F("Ty"), delta_tower_angle_trim.b);
+    print_signed_float(F("Tz"), delta_tower_angle_trim.c);
   }
-  if ((!end_stops && tower_angles) || (end_stops && !tower_angles)) { // XOR
+  if (end_stops != tower_angles)
     SERIAL_ECHOPGM("  Radius:", delta_radius);
-  }
+
   SERIAL_EOL();
 }
 
@@ -137,11 +135,11 @@ static void print_calibration_settings(const bool end_stops, const bool tower_an
  */
 static void print_calibration_results(const float z_pt[NPP + 1], const bool tower_points, const bool opposite_points) {
   SERIAL_ECHOPGM(".    ");
-  print_signed_float(PSTR("c"), z_pt[CEN]);
+  print_signed_float(F("c"), z_pt[CEN]);
   if (tower_points) {
-    print_signed_float(PSTR(" x"), z_pt[__A]);
-    print_signed_float(PSTR(" y"), z_pt[__B]);
-    print_signed_float(PSTR(" z"), z_pt[__C]);
+    print_signed_float(F(" x"), z_pt[__A]);
+    print_signed_float(F(" y"), z_pt[__B]);
+    print_signed_float(F(" z"), z_pt[__C]);
   }
   if (tower_points && opposite_points) {
     SERIAL_EOL();
@@ -149,9 +147,9 @@ static void print_calibration_results(const float z_pt[NPP + 1], const bool towe
     SERIAL_ECHO_SP(13);
   }
   if (opposite_points) {
-    print_signed_float(PSTR("yz"), z_pt[_BC]);
-    print_signed_float(PSTR("zx"), z_pt[_CA]);
-    print_signed_float(PSTR("xy"), z_pt[_AB]);
+    print_signed_float(F("yz"), z_pt[_BC]);
+    print_signed_float(F("zx"), z_pt[_CA]);
+    print_signed_float(F("xy"), z_pt[_AB]);
   }
   SERIAL_EOL();
 }
@@ -653,13 +651,13 @@ void GcodeSuite::G33() {
       }
     }
     else { // dry run
-      PGM_P const enddryrun = PSTR("End DRY-RUN");
-      SERIAL_ECHOPGM_P(enddryrun);
+      FSTR_P const enddryrun = F("End DRY-RUN");
+      SERIAL_ECHOF(enddryrun);
       SERIAL_ECHO_SP(35);
       SERIAL_ECHOLNPAIR_F("std dev:", zero_std_dev, 3);
 
       char mess[21];
-      strcpy_P(mess, enddryrun);
+      strcpy_P(mess, FTOP(enddryrun));
       strcpy_P(&mess[11], PSTR(" sd:"));
       if (zero_std_dev < 1)
         sprintf_P(&mess[15], PSTR("0.%03i"), (int)LROUND(zero_std_dev * 1000.0f));
diff --git a/Marlin/src/gcode/calibrate/M100.cpp b/Marlin/src/gcode/calibrate/M100.cpp
index 0e2d42907a2..338392b5974 100644
--- a/Marlin/src/gcode/calibrate/M100.cpp
+++ b/Marlin/src/gcode/calibrate/M100.cpp
@@ -51,7 +51,7 @@
  * Also, there are two support functions that can be called from a developer's C code.
  *
  *    uint16_t check_for_free_memory_corruption(PGM_P const free_memory_start);
- *    void M100_dump_routine(PGM_P const title, const char * const start, const uintptr_t size);
+ *    void M100_dump_routine(FSTR_P const title, const char * const start, const uintptr_t size);
  *
  * Initial version by Roxy-3D
  */
@@ -182,8 +182,8 @@ inline int32_t count_test_bytes(const char * const start_free_memory) {
     }
   }
 
-  void M100_dump_routine(PGM_P const title, const char * const start, const uintptr_t size) {
-    SERIAL_ECHOLNPGM_P(title);
+  void M100_dump_routine(FSTR_P const title, const char * const start, const uintptr_t size) {
+    SERIAL_ECHOLNF(title);
     //
     // Round the start and end locations to produce full lines of output
     //
@@ -196,8 +196,8 @@ inline int32_t count_test_bytes(const char * const start_free_memory) {
 
 #endif // M100_FREE_MEMORY_DUMPER
 
-inline int check_for_free_memory_corruption(PGM_P const title) {
-  SERIAL_ECHOPGM_P(title);
+inline int check_for_free_memory_corruption(FSTR_P const title) {
+  SERIAL_ECHOF(title);
 
   char *start_free_memory = free_memory_start, *end_free_memory = free_memory_end;
   int n = end_free_memory - start_free_memory;
@@ -217,7 +217,7 @@ inline int check_for_free_memory_corruption(PGM_P const title) {
     //  idle();
     serial_delay(20);
     #if ENABLED(M100_FREE_MEMORY_DUMPER)
-      M100_dump_routine(PSTR("   Memory corruption detected with end_free_memory<Heap\n"), (const char*)0x1B80, 0x0680);
+      M100_dump_routine(F("   Memory corruption detected with end_free_memory<Heap\n"), (const char*)0x1B80, 0x0680);
     #endif
   }
 
@@ -281,7 +281,7 @@ inline void free_memory_pool_report(char * const start_free_memory, const int32_
     "\nMemory Corruption detected in free memory area."
     "\nLargest free block is ", max_cnt, " bytes at ", hex_address(max_addr)
   );
-  SERIAL_ECHOLNPGM("check_for_free_memory_corruption() = ", check_for_free_memory_corruption(PSTR("M100 F ")));
+  SERIAL_ECHOLNPGM("check_for_free_memory_corruption() = ", check_for_free_memory_corruption(F("M100 F ")));
 }
 
 #if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
diff --git a/Marlin/src/gcode/config/M43.cpp b/Marlin/src/gcode/config/M43.cpp
index 82089b7d977..2c778fd0063 100644
--- a/Marlin/src/gcode/config/M43.cpp
+++ b/Marlin/src/gcode/config/M43.cpp
@@ -65,12 +65,12 @@ inline void toggle_pins() {
     pin_t pin = GET_PIN_MAP_PIN_M43(i);
     if (!VALID_PIN(pin)) continue;
     if (M43_NEVER_TOUCH(i) || (!ignore_protection && pin_is_protected(pin))) {
-      report_pin_state_extended(pin, ignore_protection, true, PSTR("Untouched "));
+      report_pin_state_extended(pin, ignore_protection, true, F("Untouched "));
       SERIAL_EOL();
     }
     else {
       watchdog_refresh();
-      report_pin_state_extended(pin, ignore_protection, true, PSTR("Pulsing   "));
+      report_pin_state_extended(pin, ignore_protection, true, F("Pulsing   "));
       #ifdef __STM32F1__
         const auto prior_mode = _GET_MODE(i);
       #else
@@ -303,7 +303,7 @@ void GcodeSuite::M43() {
   if (parser.seen('E')) {
     endstops.monitor_flag = parser.value_bool();
     SERIAL_ECHOPGM("endstop monitor ");
-    SERIAL_ECHOPGM_P(endstops.monitor_flag ? PSTR("en") : PSTR("dis"));
+    SERIAL_ECHOF(endstops.monitor_flag ? F("en") : F("dis"));
     SERIAL_ECHOLNPGM("abled");
     return;
   }
diff --git a/Marlin/src/gcode/feature/network/M552-M554.cpp b/Marlin/src/gcode/feature/network/M552-M554.cpp
index 887e67f3bde..0973fb87bf1 100644
--- a/Marlin/src/gcode/feature/network/M552-M554.cpp
+++ b/Marlin/src/gcode/feature/network/M552-M554.cpp
@@ -57,14 +57,14 @@ void MAC_report() {
 
 // Display current values when the link is active,
 // otherwise show the stored values
-void ip_report(const uint16_t cmd, PGM_P const post, const IPAddress &ipo) {
+void ip_report(const uint16_t cmd, FSTR_P const post, const IPAddress &ipo) {
   SERIAL_CHAR('M'); SERIAL_ECHO(cmd); SERIAL_CHAR(' ');
   LOOP_L_N(i, 4) {
     SERIAL_ECHO(ipo[i]);
     if (i < 3) SERIAL_CHAR('.');
   }
   SERIAL_ECHOPGM(" ; ");
-  SERIAL_ECHOLNPGM_P(post);
+  SERIAL_ECHOLNF(post);
 }
 
 /**
@@ -98,7 +98,7 @@ void GcodeSuite::M552() {
 }
 
 void GcodeSuite::M552_report() {
-  ip_report(552, PSTR("ip address"), Ethernet.linkStatus() == LinkON ? Ethernet.localIP() : ethernet.ip);
+  ip_report(552, F("ip address"), Ethernet.linkStatus() == LinkON ? Ethernet.localIP() : ethernet.ip);
 }
 
 /**
@@ -112,7 +112,7 @@ void GcodeSuite::M553() {
 }
 
 void GcodeSuite::M553_report() {
-  ip_report(553, PSTR("subnet mask"), Ethernet.linkStatus() == LinkON ? Ethernet.subnetMask() : ethernet.subnet);
+  ip_report(553, F("subnet mask"), Ethernet.linkStatus() == LinkON ? Ethernet.subnetMask() : ethernet.subnet);
 }
 
 /**
@@ -126,7 +126,7 @@ void GcodeSuite::M554() {
 }
 
 void GcodeSuite::M554_report() {
-  ip_report(554, PSTR("gateway"), Ethernet.linkStatus() == LinkON ? Ethernet.gatewayIP() : ethernet.gateway);
+  ip_report(554, F("gateway"), Ethernet.linkStatus() == LinkON ? Ethernet.gatewayIP() : ethernet.gateway);
 }
 
 #endif // HAS_ETHERNET
diff --git a/Marlin/src/gcode/feature/powerloss/M1000.cpp b/Marlin/src/gcode/feature/powerloss/M1000.cpp
index 3ebb286b577..c086ca842c1 100644
--- a/Marlin/src/gcode/feature/powerloss/M1000.cpp
+++ b/Marlin/src/gcode/feature/powerloss/M1000.cpp
@@ -44,10 +44,10 @@
 
 void menu_job_recovery();
 
-inline void plr_error(PGM_P const prefix) {
+inline void plr_error(FSTR_P const prefix) {
   #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
     DEBUG_ECHO_START();
-    DEBUG_ECHOPGM_P(prefix);
+    DEBUG_ECHOF(prefix);
     DEBUG_ECHOLNPGM(" Job Recovery Data");
   #else
     UNUSED(prefix);
@@ -91,7 +91,7 @@ void GcodeSuite::M1000() {
       recovery.resume();
   }
   else
-    plr_error(recovery.info.valid_head ? PSTR("No") : PSTR("Invalid"));
+    plr_error(recovery.info.valid_head ? F("No") : F("Invalid"));
 
 }
 
diff --git a/Marlin/src/gcode/feature/powerloss/M413.cpp b/Marlin/src/gcode/feature/powerloss/M413.cpp
index e02bd4bd951..0ccbfe6341a 100644
--- a/Marlin/src/gcode/feature/powerloss/M413.cpp
+++ b/Marlin/src/gcode/feature/powerloss/M413.cpp
@@ -47,7 +47,7 @@ void GcodeSuite::M413() {
     if (parser.seen("RL")) recovery.load();
     if (parser.seen_test('W')) recovery.save(true);
     if (parser.seen_test('P')) recovery.purge();
-    if (parser.seen_test('D')) recovery.debug(PSTR("M413"));
+    if (parser.seen_test('D')) recovery.debug(F("M413"));
     #if PIN_EXISTS(POWER_LOSS)
       if (parser.seen_test('O')) recovery._outage();
     #endif
diff --git a/Marlin/src/gcode/feature/trinamic/M569.cpp b/Marlin/src/gcode/feature/trinamic/M569.cpp
index 36a2c50ab28..2803c445927 100644
--- a/Marlin/src/gcode/feature/trinamic/M569.cpp
+++ b/Marlin/src/gcode/feature/trinamic/M569.cpp
@@ -141,12 +141,12 @@ void GcodeSuite::M569() {
 void GcodeSuite::M569_report(const bool forReplay/*=true*/) {
   report_heading(forReplay, F(STR_DRIVER_STEPPING_MODE));
 
-  auto say_M569 = [](const bool forReplay, const char * const etc=nullptr, const bool eol=false) {
+  auto say_M569 = [](const bool forReplay, FSTR_P const etc=nullptr, const bool eol=false) {
     if (!forReplay) SERIAL_ECHO_START();
     SERIAL_ECHOPGM("  M569 S1");
     if (etc) {
       SERIAL_CHAR(' ');
-      SERIAL_ECHOPGM_P(etc);
+      SERIAL_ECHOF(etc);
     }
     if (eol) SERIAL_EOL();
   };
@@ -176,28 +176,28 @@ void GcodeSuite::M569_report(const bool forReplay/*=true*/) {
              chop_z2 = TERN0(Z2_HAS_STEALTHCHOP, stepperZ2.get_stored_stealthChop());
 
   if (chop_x2 || chop_y2 || chop_z2) {
-    say_M569(forReplay, PSTR("I1"));
+    say_M569(forReplay, F("I1"));
     if (chop_x2) SERIAL_ECHOPGM_P(SP_X_STR);
     if (chop_y2) SERIAL_ECHOPGM_P(SP_Y_STR);
     if (chop_z2) SERIAL_ECHOPGM_P(SP_Z_STR);
     SERIAL_EOL();
   }
 
-  if (TERN0(Z3_HAS_STEALTHCHOP, stepperZ3.get_stored_stealthChop())) { say_M569(forReplay, PSTR("I2 Z"), true); }
-  if (TERN0(Z4_HAS_STEALTHCHOP, stepperZ4.get_stored_stealthChop())) { say_M569(forReplay, PSTR("I3 Z"), true); }
+  if (TERN0(Z3_HAS_STEALTHCHOP, stepperZ3.get_stored_stealthChop())) { say_M569(forReplay, F("I2 Z"), true); }
+  if (TERN0(Z4_HAS_STEALTHCHOP, stepperZ4.get_stored_stealthChop())) { say_M569(forReplay, F("I3 Z"), true); }
 
-  if (TERN0( I_HAS_STEALTHCHOP, stepperI.get_stored_stealthChop()))  { say_M569(forReplay, SP_I_STR, true); }
-  if (TERN0( J_HAS_STEALTHCHOP, stepperJ.get_stored_stealthChop()))  { say_M569(forReplay, SP_J_STR, true); }
-  if (TERN0( K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop()))  { say_M569(forReplay, SP_K_STR, true); }
+  if (TERN0( I_HAS_STEALTHCHOP, stepperI.get_stored_stealthChop()))  { say_M569(forReplay, FPSTR(SP_I_STR), true); }
+  if (TERN0( J_HAS_STEALTHCHOP, stepperJ.get_stored_stealthChop()))  { say_M569(forReplay, FPSTR(SP_J_STR), true); }
+  if (TERN0( K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop()))  { say_M569(forReplay, FPSTR(SP_K_STR), true); }
 
-  if (TERN0(E0_HAS_STEALTHCHOP, stepperE0.get_stored_stealthChop())) { say_M569(forReplay, PSTR("T0 E"), true); }
-  if (TERN0(E1_HAS_STEALTHCHOP, stepperE1.get_stored_stealthChop())) { say_M569(forReplay, PSTR("T1 E"), true); }
-  if (TERN0(E2_HAS_STEALTHCHOP, stepperE2.get_stored_stealthChop())) { say_M569(forReplay, PSTR("T2 E"), true); }
-  if (TERN0(E3_HAS_STEALTHCHOP, stepperE3.get_stored_stealthChop())) { say_M569(forReplay, PSTR("T3 E"), true); }
-  if (TERN0(E4_HAS_STEALTHCHOP, stepperE4.get_stored_stealthChop())) { say_M569(forReplay, PSTR("T4 E"), true); }
-  if (TERN0(E5_HAS_STEALTHCHOP, stepperE5.get_stored_stealthChop())) { say_M569(forReplay, PSTR("T5 E"), true); }
-  if (TERN0(E6_HAS_STEALTHCHOP, stepperE6.get_stored_stealthChop())) { say_M569(forReplay, PSTR("T6 E"), true); }
-  if (TERN0(E7_HAS_STEALTHCHOP, stepperE7.get_stored_stealthChop())) { say_M569(forReplay, PSTR("T7 E"), true); }
+  if (TERN0(E0_HAS_STEALTHCHOP, stepperE0.get_stored_stealthChop())) { say_M569(forReplay, F("T0 E"), true); }
+  if (TERN0(E1_HAS_STEALTHCHOP, stepperE1.get_stored_stealthChop())) { say_M569(forReplay, F("T1 E"), true); }
+  if (TERN0(E2_HAS_STEALTHCHOP, stepperE2.get_stored_stealthChop())) { say_M569(forReplay, F("T2 E"), true); }
+  if (TERN0(E3_HAS_STEALTHCHOP, stepperE3.get_stored_stealthChop())) { say_M569(forReplay, F("T3 E"), true); }
+  if (TERN0(E4_HAS_STEALTHCHOP, stepperE4.get_stored_stealthChop())) { say_M569(forReplay, F("T4 E"), true); }
+  if (TERN0(E5_HAS_STEALTHCHOP, stepperE5.get_stored_stealthChop())) { say_M569(forReplay, F("T5 E"), true); }
+  if (TERN0(E6_HAS_STEALTHCHOP, stepperE6.get_stored_stealthChop())) { say_M569(forReplay, F("T6 E"), true); }
+  if (TERN0(E7_HAS_STEALTHCHOP, stepperE7.get_stored_stealthChop())) { say_M569(forReplay, F("T7 E"), true); }
 }
 
 #endif // HAS_STEALTHCHOP
diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index 5f84ca3c38b..126f7452b87 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -1067,7 +1067,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
 }
 
 #if ENABLED(M100_FREE_MEMORY_DUMPER)
-  void M100_dump_routine(PGM_P const title, const char * const start, const uintptr_t size);
+  void M100_dump_routine(FSTR_P const title, const char * const start, const uintptr_t size);
 #endif
 
 /**
@@ -1086,7 +1086,7 @@ void GcodeSuite::process_next_command() {
     SERIAL_ECHOLN(command.buffer);
     #if ENABLED(M100_FREE_MEMORY_DUMPER)
       SERIAL_ECHOPGM("slot:", queue.ring_buffer.index_r);
-      M100_dump_routine(PSTR("   Command Queue:"), (const char*)&queue.ring_buffer, sizeof(queue.ring_buffer));
+      M100_dump_routine(F("   Command Queue:"), (const char*)&queue.ring_buffer, sizeof(queue.ring_buffer));
     #endif
   }
 
diff --git a/Marlin/src/gcode/host/M115.cpp b/Marlin/src/gcode/host/M115.cpp
index 1c106977bf0..8a9c409764c 100644
--- a/Marlin/src/gcode/host/M115.cpp
+++ b/Marlin/src/gcode/host/M115.cpp
@@ -34,9 +34,9 @@
 #endif
 
 #if ENABLED(EXTENDED_CAPABILITIES_REPORT)
-  static void cap_line(PGM_P const name, bool ena=false) {
+  static void cap_line(FSTR_P const name, bool ena=false) {
     SERIAL_ECHOPGM("Cap:");
-    SERIAL_ECHOPGM_P(name);
+    SERIAL_ECHOF(name);
     SERIAL_CHAR(':', '0' + ena);
     SERIAL_EOL();
   }
@@ -68,101 +68,101 @@ void GcodeSuite::M115() {
     serial_index_t port = queue.ring_buffer.command_port();
 
     // PAREN_COMMENTS
-    TERN_(PAREN_COMMENTS, cap_line(PSTR("PAREN_COMMENTS"), true));
+    TERN_(PAREN_COMMENTS, cap_line(F("PAREN_COMMENTS"), true));
 
     // QUOTED_STRINGS
-    TERN_(GCODE_QUOTED_STRINGS, cap_line(PSTR("QUOTED_STRINGS"), true));
+    TERN_(GCODE_QUOTED_STRINGS, cap_line(F("QUOTED_STRINGS"), true));
 
     // SERIAL_XON_XOFF
-    cap_line(PSTR("SERIAL_XON_XOFF"), ENABLED(SERIAL_XON_XOFF));
+    cap_line(F("SERIAL_XON_XOFF"), ENABLED(SERIAL_XON_XOFF));
 
     // BINARY_FILE_TRANSFER (M28 B1)
-    cap_line(PSTR("BINARY_FILE_TRANSFER"), ENABLED(BINARY_FILE_TRANSFER)); // TODO: Use SERIAL_IMPL.has_feature(port, SerialFeature::BinaryFileTransfer) once implemented
+    cap_line(F("BINARY_FILE_TRANSFER"), ENABLED(BINARY_FILE_TRANSFER)); // TODO: Use SERIAL_IMPL.has_feature(port, SerialFeature::BinaryFileTransfer) once implemented
 
     // EEPROM (M500, M501)
-    cap_line(PSTR("EEPROM"), ENABLED(EEPROM_SETTINGS));
+    cap_line(F("EEPROM"), ENABLED(EEPROM_SETTINGS));
 
     // Volumetric Extrusion (M200)
-    cap_line(PSTR("VOLUMETRIC"), DISABLED(NO_VOLUMETRICS));
+    cap_line(F("VOLUMETRIC"), DISABLED(NO_VOLUMETRICS));
 
     // AUTOREPORT_POS (M154)
-    cap_line(PSTR("AUTOREPORT_POS"), ENABLED(AUTO_REPORT_POSITION));
+    cap_line(F("AUTOREPORT_POS"), ENABLED(AUTO_REPORT_POSITION));
 
     // AUTOREPORT_TEMP (M155)
-    cap_line(PSTR("AUTOREPORT_TEMP"), ENABLED(AUTO_REPORT_TEMPERATURES));
+    cap_line(F("AUTOREPORT_TEMP"), ENABLED(AUTO_REPORT_TEMPERATURES));
 
     // PROGRESS (M530 S L, M531 <file>, M532 X L)
-    cap_line(PSTR("PROGRESS"));
+    cap_line(F("PROGRESS"));
 
     // Print Job timer M75, M76, M77
-    cap_line(PSTR("PRINT_JOB"), true);
+    cap_line(F("PRINT_JOB"), true);
 
     // AUTOLEVEL (G29)
-    cap_line(PSTR("AUTOLEVEL"), ENABLED(HAS_AUTOLEVEL));
+    cap_line(F("AUTOLEVEL"), ENABLED(HAS_AUTOLEVEL));
 
     // RUNOUT (M412, M600)
-    cap_line(PSTR("RUNOUT"), ENABLED(FILAMENT_RUNOUT_SENSOR));
+    cap_line(F("RUNOUT"), ENABLED(FILAMENT_RUNOUT_SENSOR));
 
     // Z_PROBE (G30)
-    cap_line(PSTR("Z_PROBE"), ENABLED(HAS_BED_PROBE));
+    cap_line(F("Z_PROBE"), ENABLED(HAS_BED_PROBE));
 
     // MESH_REPORT (M420 V)
-    cap_line(PSTR("LEVELING_DATA"), ENABLED(HAS_LEVELING));
+    cap_line(F("LEVELING_DATA"), ENABLED(HAS_LEVELING));
 
     // BUILD_PERCENT (M73)
-    cap_line(PSTR("BUILD_PERCENT"), ENABLED(LCD_SET_PROGRESS_MANUALLY));
+    cap_line(F("BUILD_PERCENT"), ENABLED(LCD_SET_PROGRESS_MANUALLY));
 
     // SOFTWARE_POWER (M80, M81)
-    cap_line(PSTR("SOFTWARE_POWER"), ENABLED(PSU_CONTROL));
+    cap_line(F("SOFTWARE_POWER"), ENABLED(PSU_CONTROL));
 
     // TOGGLE_LIGHTS (M355)
-    cap_line(PSTR("TOGGLE_LIGHTS"), ENABLED(CASE_LIGHT_ENABLE));
-    cap_line(PSTR("CASE_LIGHT_BRIGHTNESS"), TERN0(CASE_LIGHT_ENABLE, caselight.has_brightness()));
+    cap_line(F("TOGGLE_LIGHTS"), ENABLED(CASE_LIGHT_ENABLE));
+    cap_line(F("CASE_LIGHT_BRIGHTNESS"), TERN0(CASE_LIGHT_ENABLE, caselight.has_brightness()));
 
     // EMERGENCY_PARSER (M108, M112, M410, M876)
-    cap_line(PSTR("EMERGENCY_PARSER"), ENABLED(EMERGENCY_PARSER));
+    cap_line(F("EMERGENCY_PARSER"), ENABLED(EMERGENCY_PARSER));
 
     // HOST ACTION COMMANDS (paused, resume, resumed, cancel, etc.)
-    cap_line(PSTR("HOST_ACTION_COMMANDS"), ENABLED(HOST_ACTION_COMMANDS));
+    cap_line(F("HOST_ACTION_COMMANDS"), ENABLED(HOST_ACTION_COMMANDS));
 
     // PROMPT SUPPORT (M876)
-    cap_line(PSTR("PROMPT_SUPPORT"), ENABLED(HOST_PROMPT_SUPPORT));
+    cap_line(F("PROMPT_SUPPORT"), ENABLED(HOST_PROMPT_SUPPORT));
 
     // SDCARD (M20, M23, M24, etc.)
-    cap_line(PSTR("SDCARD"), ENABLED(SDSUPPORT));
+    cap_line(F("SDCARD"), ENABLED(SDSUPPORT));
 
     // REPEAT (M808)
-    cap_line(PSTR("REPEAT"), ENABLED(GCODE_REPEAT_MARKERS));
+    cap_line(F("REPEAT"), ENABLED(GCODE_REPEAT_MARKERS));
 
     // SD_WRITE (M928, M28, M29)
-    cap_line(PSTR("SD_WRITE"), ENABLED(SDSUPPORT) && DISABLED(SDCARD_READONLY));
+    cap_line(F("SD_WRITE"), ENABLED(SDSUPPORT) && DISABLED(SDCARD_READONLY));
 
     // AUTOREPORT_SD_STATUS (M27 extension)
-    cap_line(PSTR("AUTOREPORT_SD_STATUS"), ENABLED(AUTO_REPORT_SD_STATUS));
+    cap_line(F("AUTOREPORT_SD_STATUS"), ENABLED(AUTO_REPORT_SD_STATUS));
 
     // LONG_FILENAME_HOST_SUPPORT (M33)
-    cap_line(PSTR("LONG_FILENAME"), ENABLED(LONG_FILENAME_HOST_SUPPORT));
+    cap_line(F("LONG_FILENAME"), ENABLED(LONG_FILENAME_HOST_SUPPORT));
 
     // THERMAL_PROTECTION
-    cap_line(PSTR("THERMAL_PROTECTION"), ENABLED(THERMALLY_SAFE));
+    cap_line(F("THERMAL_PROTECTION"), ENABLED(THERMALLY_SAFE));
 
     // MOTION_MODES (M80-M89)
-    cap_line(PSTR("MOTION_MODES"), ENABLED(GCODE_MOTION_MODES));
+    cap_line(F("MOTION_MODES"), ENABLED(GCODE_MOTION_MODES));
 
     // ARC_SUPPORT (G2-G3)
-    cap_line(PSTR("ARCS"), ENABLED(ARC_SUPPORT));
+    cap_line(F("ARCS"), ENABLED(ARC_SUPPORT));
 
     // BABYSTEPPING (M290)
-    cap_line(PSTR("BABYSTEPPING"), ENABLED(BABYSTEPPING));
+    cap_line(F("BABYSTEPPING"), ENABLED(BABYSTEPPING));
 
     // CHAMBER_TEMPERATURE (M141, M191)
-    cap_line(PSTR("CHAMBER_TEMPERATURE"), ENABLED(HAS_HEATED_CHAMBER));
+    cap_line(F("CHAMBER_TEMPERATURE"), ENABLED(HAS_HEATED_CHAMBER));
 
     // COOLER_TEMPERATURE (M143, M193)
-    cap_line(PSTR("COOLER_TEMPERATURE"), ENABLED(HAS_COOLER));
+    cap_line(F("COOLER_TEMPERATURE"), ENABLED(HAS_COOLER));
 
     // MEATPACK Compression
-    cap_line(PSTR("MEATPACK"), SERIAL_IMPL.has_feature(port, SerialFeature::MeatPack));
+    cap_line(F("MEATPACK"), SERIAL_IMPL.has_feature(port, SerialFeature::MeatPack));
 
     // Machine Geometry
     #if ENABLED(M115_GEOMETRY_REPORT)
diff --git a/Marlin/src/gcode/host/M360.cpp b/Marlin/src/gcode/host/M360.cpp
index 1830dea3bfd..29b7ae602b3 100644
--- a/Marlin/src/gcode/host/M360.cpp
+++ b/Marlin/src/gcode/host/M360.cpp
@@ -43,9 +43,15 @@ static void config_line(PGM_P const name, const float val, PGM_P const pref=null
   config_prefix(name, pref, ind);
   SERIAL_ECHOLN(val);
 }
+static void config_line(FSTR_P const name, const float val, FSTR_P const pref=nullptr, const int8_t ind=-1) {
+  config_line(FTOP(name), val, FTOP(pref) , ind);
+}
 static void config_line_e(const int8_t e, PGM_P const name, const float val) {
   config_line(name, val, PSTR("Extr."), e + 1);
 }
+static void config_line_e(const int8_t e, FSTR_P const name, const float val) {
+  config_line_e(e, FTOP(name), val);
+}
 
 /**
  * M360: Report Firmware configuration
@@ -60,19 +66,19 @@ void GcodeSuite::M360() {
   //
   // Basics and Enabled items
   //
-  config_line(PSTR("Baudrate"),                   BAUDRATE);
-  config_line(PSTR("InputBuffer"),                MAX_CMD_SIZE);
-  config_line(PSTR("PrintlineCache"),             BUFSIZE);
-  config_line(PSTR("MixingExtruder"),             ENABLED(MIXING_EXTRUDER));
-  config_line(PSTR("SDCard"),                     ENABLED(SDSUPPORT));
-  config_line(PSTR("Fan"),                        ENABLED(HAS_FAN));
-  config_line(PSTR("LCD"),                        ENABLED(HAS_DISPLAY));
-  config_line(PSTR("SoftwarePowerSwitch"), 1);
-  config_line(PSTR("SupportLocalFilamentchange"), ENABLED(ADVANCED_PAUSE_FEATURE));
-  config_line(PSTR("CaseLights"),                 ENABLED(CASE_LIGHT_ENABLE));
-  config_line(PSTR("ZProbe"),                     ENABLED(HAS_BED_PROBE));
-  config_line(PSTR("Autolevel"),                  ENABLED(HAS_LEVELING));
-  config_line(PSTR("EEPROM"),                     ENABLED(EEPROM_SETTINGS));
+  config_line(F("Baudrate"),                    BAUDRATE);
+  config_line(F("InputBuffer"),                 MAX_CMD_SIZE);
+  config_line(F("PrintlineCache"),              BUFSIZE);
+  config_line(F("MixingExtruder"),              ENABLED(MIXING_EXTRUDER));
+  config_line(F("SDCard"),                      ENABLED(SDSUPPORT));
+  config_line(F("Fan"),                         ENABLED(HAS_FAN));
+  config_line(F("LCD"),                         ENABLED(HAS_DISPLAY));
+  config_line(F("SoftwarePowerSwitch"),         1);
+  config_line(F("SupportLocalFilamentchange"),  ENABLED(ADVANCED_PAUSE_FEATURE));
+  config_line(F("CaseLights"),                  ENABLED(CASE_LIGHT_ENABLE));
+  config_line(F("ZProbe"),                      ENABLED(HAS_BED_PROBE));
+  config_line(F("Autolevel"),                   ENABLED(HAS_LEVELING));
+  config_line(F("EEPROM"),                      ENABLED(EEPROM_SETTINGS));
 
   //
   // Homing Directions
@@ -87,7 +93,7 @@ void GcodeSuite::M360() {
   //
   #if HAS_CLASSIC_JERK
     if (planner.max_jerk.x == planner.max_jerk.y)
-      config_line(PSTR("XY"), planner.max_jerk.x, JERK_STR);
+      config_line(F("XY"), planner.max_jerk.x, JERK_STR);
     else {
       config_line(X_STR, planner.max_jerk.x, JERK_STR);
       config_line(Y_STR, planner.max_jerk.y, JERK_STR);
@@ -98,21 +104,21 @@ void GcodeSuite::M360() {
   //
   // Firmware Retraction
   //
-  config_line(PSTR("SupportG10G11"), ENABLED(FWRETRACT));
+  config_line(F("SupportG10G11"), ENABLED(FWRETRACT));
   #if ENABLED(FWRETRACT)
     PGMSTR(RET_STR, "Retraction");
     PGMSTR(UNRET_STR, "RetractionUndo");
     PGMSTR(SPEED_STR, "Speed");
     // M10 Retract with swap (long) moves
-    config_line(PSTR("Length"),     fwretract.settings.retract_length, RET_STR);
+    config_line(F("Length"),     fwretract.settings.retract_length, RET_STR);
     config_line(SPEED_STR,          fwretract.settings.retract_feedrate_mm_s, RET_STR);
-    config_line(PSTR("ZLift"),      fwretract.settings.retract_zraise, RET_STR);
-    config_line(PSTR("LongLength"), fwretract.settings.swap_retract_length, RET_STR);
+    config_line(F("ZLift"),      fwretract.settings.retract_zraise, RET_STR);
+    config_line(F("LongLength"), fwretract.settings.swap_retract_length, RET_STR);
     // M11 Recover (undo) with swap (long) moves
     config_line(SPEED_STR,               fwretract.settings.retract_recover_feedrate_mm_s, UNRET_STR);
-    config_line(PSTR("ExtraLength"),     fwretract.settings.retract_recover_extra, UNRET_STR);
-    config_line(PSTR("ExtraLongLength"), fwretract.settings.swap_retract_recover_extra, UNRET_STR);
-    config_line(PSTR("LongSpeed"),       fwretract.settings.swap_retract_recover_feedrate_mm_s, UNRET_STR);
+    config_line(F("ExtraLength"),     fwretract.settings.retract_recover_extra, UNRET_STR);
+    config_line(F("ExtraLongLength"), fwretract.settings.swap_retract_recover_extra, UNRET_STR);
+    config_line(F("LongSpeed"),       fwretract.settings.swap_retract_recover_feedrate_mm_s, UNRET_STR);
   #endif
 
   //
@@ -163,22 +169,22 @@ void GcodeSuite::M360() {
   //
   // Heated Bed
   //
-  config_line(PSTR("HeatedBed"), ENABLED(HAS_HEATED_BED));
+  config_line(F("HeatedBed"), ENABLED(HAS_HEATED_BED));
   #if HAS_HEATED_BED
-    config_line(PSTR("MaxBedTemp"), BED_MAX_TARGET);
+    config_line(F("MaxBedTemp"), BED_MAX_TARGET);
   #endif
 
   //
   // Per-Extruder settings
   //
-  config_line(PSTR("NumExtruder"), EXTRUDERS);
+  config_line(F("NumExtruder"), EXTRUDERS);
   #if HAS_EXTRUDERS
     LOOP_L_N(e, EXTRUDERS) {
       config_line_e(e, JERK_STR, TERN(HAS_LINEAR_E_JERK, planner.max_e_jerk[E_INDEX_N(e)], TERN(HAS_CLASSIC_JERK, planner.max_jerk.e, DEFAULT_EJERK)));
-      config_line_e(e, PSTR("MaxSpeed"), planner.settings.max_feedrate_mm_s[E_AXIS_N(e)]);
-      config_line_e(e, PSTR("Acceleration"), planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(e)]);
-      config_line_e(e, PSTR("Diameter"), TERN(NO_VOLUMETRICS, DEFAULT_NOMINAL_FILAMENT_DIA, planner.filament_size[e]));
-      config_line_e(e, PSTR("MaxTemp"), thermalManager.hotend_maxtemp[e]);
+      config_line_e(e, F("MaxSpeed"), planner.settings.max_feedrate_mm_s[E_AXIS_N(e)]);
+      config_line_e(e, F("Acceleration"), planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(e)]);
+      config_line_e(e, F("Diameter"), TERN(NO_VOLUMETRICS, DEFAULT_NOMINAL_FILAMENT_DIA, planner.filament_size[e]));
+      config_line_e(e, F("MaxTemp"), thermalManager.hotend_maxtemp[e]);
     }
   #endif
 }
diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp
index 54248096993..9c3175da580 100644
--- a/Marlin/src/gcode/queue.cpp
+++ b/Marlin/src/gcode/queue.cpp
@@ -302,10 +302,10 @@ static bool serial_data_available(serial_index_t index) {
 
 inline int read_serial(const serial_index_t index) { return SERIAL_IMPL.read(index); }
 
-void GCodeQueue::gcode_line_error(PGM_P const err, const serial_index_t serial_ind) {
+void GCodeQueue::gcode_line_error(FSTR_P const ferr, const serial_index_t serial_ind) {
   PORT_REDIRECT(SERIAL_PORTMASK(serial_ind)); // Reply to the serial port that sent the command
   SERIAL_ERROR_START();
-  SERIAL_ECHOLNPGM_P(err, serial_state[serial_ind.index].last_N);
+  SERIAL_ECHOLNF(ferr, serial_state[serial_ind.index].last_N);
   while (read_serial(serial_ind) != -1) { /* nada */ } // Clear out the RX buffer. Why don't use flush here ?
   flush_and_request_resend(serial_ind);
   serial_state[serial_ind.index].count = 0;
@@ -470,7 +470,7 @@ void GCodeQueue::get_serial_commands() {
 
           if (gcode_N != serial.last_N + 1 && !M110) {
             // In case of error on a serial port, don't prevent other serial port from making progress
-            gcode_line_error(PSTR(STR_ERR_LINE_NO), p);
+            gcode_line_error(F(STR_ERR_LINE_NO), p);
             break;
           }
 
@@ -480,13 +480,13 @@ void GCodeQueue::get_serial_commands() {
             while (count) checksum ^= command[--count];
             if (strtol(apos + 1, nullptr, 10) != checksum) {
               // In case of error on a serial port, don't prevent other serial port from making progress
-              gcode_line_error(PSTR(STR_ERR_CHECKSUM_MISMATCH), p);
+              gcode_line_error(F(STR_ERR_CHECKSUM_MISMATCH), p);
               break;
             }
           }
           else {
             // In case of error on a serial port, don't prevent other serial port from making progress
-            gcode_line_error(PSTR(STR_ERR_NO_CHECKSUM), p);
+            gcode_line_error(F(STR_ERR_NO_CHECKSUM), p);
             break;
           }
 
@@ -495,7 +495,7 @@ void GCodeQueue::get_serial_commands() {
         #if ENABLED(SDSUPPORT)
           // Pronterface "M29" and "M29 " has no line number
           else if (card.flag.saving && !is_M29(command)) {
-            gcode_line_error(PSTR(STR_ERR_NO_CHECKSUM), p);
+            gcode_line_error(F(STR_ERR_NO_CHECKSUM), p);
             break;
           }
         #endif
diff --git a/Marlin/src/gcode/queue.h b/Marlin/src/gcode/queue.h
index 71a710b8cbe..c5562da3aa0 100644
--- a/Marlin/src/gcode/queue.h
+++ b/Marlin/src/gcode/queue.h
@@ -259,7 +259,7 @@ private:
    */
   static bool enqueue_one(const char *cmd);
 
-  static void gcode_line_error(PGM_P const err, const serial_index_t serial_ind);
+  static void gcode_line_error(FSTR_P const ferr, const serial_index_t serial_ind);
 
   friend class GcodeSuite;
 };
diff --git a/Marlin/src/libs/stopwatch.cpp b/Marlin/src/libs/stopwatch.cpp
index adfaa3b043e..4178807951d 100644
--- a/Marlin/src/libs/stopwatch.cpp
+++ b/Marlin/src/libs/stopwatch.cpp
@@ -34,7 +34,7 @@ millis_t Stopwatch::startTimestamp;
 millis_t Stopwatch::stopTimestamp;
 
 bool Stopwatch::stop() {
-  Stopwatch::debug(PSTR("stop"));
+  debug(F("stop"));
 
   if (isRunning() || isPaused()) {
     TERN_(EXTENSIBLE_UI, ExtUI::onPrintTimerStopped());
@@ -46,7 +46,7 @@ bool Stopwatch::stop() {
 }
 
 bool Stopwatch::pause() {
-  Stopwatch::debug(PSTR("pause"));
+  debug(F("pause"));
 
   if (isRunning()) {
     TERN_(EXTENSIBLE_UI, ExtUI::onPrintTimerPaused());
@@ -58,7 +58,7 @@ bool Stopwatch::pause() {
 }
 
 bool Stopwatch::start() {
-  Stopwatch::debug(PSTR("start"));
+  debug(F("start"));
 
   TERN_(EXTENSIBLE_UI, ExtUI::onPrintTimerStarted());
 
@@ -74,14 +74,14 @@ bool Stopwatch::start() {
 }
 
 void Stopwatch::resume(const millis_t with_time) {
-  Stopwatch::debug(PSTR("resume"));
+  debug(F("resume"));
 
   reset();
   if ((accumulator = with_time)) state = RUNNING;
 }
 
 void Stopwatch::reset() {
-  Stopwatch::debug(PSTR("reset"));
+  debug(F("reset"));
 
   state = STOPPED;
   startTimestamp = 0;
@@ -95,12 +95,8 @@ millis_t Stopwatch::duration() {
 
 #if ENABLED(DEBUG_STOPWATCH)
 
-  void Stopwatch::debug(const char func[]) {
-    if (DEBUGGING(INFO)) {
-      SERIAL_ECHOPGM("Stopwatch::");
-      SERIAL_ECHOPGM_P(func);
-      SERIAL_ECHOLNPGM("()");
-    }
+  void Stopwatch::debug(FSTR_P const func) {
+    if (DEBUGGING(INFO)) SERIAL_ECHOLNPGM("Stopwatch::", func, "()");
   }
 
 #endif
diff --git a/Marlin/src/libs/stopwatch.h b/Marlin/src/libs/stopwatch.h
index b64a36a90e7..fe5101a5bea 100644
--- a/Marlin/src/libs/stopwatch.h
+++ b/Marlin/src/libs/stopwatch.h
@@ -21,14 +21,11 @@
  */
 #pragma once
 
+#include "../inc/MarlinConfig.h"
+
 // Print debug messages with M111 S2 (Uses 156 bytes of PROGMEM)
 //#define DEBUG_STOPWATCH
 
-#include "../core/macros.h" // for FORCE_INLINE
-
-#include <stdint.h>
-typedef uint32_t millis_t;
-
 /**
  * @brief Stopwatch class
  * @details This class acts as a timer proving stopwatch functionality including
@@ -113,11 +110,11 @@ class Stopwatch {
        * @brief Print a debug message
        * @details Print a simple debug message "Stopwatch::function"
        */
-      static void debug(const char func[]);
+      static void debug(FSTR_P const);
 
     #else
 
-      static inline void debug(const char[]) {}
+      static inline void debug(FSTR_P const) {}
 
     #endif
 };
diff --git a/Marlin/src/libs/vector_3.cpp b/Marlin/src/libs/vector_3.cpp
index 4db8fb5f2e1..614d2121b89 100644
--- a/Marlin/src/libs/vector_3.cpp
+++ b/Marlin/src/libs/vector_3.cpp
@@ -75,8 +75,8 @@ void vector_3::apply_rotation(const matrix_3x3 &matrix) {
             matrix.vectors[0].z * _x + matrix.vectors[1].z * _y + matrix.vectors[2].z * _z };
 }
 
-void vector_3::debug(PGM_P const title) {
-  SERIAL_ECHOPGM_P(title);
+void vector_3::debug(FSTR_P const title) {
+  SERIAL_ECHOF(title);
   SERIAL_ECHOPAIR_F_P(SP_X_STR, x, 6);
   SERIAL_ECHOPAIR_F_P(SP_Y_STR, y, 6);
   SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, z, 6);
@@ -100,14 +100,14 @@ void matrix_3x3::set_to_identity() {
 
 // Create a matrix from 3 vector_3 inputs
 matrix_3x3 matrix_3x3::create_from_rows(const vector_3 &row_0, const vector_3 &row_1, const vector_3 &row_2) {
-  //row_0.debug(PSTR("row_0"));
-  //row_1.debug(PSTR("row_1"));
-  //row_2.debug(PSTR("row_2"));
+  //row_0.debug(F("row_0"));
+  //row_1.debug(F("row_1"));
+  //row_2.debug(F("row_2"));
   matrix_3x3 new_matrix;
   new_matrix.vectors[0] = row_0;
   new_matrix.vectors[1] = row_1;
   new_matrix.vectors[2] = row_2;
-  //new_matrix.debug(PSTR("new_matrix"));
+  //new_matrix.debug(F("new_matrix"));
   return new_matrix;
 }
 
@@ -117,14 +117,14 @@ matrix_3x3 matrix_3x3::create_look_at(const vector_3 &target) {
                  x_row = vector_3(1, 0, -target.x / target.z).get_normal(),
                  y_row = vector_3::cross(z_row, x_row).get_normal();
 
-  // x_row.debug(PSTR("x_row"));
-  // y_row.debug(PSTR("y_row"));
-  // z_row.debug(PSTR("z_row"));
+  // x_row.debug(F("x_row"));
+  // y_row.debug(F("y_row"));
+  // z_row.debug(F("z_row"));
 
   // create the matrix already correctly transposed
   matrix_3x3 rot = matrix_3x3::create_from_rows(x_row, y_row, z_row);
 
-  // rot.debug(PSTR("rot"));
+  // rot.debug(F("rot"));
   return rot;
 }
 
@@ -137,8 +137,8 @@ matrix_3x3 matrix_3x3::transpose(const matrix_3x3 &original) {
   return new_matrix;
 }
 
-void matrix_3x3::debug(PGM_P const title) {
-  if (title) SERIAL_ECHOLNPGM_P(title);
+void matrix_3x3::debug(FSTR_P const title) {
+  if (title) SERIAL_ECHOLNF(title);
   LOOP_L_N(i, 3) {
     LOOP_L_N(j, 3) {
       if (vectors[i][j] >= 0.0) SERIAL_CHAR('+');
diff --git a/Marlin/src/libs/vector_3.h b/Marlin/src/libs/vector_3.h
index 5d99fcec20d..f515333cc76 100644
--- a/Marlin/src/libs/vector_3.h
+++ b/Marlin/src/libs/vector_3.h
@@ -78,7 +78,7 @@ struct vector_3 {
   operator xy_float_t() { return xy_float_t({ x, y }); }
   operator xyz_float_t() { return xyz_float_t({ x, y, z }); }
 
-  void debug(PGM_P const title);
+  void debug(FSTR_P const title);
 };
 
 struct matrix_3x3 {
@@ -91,7 +91,7 @@ struct matrix_3x3 {
 
   void set_to_identity();
 
-  void debug(PGM_P const title);
+  void debug(FSTR_P const title);
 
   void apply_rotation_xyz(float &x, float &y, float &z);
 };
diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp
index b5f270ee634..80e20a07785 100644
--- a/Marlin/src/module/endstops.cpp
+++ b/Marlin/src/module/endstops.cpp
@@ -483,10 +483,10 @@ void Endstops::event_handler() {
   #pragma GCC diagnostic ignored "-Wunused-function"
 #endif
 
-static void print_es_state(const bool is_hit, PGM_P const label=nullptr) {
-  if (label) SERIAL_ECHOPGM_P(label);
+static void print_es_state(const bool is_hit, FSTR_P const flabel=nullptr) {
+  if (flabel) SERIAL_ECHOF(flabel);
   SERIAL_ECHOPGM(": ");
-  SERIAL_ECHOLNPGM_P(is_hit ? PSTR(STR_ENDSTOP_HIT) : PSTR(STR_ENDSTOP_OPEN));
+  SERIAL_ECHOLNF(is_hit ? F(STR_ENDSTOP_HIT) : F(STR_ENDSTOP_OPEN));
 }
 
 #if GCC_VERSION <= 50000
@@ -496,7 +496,7 @@ static void print_es_state(const bool is_hit, PGM_P const label=nullptr) {
 void _O2 Endstops::report_states() {
   TERN_(BLTOUCH, bltouch._set_SW_mode());
   SERIAL_ECHOLNPGM(STR_M119_REPORT);
-  #define ES_REPORT(S) print_es_state(READ(S##_PIN) != S##_ENDSTOP_INVERTING, PSTR(STR_##S))
+  #define ES_REPORT(S) print_es_state(READ(S##_PIN) != S##_ENDSTOP_INVERTING, F(STR_##S))
   #if HAS_X_MIN
     ES_REPORT(X_MIN);
   #endif
@@ -564,10 +564,10 @@ void _O2 Endstops::report_states() {
     ES_REPORT(K_MAX);
   #endif
   #if BOTH(MARLIN_DEV_MODE, PROBE_ACTIVATION_SWITCH)
-    print_es_state(probe_switch_activated(), PSTR(STR_PROBE_EN));
+    print_es_state(probe_switch_activated(), F(STR_PROBE_EN));
   #endif
   #if USES_Z_MIN_PROBE_PIN
-    print_es_state(PROBE_TRIGGERED(), PSTR(STR_Z_PROBE));
+    print_es_state(PROBE_TRIGGERED(), F(STR_Z_PROBE));
   #endif
   #if MULTI_FILAMENT_SENSOR
     #define _CASE_RUNOUT(N) case N: pin = FIL_RUNOUT##N##_PIN; state = FIL_RUNOUT##N##_STATE; break;
@@ -584,7 +584,7 @@ void _O2 Endstops::report_states() {
     }
     #undef _CASE_RUNOUT
   #elif HAS_FILAMENT_SENSOR
-    print_es_state(READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE, PSTR(STR_FILAMENT));
+    print_es_state(READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE, F(STR_FILAMENT));
   #endif
 
   TERN_(BLTOUCH, bltouch._reset_SW_mode());
diff --git a/Marlin/src/pins/pinsDebug.h b/Marlin/src/pins/pinsDebug.h
index b384342335b..e5db7f7b54b 100644
--- a/Marlin/src/pins/pinsDebug.h
+++ b/Marlin/src/pins/pinsDebug.h
@@ -178,7 +178,7 @@ static void print_input_or_output(const bool isout) {
 }
 
 // pretty report with PWM info
-inline void report_pin_state_extended(pin_t pin, const bool ignore, const bool extended=false, PGM_P const start_string=nullptr) {
+inline void report_pin_state_extended(pin_t pin, const bool ignore, const bool extended=false, FSTR_P const start_string=nullptr) {
   char buffer[MAX_NAME_LENGTH + 1];   // for the sprintf statements
   bool found = false, multi_name_pin = false;
 
@@ -202,7 +202,7 @@ inline void report_pin_state_extended(pin_t pin, const bool ignore, const bool e
   LOOP_L_N(x, COUNT(pin_array))  {    // scan entire array and report all instances of this pin
     if (GET_ARRAY_PIN(x) == pin) {
       if (!found) {    // report digital and analog pin number only on the first time through
-        if (start_string) SERIAL_ECHOPGM_P(start_string);
+        if (start_string) SERIAL_ECHOF(start_string);
         SERIAL_ECHOPGM("PIN: ");
         PRINT_PIN(pin);
         PRINT_PORT(pin);
@@ -211,7 +211,7 @@ inline void report_pin_state_extended(pin_t pin, const bool ignore, const bool e
       }
       else {
         SERIAL_CHAR('.');
-        SERIAL_ECHO_SP(MULTI_NAME_PAD + (start_string ? strlen_P(start_string) : 0));  // add padding if not the first instance found
+        SERIAL_ECHO_SP(MULTI_NAME_PAD + (start_string ? strlen_P(FTOP(start_string)) : 0));  // add padding if not the first instance found
       }
       PRINT_ARRAY_NAME(x);
       if (extended) {
@@ -250,7 +250,7 @@ inline void report_pin_state_extended(pin_t pin, const bool ignore, const bool e
   } // end of for loop
 
   if (!found) {
-    if (start_string) SERIAL_ECHOPGM_P(start_string);
+    if (start_string) SERIAL_ECHOF(start_string);
     SERIAL_ECHOPGM("PIN: ");
     PRINT_PIN(pin);
     PRINT_PORT(pin);