diff --git a/.travis.yml b/.travis.yml
index e29f7f6d71f..20a50751016 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -375,17 +375,17 @@ script:
   - use_example_configs Hephestos_2
   - build_marlin
   #
-  # Delta Config (generic)
+  # Delta Config (generic) + ABL bilinear + PROBE_MANUALLY
   - restore_configs
   - use_example_configs delta/generic
-  - opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER DELTA_CALIBRATION_MENU
+  - opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER DELTA_CALIBRATION_MENU AUTO_BED_LEVELING_BILINEAR PROBE_MANUALLY
   - build_marlin
   #
-  # Delta Config (generic) + ABL + ALLEN_KEY
+  # Delta Config (generic) + UBL + ALLEN_KEY + OLED_PANEL_TINYBOY2 + EEPROM_SETTINGS
   #
   - use_example_configs delta/generic
   - opt_disable DISABLE_MIN_ENDSTOPS
-  - opt_enable AUTO_BED_LEVELING_BILINEAR Z_PROBE_ALLEN_KEY
+  - opt_enable AUTO_BED_LEVELING_UBL Z_PROBE_ALLEN_KEY EEPROM_SETTINGS EEPROM_CHITCHAT OLED_PANEL_TINYBOY2
   - build_marlin
   #
   # Delta Config (FLSUN AC because it's complex)
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index cb7ec8696e2..f68ec7b098b 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -3943,7 +3943,7 @@ void home_all_axes() { gcode_G28(true); }
 #if ENABLED(MESH_BED_LEVELING)
 
   // Save 130 bytes with non-duplication of PSTR
-  void say_not_entered() { SERIAL_PROTOCOLLNPGM(" not entered."); }
+  void echo_not_entered() { SERIAL_PROTOCOLLNPGM(" not entered."); }
 
   void mbl_mesh_report() {
     SERIAL_PROTOCOLLNPGM("Num X,Y: " STRINGIFY(GRID_MAX_POINTS_X) "," STRINGIFY(GRID_MAX_POINTS_Y));
@@ -4074,7 +4074,7 @@ void home_all_axes() { gcode_G28(true); }
           }
         }
         else {
-          SERIAL_CHAR('X'); say_not_entered();
+          SERIAL_CHAR('X'); echo_not_entered();
           return;
         }
 
@@ -4086,7 +4086,7 @@ void home_all_axes() { gcode_G28(true); }
           }
         }
         else {
-          SERIAL_CHAR('Y'); say_not_entered();
+          SERIAL_CHAR('Y'); echo_not_entered();
           return;
         }
 
@@ -4094,7 +4094,7 @@ void home_all_axes() { gcode_G28(true); }
           mbl.z_values[px][py] = code_value_linear_units();
         }
         else {
-          SERIAL_CHAR('Z'); say_not_entered();
+          SERIAL_CHAR('Z'); echo_not_entered();
           return;
         }
         break;
@@ -4104,7 +4104,7 @@ void home_all_axes() { gcode_G28(true); }
           mbl.z_offset = code_value_linear_units();
         }
         else {
-          SERIAL_CHAR('Z'); say_not_entered();
+          SERIAL_CHAR('Z'); echo_not_entered();
           return;
         }
         break;
@@ -5123,7 +5123,7 @@ void home_all_axes() { gcode_G28(true); }
       SERIAL_PROTOCOLPGM("Checking... AC");
       if (verbose_level == 0) SERIAL_PROTOCOLPGM(" (DRY-RUN)");
       SERIAL_EOL;
-      LCD_MESSAGEPGM("Checking... AC");
+      LCD_MESSAGEPGM("Checking... AC"); // TODO: Make translatable string
 
       SERIAL_PROTOCOLPAIR(".Height:", DELTA_HEIGHT + home_offset[Z_AXIS]);
       if (!do_height_only) {
@@ -5343,7 +5343,7 @@ void home_all_axes() { gcode_G28(true); }
             SERIAL_PROTOCOL_SP(36);
             SERIAL_PROTOCOLPGM("rolling back.");
             SERIAL_EOL;
-            LCD_MESSAGEPGM("Calibration OK");
+            LCD_MESSAGEPGM("Calibration OK"); // TODO: Make translatable string
           }
           else {                                                     // !end iterations
             char mess[15] = "No convergence";
@@ -5394,7 +5394,7 @@ void home_all_axes() { gcode_G28(true); }
           }
           else {
             SERIAL_PROTOCOLLNPGM("Calibration OK");
-            LCD_MESSAGEPGM("Calibration OK");
+            LCD_MESSAGEPGM("Calibration OK"); // TODO: Make translatable string
             SERIAL_PROTOCOLPAIR(".Height:", DELTA_HEIGHT + home_offset[Z_AXIS]);
             SERIAL_EOL;
             serialprintPGM(save_message);
@@ -8460,15 +8460,22 @@ void quickstop_stepper() {
     #if ENABLED(AUTO_BED_LEVELING_UBL)
       // L to load a mesh from the EEPROM
       if (code_seen('L')) {
-        const int8_t storage_slot = code_has_value() ? code_value_int() : ubl.state.eeprom_storage_slot;
-        const int16_t j = (UBL_LAST_EEPROM_INDEX - ubl.eeprom_start) / sizeof(ubl.z_values);
-        if (!WITHIN(storage_slot, 0, j - 1) || ubl.eeprom_start <= 0) {
-          SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n");
+        const int8_t storage_slot = code_has_value() ? code_value_int() : ubl.state.storage_slot;
+        const int16_t a = settings.calc_num_meshes();
+
+        if (!a) {
+          SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
           return;
         }
 
-        ubl.load_mesh(storage_slot);
-        ubl.state.eeprom_storage_slot = storage_slot;
+        if (!WITHIN(storage_slot, 0, a - 1)) {
+          SERIAL_PROTOCOLLNPGM("?Invalid storage slot.");
+          SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
+          return;
+        }
+
+        settings.load_mesh(storage_slot);
+        ubl.state.storage_slot = storage_slot;
       }
     #endif // AUTO_BED_LEVELING_UBL
 
@@ -8496,7 +8503,7 @@ void quickstop_stepper() {
       if (code_seen('L') || code_seen('V')) {
         ubl.display_map(0);  // Currently only supports one map type
         SERIAL_ECHOLNPAIR("UBL_MESH_VALID = ", UBL_MESH_VALID);
-        SERIAL_ECHOLNPAIR("eeprom_storage_slot = ", ubl.state.eeprom_storage_slot);
+        SERIAL_ECHOLNPAIR("ubl.state.storage_slot = ", ubl.state.storage_slot);
       }
     #endif
 
diff --git a/Marlin/configuration_store.cpp b/Marlin/configuration_store.cpp
index 5f063d8c056..4ea56ff6f84 100644
--- a/Marlin/configuration_store.cpp
+++ b/Marlin/configuration_store.cpp
@@ -36,16 +36,16 @@
  *
  */
 
-#define EEPROM_VERSION "V37"
+#define EEPROM_VERSION "V38"
 
 // Change EEPROM version if these are changed:
 #define EEPROM_OFFSET 100
 
 /**
- * V37 EEPROM Layout:
+ * V38 EEPROM Layout:
  *
  *  100  Version                                    (char x4)
- *  104  EEPROM Checksum                            (uint16_t)
+ *  104  EEPROM CRC16                               (uint16_t)
  *
  *  106            E_STEPPERS                       (uint8_t)
  *  107  M92 XYZE  planner.axis_steps_per_mm        (float x4 ... x8)
@@ -90,7 +90,7 @@
  * AUTO_BED_LEVELING_UBL:                           6 bytes
  *  324  G29 A     ubl.state.active                 (bool)
  *  325  G29 Z     ubl.state.z_offset               (float)
- *  329  G29 S     ubl.state.eeprom_storage_slot    (int8_t)
+ *  329  G29 S     ubl.state.storage_slot           (int8_t)
  *
  * DELTA:                                           48 bytes
  *  348  M666 XYZ  endstop_adj                      (float x3)
@@ -158,6 +158,14 @@
  *
  *  588                                Minimum end-point
  * 1909 (588 + 36 + 9 + 288 + 988)     Maximum end-point
+ *
+ * ========================================================================
+ * meshes_begin (between max and min end-point, directly above)
+ * -- MESHES --
+ * meshes_end
+ * -- MAT (Mesh Allocation Table) --                128 bytes (placeholder size)
+ * mat_end = E2END (0xFFF)
+ *
  */
 #include "configuration_store.h"
 
@@ -230,18 +238,26 @@ void MarlinSettings::postprocess() {
 
 #if ENABLED(EEPROM_SETTINGS)
 
+  #define DUMMY_PID_VALUE 3000.0f
+  #define EEPROM_START() int eeprom_index = EEPROM_OFFSET
+  #define EEPROM_SKIP(VAR) eeprom_index += sizeof(VAR)
+  #define EEPROM_WRITE(VAR) write_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc)
+  #define EEPROM_READ(VAR) read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc)
+  #define EEPROM_ASSERT(TST,ERR) if (!(TST)) do{ SERIAL_ERROR_START; SERIAL_ERRORLNPGM(ERR); eeprom_read_error = true; }while(0)
+
   const char version[4] = EEPROM_VERSION;
 
-  uint16_t MarlinSettings::eeprom_checksum;
+  bool MarlinSettings::eeprom_error;
 
-  bool MarlinSettings::eeprom_write_error,
-       MarlinSettings::eeprom_read_error;
+  #if ENABLED(AUTO_BED_LEVELING_UBL)
+    int MarlinSettings::meshes_begin;
+  #endif
 
-  void MarlinSettings::write_data(int &pos, const uint8_t* value, uint16_t size) {
-    if (eeprom_write_error) return;
+  void MarlinSettings::write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc) {
+    if (eeprom_error) return;
     while (size--) {
       uint8_t * const p = (uint8_t * const)pos;
-      const uint8_t v = *value;
+      uint8_t v = *value;
       // EEPROM has only ~100,000 write cycles,
       // so only write bytes that have changed!
       if (v != eeprom_read_byte(p)) {
@@ -249,32 +265,27 @@ void MarlinSettings::postprocess() {
         if (eeprom_read_byte(p) != v) {
           SERIAL_ECHO_START;
           SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE);
-          eeprom_write_error = true;
+          eeprom_error = true;
           return;
         }
       }
-      eeprom_checksum += v;
+      crc16(crc, &v, 1);
       pos++;
       value++;
     };
   }
-  void MarlinSettings::read_data(int &pos, uint8_t* value, uint16_t size) {
+
+  void MarlinSettings::read_data(int &pos, uint8_t* value, uint16_t size, uint16_t *crc) {
+    if (eeprom_error) return;
     do {
       uint8_t c = eeprom_read_byte((unsigned char*)pos);
-      if (!eeprom_read_error) *value = c;
-      eeprom_checksum += c;
+      *value = c;
+      crc16(crc, &c, 1);
       pos++;
       value++;
     } while (--size);
   }
 
-  #define DUMMY_PID_VALUE 3000.0f
-  #define EEPROM_START() int eeprom_index = EEPROM_OFFSET
-  #define EEPROM_SKIP(VAR) eeprom_index += sizeof(VAR)
-  #define EEPROM_WRITE(VAR) write_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR))
-  #define EEPROM_READ(VAR) read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR))
-  #define EEPROM_ASSERT(TST,ERR) if (!(TST)) do{ SERIAL_ERROR_START; SERIAL_ERRORLNPGM(ERR); eeprom_read_error = true; }while(0)
-
   /**
    * M500 - Store Configuration
    */
@@ -282,14 +293,16 @@ void MarlinSettings::postprocess() {
     float dummy = 0.0f;
     char ver[4] = "000";
 
+    uint16_t working_crc = 0;
+
     EEPROM_START();
 
-    eeprom_write_error = false;
+    eeprom_error = false;
 
     EEPROM_WRITE(ver);     // invalidate data first
-    EEPROM_SKIP(eeprom_checksum); // Skip the checksum slot
+    EEPROM_SKIP(working_crc); // Skip the checksum slot
 
-    eeprom_checksum = 0; // clear before first "real data"
+    working_crc = 0; // clear before first "real data"
 
     const uint8_t esteppers = COUNT(planner.axis_steps_per_mm) - XYZ;
     EEPROM_WRITE(esteppers);
@@ -410,14 +423,14 @@ void MarlinSettings::postprocess() {
     #if ENABLED(AUTO_BED_LEVELING_UBL)
       EEPROM_WRITE(ubl.state.active);
       EEPROM_WRITE(ubl.state.z_offset);
-      EEPROM_WRITE(ubl.state.eeprom_storage_slot);
+      EEPROM_WRITE(ubl.state.storage_slot);
     #else
-      const bool ubl_active = 0;
+      const bool ubl_active = false;
       dummy = 0.0f;
-      const int8_t eeprom_slot = -1;
+      const int8_t storage_slot = -1;
       EEPROM_WRITE(ubl_active);
       EEPROM_WRITE(dummy);
-      EEPROM_WRITE(eeprom_slot);
+      EEPROM_WRITE(storage_slot);
     #endif // AUTO_BED_LEVELING_UBL
 
     // 9 floats for DELTA / Z_DUAL_ENDSTOPS
@@ -609,43 +622,42 @@ void MarlinSettings::postprocess() {
       EEPROM_WRITE(dummy);
     #endif
 
-    if (!eeprom_write_error) {
-
-      const uint16_t final_checksum = eeprom_checksum,
-                     eeprom_size = eeprom_index;
+    if (!eeprom_error) {
+      const int eeprom_size = eeprom_index;
 
       // Write the EEPROM header
       eeprom_index = EEPROM_OFFSET;
       EEPROM_WRITE(version);
-      EEPROM_WRITE(final_checksum);
+      EEPROM_WRITE(working_crc);
 
       // Report storage size
       SERIAL_ECHO_START;
       SERIAL_ECHOPAIR("Settings Stored (", eeprom_size - (EEPROM_OFFSET));
-      SERIAL_ECHOLNPGM(" bytes)");
+      SERIAL_ECHOPAIR(" bytes; crc ", working_crc);
+      SERIAL_ECHOLNPGM(")");
     }
 
     #if ENABLED(UBL_SAVE_ACTIVE_ON_M500)
-      if (ubl.state.eeprom_storage_slot >= 0)
-        ubl.store_mesh(ubl.state.eeprom_storage_slot);
+      if (ubl.state.storage_slot >= 0)
+        store_mesh(ubl.state.storage_slot);
     #endif
 
-    return !eeprom_write_error;
+    return !eeprom_error;
   }
 
   /**
    * M501 - Retrieve Configuration
    */
   bool MarlinSettings::load() {
+    uint16_t working_crc = 0;
 
     EEPROM_START();
-    eeprom_read_error = false; // If set EEPROM_READ won't write into RAM
 
     char stored_ver[4];
     EEPROM_READ(stored_ver);
 
-    uint16_t stored_checksum;
-    EEPROM_READ(stored_checksum);
+    uint16_t stored_crc;
+    EEPROM_READ(stored_crc);
 
     // Version has to match or defaults are used
     if (strncmp(version, stored_ver, 3) != 0) {
@@ -662,7 +674,7 @@ void MarlinSettings::postprocess() {
     else {
       float dummy = 0;
 
-      eeprom_checksum = 0; // clear before reading first "real data"
+      working_crc = 0; //clear before reading first "real data"
 
       // Number of esteppers may change
       uint8_t esteppers;
@@ -788,7 +800,7 @@ void MarlinSettings::postprocess() {
       #if ENABLED(AUTO_BED_LEVELING_UBL)
         EEPROM_READ(ubl.state.active);
         EEPROM_READ(ubl.state.z_offset);
-        EEPROM_READ(ubl.state.eeprom_storage_slot);
+        EEPROM_READ(ubl.state.storage_slot);
       #else
         bool dummyb;
         uint8_t dummyui8;
@@ -960,42 +972,45 @@ void MarlinSettings::postprocess() {
         EEPROM_READ(dummy);
       #endif
 
-      if (eeprom_checksum == stored_checksum) {
-        if (eeprom_read_error)
-          reset();
-        else {
+      if (working_crc == stored_crc) {
           postprocess();
           SERIAL_ECHO_START;
           SERIAL_ECHO(version);
           SERIAL_ECHOPAIR(" stored settings retrieved (", eeprom_index - (EEPROM_OFFSET));
-          SERIAL_ECHOLNPGM(" bytes)");
-        }
+          SERIAL_ECHOPAIR(" bytes; crc ", working_crc);
+          SERIAL_ECHOLNPGM(")");
       }
       else {
         SERIAL_ERROR_START;
-        SERIAL_ERRORLNPGM("EEPROM checksum mismatch");
+        SERIAL_ERRORPGM("EEPROM checksum mismatch - (stored CRC)");
+        SERIAL_ERROR(stored_crc);
+        SERIAL_ERRORPGM(" != ");
+        SERIAL_ERROR(working_crc);
+        SERIAL_ERRORLNPGM(" (calculated CRC)!");
         reset();
       }
 
       #if ENABLED(AUTO_BED_LEVELING_UBL)
-        ubl.eeprom_start = (eeprom_index + 32) & 0xFFF8; // Pad the end of configuration data so it
-                                                         // can float up or down a little bit without
-                                                         // disrupting the Unified Bed Leveling data
-        SERIAL_ECHOPGM(" UBL ");
-        if (!ubl.state.active) SERIAL_ECHO("not ");
-        SERIAL_ECHOLNPGM("active!");
+        meshes_begin = (eeprom_index + 32) & 0xFFF8;  // Pad the end of configuration data so it
+                                                      // can float up or down a little bit without
+                                                      // disrupting the mesh data
+        ubl.report_state();
 
         if (!ubl.sanity_check()) {
-          SERIAL_ECHOLNPGM("\nUnified Bed Leveling system initialized.\n");
+          SERIAL_EOL;
+          ubl.echo_name();
+          SERIAL_ECHOLNPGM(" initialized.\n");
         }
         else {
-          SERIAL_PROTOCOLPGM("?Unable to enable Unified Bed Leveling system.\n");
+          SERIAL_PROTOCOLPGM("?Can't enable ");
+          ubl.echo_name();
+          SERIAL_PROTOCOLLNPGM(".");
           ubl.reset();
         }
 
-        if (ubl.state.eeprom_storage_slot >= 0) {
-          ubl.load_mesh(ubl.state.eeprom_storage_slot);
-          SERIAL_ECHOPAIR("Mesh ", ubl.state.eeprom_storage_slot);
+        if (ubl.state.storage_slot >= 0) {
+          load_mesh(ubl.state.storage_slot);
+          SERIAL_ECHOPAIR("Mesh ", ubl.state.storage_slot);
           SERIAL_ECHOLNPGM(" loaded from storage.");
         }
         else {
@@ -1009,9 +1024,87 @@ void MarlinSettings::postprocess() {
       report();
     #endif
 
-    return !eeprom_read_error;
+    return !eeprom_error;
   }
 
+
+  #if ENABLED(AUTO_BED_LEVELING_UBL)
+
+    void ubl_invalid_slot(const int s) {
+      SERIAL_PROTOCOLLNPGM("?Invalid slot.");
+      SERIAL_PROTOCOL(s);
+      SERIAL_PROTOCOLLNPGM(" mesh slots available.");
+    }
+
+    int MarlinSettings::calc_num_meshes() {
+      //obviously this will get more sophisticated once we've added an actual MAT
+
+      if (meshes_begin <= 0) return 0;
+
+      return (meshes_end - meshes_begin) / sizeof(ubl.z_values);
+    }
+
+    void MarlinSettings::store_mesh(int8_t slot) {
+
+      #if ENABLED(AUTO_BED_LEVELING_UBL)
+        const int a = calc_num_meshes();
+        if (!WITHIN(slot, 0, a - 1)) {
+          ubl_invalid_slot(a);
+          SERIAL_PROTOCOLPAIR("E2END=", E2END);
+          SERIAL_PROTOCOLPAIR(" meshes_end=", (int)meshes_end);
+          SERIAL_PROTOCOLLNPAIR(" slot=", slot);
+          SERIAL_EOL;
+          return;
+        }
+
+        uint16_t crc = 0;
+        int pos = meshes_end - (slot + 1) * sizeof(ubl.z_values);
+
+        write_data(pos, (uint8_t *)&ubl.z_values, sizeof(ubl.z_values), &crc);
+
+        // Write crc to MAT along with other data, or just tack on to the beginning or end
+
+        SERIAL_PROTOCOLPAIR("Mesh saved in slot ", slot);
+
+      #else
+
+        // Other mesh types
+
+      #endif
+    }
+
+    void MarlinSettings::load_mesh(int8_t slot, void *into /* = 0 */) {
+
+      #if ENABLED(AUTO_BED_LEVELING_UBL)
+
+        const int16_t a = settings.calc_num_meshes();
+
+        if (!WITHIN(slot, 0, a - 1)) {
+          ubl_invalid_slot(a);
+          return;
+        }
+
+        uint16_t crc = 0;
+        int pos = meshes_end - (slot + 1) * sizeof(ubl.z_values);
+        uint8_t * const dest = into ? (uint8_t*)into : (uint8_t*)&ubl.z_values;
+        read_data(pos, dest, sizeof(ubl.z_values), &crc);
+
+        // Compare crc with crc from MAT, or read from end
+
+        SERIAL_PROTOCOLPAIR("Mesh loaded from slot ", slot);
+
+      #else
+
+        // Other mesh types
+
+      #endif
+    }
+
+    //void MarlinSettings::delete_mesh() { return; }
+    //void MarlinSettings::defrag_meshes() { return; }
+
+  #endif // AUTO_BED_LEVELING_UBL
+
 #else // !EEPROM_SETTINGS
 
   bool MarlinSettings::save() {
@@ -1449,7 +1542,8 @@ void MarlinSettings::reset() {
 
       if (!forReplay) {
         CONFIG_ECHO_START;
-        SERIAL_ECHOLNPGM("Unified Bed Leveling:");
+        ubl.echo_name();
+        SERIAL_ECHOLNPGM(":");
       }
       CONFIG_ECHO_START;
       SERIAL_ECHOPAIR("  M420 S", ubl.state.active ? 1 : 0);
@@ -1458,7 +1552,19 @@ void MarlinSettings::reset() {
       #endif
       SERIAL_EOL;
 
-      if (!forReplay) ubl.g29_what_command();
+      if (!forReplay) {
+        SERIAL_EOL;
+        ubl.report_state();
+
+        SERIAL_ECHOLNPAIR("\nActive Mesh Slot: ", ubl.state.storage_slot);
+
+        SERIAL_ECHOPGM("z_offset: ");
+        SERIAL_ECHO_F(ubl.state.z_offset, 6);
+        SERIAL_EOL;
+
+        SERIAL_ECHOPAIR("EEPROM can hold ", calc_num_meshes());
+        SERIAL_ECHOLNPGM(" meshes.\n");
+      }
 
     #elif HAS_ABL
 
diff --git a/Marlin/configuration_store.h b/Marlin/configuration_store.h
index e31d20b5cbd..1166ed29ea6 100644
--- a/Marlin/configuration_store.h
+++ b/Marlin/configuration_store.h
@@ -34,6 +34,18 @@ class MarlinSettings {
 
     #if ENABLED(EEPROM_SETTINGS)
       static bool load();
+
+      #if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
+                                         // That can store is enabled
+        FORCE_INLINE static int get_start_of_meshes() { return meshes_begin; }
+        FORCE_INLINE static int get_end_of_meshes() { return meshes_end; }
+        static int calc_num_meshes();
+        static void store_mesh(int8_t slot);
+        static void load_mesh(int8_t slot, void *into = 0);
+
+        //static void delete_mesh();    // necessary if we have a MAT
+        //static void defrag_meshes();  // "
+      #endif
     #else
       FORCE_INLINE
       static bool load() { reset(); report(); return true; }
@@ -50,10 +62,18 @@ class MarlinSettings {
     static void postprocess();
 
     #if ENABLED(EEPROM_SETTINGS)
-      static uint16_t eeprom_checksum;
-      static bool eeprom_read_error, eeprom_write_error;
-      static void write_data(int &pos, const uint8_t* value, uint16_t size);
-      static void read_data(int &pos, uint8_t* value, uint16_t size);
+      static bool eeprom_error;
+
+      #if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
+                                         // That can store is enabled
+        static int meshes_begin;
+        const static int mat_end = E2END;            // Mesh allocation table; this may not end up being necessary
+        const static int meshes_end = mat_end - 128; // 128 is a placeholder for the size of the MAT
+
+      #endif
+
+      static void write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc);
+      static void read_data(int &pos, uint8_t *value, uint16_t size, uint16_t *crc);
     #endif
 };
 
diff --git a/Marlin/ubl.cpp b/Marlin/ubl.cpp
index bff73b17236..8ca43c5be16 100644
--- a/Marlin/ubl.cpp
+++ b/Marlin/ubl.cpp
@@ -41,6 +41,16 @@
 
   uint8_t ubl_cnt = 0;
 
+  void unified_bed_leveling::echo_name() { SERIAL_PROTOCOLPGM("Unified Bed Leveling"); }
+
+  void unified_bed_leveling::report_state() {
+    echo_name();
+    SERIAL_PROTOCOLPGM(" System v" UBL_VERSION " ");
+    if (!state.active) SERIAL_PROTOCOLPGM("in");
+    SERIAL_PROTOCOLLNPGM("active.");
+    safe_delay(50);
+  }
+
   static void serial_echo_xy(const int16_t x, const int16_t y) {
     SERIAL_CHAR('(');
     SERIAL_ECHO(x);
@@ -63,9 +73,6 @@
   bool unified_bed_leveling::g26_debug_flag = false,
        unified_bed_leveling::has_control_of_lcd_panel = false;
 
-  int16_t unified_bed_leveling::eeprom_start = -1;  // Please stop changing this to 8 bits in size
-                                                    // It needs to hold values bigger than this.
-
   volatile int unified_bed_leveling::encoder_diff;
 
   unified_bed_leveling::unified_bed_leveling() {
@@ -73,53 +80,10 @@
     reset();
   }
 
-  void unified_bed_leveling::load_mesh(const int16_t slot) {
-    int16_t j = (UBL_LAST_EEPROM_INDEX - eeprom_start) / sizeof(z_values);
-
-    if (slot == -1) {
-      SERIAL_PROTOCOLLNPGM("?No mesh saved in EEPROM. Zeroing mesh in memory.\n");
-      reset();
-      return;
-    }
-
-    if (!WITHIN(slot, 0, j - 1) || eeprom_start <= 0) {
-      SERIAL_PROTOCOLLNPGM("?EEPROM storage not available to load mesh.\n");
-      return;
-    }
-
-    j = UBL_LAST_EEPROM_INDEX - (slot + 1) * sizeof(z_values);
-    eeprom_read_block((void *)&z_values, (void *)j, sizeof(z_values));
-
-    SERIAL_PROTOCOLPAIR("Mesh loaded from slot ", slot);
-    SERIAL_PROTOCOLLNPAIR(" at offset ", hex_address((void*)j));
-  }
-
-  void unified_bed_leveling::store_mesh(const int16_t slot) {
-    int16_t j = (UBL_LAST_EEPROM_INDEX - eeprom_start) / sizeof(z_values);
-
-    if (!WITHIN(slot, 0, j - 1) || eeprom_start <= 0) {
-      SERIAL_PROTOCOLLNPGM("?EEPROM storage not available to load mesh.\n");
-      SERIAL_PROTOCOL(slot);
-      SERIAL_PROTOCOLLNPGM(" mesh slots available.\n");
-      SERIAL_PROTOCOLLNPAIR("E2END     : ", E2END);
-      SERIAL_PROTOCOLLNPAIR("k         : ", (int)UBL_LAST_EEPROM_INDEX);
-      SERIAL_PROTOCOLLNPAIR("j         : ", j);
-      SERIAL_PROTOCOLLNPAIR("m         : ", slot);
-      SERIAL_EOL;
-      return;
-    }
-
-    j = UBL_LAST_EEPROM_INDEX - (slot + 1) * sizeof(z_values);
-    eeprom_write_block((const void *)&z_values, (void *)j, sizeof(z_values));
-
-    SERIAL_PROTOCOLPAIR("Mesh saved in slot ", slot);
-    SERIAL_PROTOCOLLNPAIR(" at offset ", hex_address((void*)j));
-  }
-
   void unified_bed_leveling::reset() {
     state.active = false;
     state.z_offset = 0;
-    state.eeprom_storage_slot = -1;
+    state.storage_slot = -1;
 
     ZERO(z_values);
 
@@ -203,9 +167,9 @@
   bool unified_bed_leveling::sanity_check() {
     uint8_t error_flag = 0;
 
-    const int j = (UBL_LAST_EEPROM_INDEX - eeprom_start) / sizeof(z_values);
-    if (j < 1) {
-      SERIAL_PROTOCOLLNPGM("?No EEPROM storage available for a mesh of this size.\n");
+    const int a = settings.calc_num_meshes();
+    if (a < 1) {
+      SERIAL_PROTOCOLLNPGM("?Insufficient EEPROM storage for a mesh of this size.");
       error_flag++;
     }
 
diff --git a/Marlin/ubl.h b/Marlin/ubl.h
index 93718d6c5a1..b1a6b9f7eef 100644
--- a/Marlin/ubl.h
+++ b/Marlin/ubl.h
@@ -30,8 +30,9 @@
   #include "planner.h"
   #include "math.h"
   #include "vector_3.h"
+  #include "configuration_store.h"
 
-  #define UBL_VERSION "1.00"
+  #define UBL_VERSION "1.01"
   #define UBL_OK false
   #define UBL_ERR true
 
@@ -92,7 +93,7 @@
   typedef struct {
     bool active = false;
     float z_offset = 0.0;
-    int8_t eeprom_storage_slot = -1;
+    int8_t storage_slot = -1;
   } ubl_state;
 
   class unified_bed_leveling {
@@ -102,6 +103,8 @@
 
     public:
 
+      void echo_name();
+      void report_state();
       void find_mean_mesh_height();
       void shift_mesh_height();
       void probe_entire_mesh(const float &lx, const float &ly, const bool do_ubl_mesh_map, const bool stow_probe, bool do_furthest);
@@ -117,10 +120,6 @@
       void display_map(const int);
       void reset();
       void invalidate();
-      void store_state();
-      void load_state();
-      void store_mesh(const int16_t);
-      void load_mesh(const int16_t);
       bool sanity_check();
 
       static ubl_state state;
@@ -153,9 +152,6 @@
 
       static bool g26_debug_flag, has_control_of_lcd_panel;
 
-      static int16_t eeprom_start;    // Please do no change this to 8 bits in size
-                                      // It needs to hold values bigger than this.
-
       static volatile int encoder_diff; // Volatile because it's changed at interrupt time.
 
       unified_bed_leveling();
@@ -351,7 +347,5 @@
 
   extern unified_bed_leveling ubl;
 
-  #define UBL_LAST_EEPROM_INDEX E2END
-
 #endif // AUTO_BED_LEVELING_UBL
 #endif // UNIFIED_BED_LEVELING_H
diff --git a/Marlin/ubl_G29.cpp b/Marlin/ubl_G29.cpp
index 065256c8d59..6e97d702fab 100644
--- a/Marlin/ubl_G29.cpp
+++ b/Marlin/ubl_G29.cpp
@@ -314,7 +314,7 @@
 
   void __attribute__((optimize("O0"))) gcode_G29() {
 
-    if (ubl.eeprom_start < 0) {
+    if (!settings.calc_num_meshes()) {
       SERIAL_PROTOCOLLNPGM("?You need to enable your EEPROM and initialize it");
       SERIAL_PROTOCOLLNPGM("with M502, M500, M501 in that order.\n");
       return;
@@ -419,9 +419,9 @@
     }
 
     if (code_seen('P')) {
-      if (WITHIN(phase_value, 0, 1) && ubl.state.eeprom_storage_slot == -1) {
-        ubl.state.eeprom_storage_slot = 0;
-        SERIAL_PROTOCOLLNPGM("Default storage slot 0 selected.\n");
+      if (WITHIN(phase_value, 0, 1) && ubl.state.storage_slot == -1) {
+        ubl.state.storage_slot = 0;
+        SERIAL_PROTOCOLLNPGM("Default storage slot 0 selected.");
       }
 
       switch (phase_value) {
@@ -430,7 +430,7 @@
           // Zero Mesh Data
           //
           ubl.reset();
-          SERIAL_PROTOCOLLNPGM("Mesh zeroed.\n");
+          SERIAL_PROTOCOLLNPGM("Mesh zeroed.");
           break;
 
         case 1:
@@ -439,7 +439,7 @@
           //
           if (!code_seen('C')) {
             ubl.invalidate();
-            SERIAL_PROTOCOLLNPGM("Mesh invalidated. Probing mesh.\n");
+            SERIAL_PROTOCOLLNPGM("Mesh invalidated. Probing mesh.");
           }
           if (g29_verbose_level > 1) {
             SERIAL_PROTOCOLPAIR("Probing Mesh Points Closest to (", x_pos);
@@ -455,7 +455,7 @@
           //
           // Manually Probe Mesh in areas that can't be reached by the probe
           //
-          SERIAL_PROTOCOLLNPGM("Manually probing unreachable mesh locations.\n");
+          SERIAL_PROTOCOLLNPGM("Manually probing unreachable mesh locations.");
           do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
           if (!x_flag && !y_flag) {
             /**
@@ -485,7 +485,7 @@
             card_thickness = code_has_value() ? code_value_float() : measure_business_card_thickness(height);
 
             if (fabs(card_thickness) > 1.5) {
-              SERIAL_PROTOCOLLNPGM("?Error in Business Card measurement.\n");
+              SERIAL_PROTOCOLLNPGM("?Error in Business Card measurement.");
               return;
             }
           }
@@ -561,17 +561,25 @@
     //
 
     if (code_seen('L')) {     // Load Current Mesh Data
-      storage_slot = code_has_value() ? code_value_int() : ubl.state.eeprom_storage_slot;
+      storage_slot = code_has_value() ? code_value_int() : ubl.state.storage_slot;
 
-      const int16_t j = (UBL_LAST_EEPROM_INDEX - ubl.eeprom_start) / sizeof(ubl.z_values);
+      int16_t a = settings.calc_num_meshes();
 
-      if (!WITHIN(storage_slot, 0, j - 1) || ubl.eeprom_start <= 0) {
-        SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n");
+      if (!a) {
+        SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
         return;
       }
-      ubl.load_mesh(storage_slot);
-      ubl.state.eeprom_storage_slot = storage_slot;
-      SERIAL_PROTOCOLLNPGM("Done.\n");
+
+      if (!WITHIN(storage_slot, 0, a - 1)) {
+        SERIAL_PROTOCOLLNPGM("?Invalid storage slot.");
+        SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
+        return;
+      }
+
+      settings.load_mesh(storage_slot);
+      ubl.state.storage_slot = storage_slot;
+
+      SERIAL_PROTOCOLLNPGM("Done.");
     }
 
     //
@@ -579,7 +587,7 @@
     //
 
     if (code_seen('S')) {     // Store (or Save) Current Mesh Data
-      storage_slot = code_has_value() ? code_value_int() : ubl.state.eeprom_storage_slot;
+      storage_slot = code_has_value() ? code_value_int() : ubl.state.storage_slot;
 
       if (storage_slot == -1) {                     // Special case, we are going to 'Export' the mesh to the
         SERIAL_ECHOLNPGM("G29 I 999");              // host in a form it can be reconstructed on a different machine
@@ -597,17 +605,23 @@
         return;
       }
 
-      const int16_t j = (UBL_LAST_EEPROM_INDEX - ubl.eeprom_start) / sizeof(ubl.z_values);
+      int16_t a = settings.calc_num_meshes();
 
-      if (!WITHIN(storage_slot, 0, j - 1) || ubl.eeprom_start <= 0) {
-        SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n");
-        SERIAL_PROTOCOLLNPAIR("?Use 0 to ", j - 1);
+      if (!a) {
+        SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
         goto LEAVE;
       }
-      ubl.store_mesh(storage_slot);
-      ubl.state.eeprom_storage_slot = storage_slot;
 
-      SERIAL_PROTOCOLLNPGM("Done.\n");
+      if (!WITHIN(storage_slot, 0, a - 1)) {
+        SERIAL_PROTOCOLLNPGM("?Invalid storage slot.");
+        SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
+        goto LEAVE;
+      }
+
+      settings.store_mesh(storage_slot);
+      ubl.state.storage_slot = storage_slot;
+
+      SERIAL_PROTOCOLLNPGM("Done.");
     }
 
     if (code_seen('T'))
@@ -654,7 +668,7 @@
           if (ELAPSED(millis(), nxt)) {
             SERIAL_PROTOCOLLNPGM("\nZ-Offset Adjustment Stopped.");
             do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
-            LCD_MESSAGEPGM("Z-Offset Stopped");
+            LCD_MESSAGEPGM("Z-Offset Stopped"); // TODO: Make translatable string
             ubl.restore_ubl_active_state_and_leave();
             goto LEAVE;
           }
@@ -892,7 +906,7 @@
     return current_position[Z_AXIS];
   }
 
-  static void say_and_take_a_measurement() {
+  static void echo_and_take_a_measurement() {
     SERIAL_PROTOCOLLNPGM(" and take a measurement.");
   }
 
@@ -906,17 +920,17 @@
     stepper.synchronize();
 
     SERIAL_PROTOCOLPGM("Place shim under nozzle");
-    LCD_MESSAGEPGM("Place shim & measure");
+    LCD_MESSAGEPGM("Place shim & measure"); // TODO: Make translatable string
     lcd_goto_screen(lcd_status_screen);
-    say_and_take_a_measurement();
+    echo_and_take_a_measurement();
 
     const float z1 = use_encoder_wheel_to_measure_point();
     do_blocking_move_to_z(current_position[Z_AXIS] + SIZE_OF_LITTLE_RAISE);
     stepper.synchronize();
 
     SERIAL_PROTOCOLPGM("Remove shim");
-    LCD_MESSAGEPGM("Remove & measure bed");
-    say_and_take_a_measurement();
+    LCD_MESSAGEPGM("Remove & measure bed"); // TODO: Make translatable string
+    echo_and_take_a_measurement();
 
     const float z2 = use_encoder_wheel_to_measure_point();
 
@@ -962,7 +976,7 @@
 
       do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
 
-      LCD_MESSAGEPGM("Moving to next");
+      LCD_MESSAGEPGM("Moving to next"); // TODO: Make translatable string
 
       do_blocking_move_to_xy(xProbe, yProbe);
       do_blocking_move_to_z(z_clearance);
@@ -972,8 +986,10 @@
 
       if (do_ubl_mesh_map) ubl.display_map(map_type);  // show user where we're probing
 
-      if (code_seen('B')) {LCD_MESSAGEPGM("Place shim & measure");}
-      else {LCD_MESSAGEPGM("Measure");}
+      if (code_seen('B'))
+        LCD_MESSAGEPGM("Place shim & measure"); // TODO: Make translatable string
+      else
+        LCD_MESSAGEPGM("Measure"); // TODO: Make translatable string
 
       while (ubl_lcd_clicked()) delay(50);             // wait for user to release encoder wheel
       delay(50);                                       // debounce
@@ -1017,21 +1033,10 @@
     do_blocking_move_to_xy(lx, ly);
   }
 
-  static void say_ubl_name() {
-    SERIAL_PROTOCOLPGM("Unified Bed Leveling ");
-  }
-
-  static void report_ubl_state() {
-    say_ubl_name();
-    SERIAL_PROTOCOLPGM("System ");
-    if (!ubl.state.active) SERIAL_PROTOCOLPGM("de");
-    SERIAL_PROTOCOLLNPGM("activated.\n");
-  }
-
   bool g29_parameter_parsing() {
     bool err_flag = false;
 
-    LCD_MESSAGEPGM("Doing G29 UBL!");
+    LCD_MESSAGEPGM("Doing G29 UBL!"); // TODO: Make translatable string
     lcd_quick_feedback();
 
     ubl_constant = 0.0;
@@ -1096,12 +1101,12 @@
         SERIAL_PROTOCOLLNPGM("?Can't activate and deactivate at the same time.\n");
         return UBL_ERR;
       }
-      ubl.state.active = 1;
-      report_ubl_state();
+      ubl.state.active = true;
+      ubl.report_state();
     }
     else if (code_seen('D')) {
-      ubl.state.active = 0;
-      report_ubl_state();
+      ubl.state.active = false;
+      ubl.report_state();
     }
 
     // Set global 'C' flag and its value
@@ -1134,7 +1139,7 @@
     ubl_state_recursion_chk++;
     if (ubl_state_recursion_chk != 1) {
       SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row.");
-      LCD_MESSAGEPGM("save_UBL_active() error");
+      LCD_MESSAGEPGM("save_UBL_active() error"); // TODO: Make translatable string
       lcd_quick_feedback();
       return;
     }
@@ -1145,7 +1150,7 @@
   void unified_bed_leveling::restore_ubl_active_state_and_leave() {
     if (--ubl_state_recursion_chk) {
       SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times.");
-      LCD_MESSAGEPGM("restore_UBL_active() error");
+      LCD_MESSAGEPGM("restore_UBL_active() error"); // TODO: Make translatable string
       lcd_quick_feedback();
       return;
     }
@@ -1157,21 +1162,12 @@
    * good to have the extra information. Soon... we prune this to just a few items
    */
   void unified_bed_leveling::g29_what_command() {
-    const uint16_t k = E2END - ubl.eeprom_start;
+    report_state();
 
-    say_ubl_name();
-    SERIAL_PROTOCOLPGM("System Version " UBL_VERSION " ");
-    if (state.active)
-      SERIAL_PROTOCOLCHAR('A');
-    else
-      SERIAL_PROTOCOLPGM("Ina");
-    SERIAL_PROTOCOLLNPGM("ctive.\n");
-    safe_delay(50);
-
-    if (state.eeprom_storage_slot == -1)
+    if (state.storage_slot == -1)
       SERIAL_PROTOCOLPGM("No Mesh Loaded.");
     else {
-      SERIAL_PROTOCOLPAIR("Mesh ", state.eeprom_storage_slot);
+      SERIAL_PROTOCOLPAIR("Mesh ", state.storage_slot);
       SERIAL_PROTOCOLPGM(" Loaded.");
     }
     SERIAL_EOL;
@@ -1188,12 +1184,15 @@
     SERIAL_PROTOCOL_F(zprobe_zoffset, 7);
     SERIAL_EOL;
 
-    SERIAL_PROTOCOLLNPAIR("ubl.eeprom_start=", hex_address((void*)eeprom_start));
-
+    SERIAL_ECHOLNPAIR("UBL_MESH_MIN_X  " STRINGIFY(UBL_MESH_MIN_X) "=", UBL_MESH_MIN_X);
+    SERIAL_ECHOLNPAIR("UBL_MESH_MIN_Y  " STRINGIFY(UBL_MESH_MIN_Y) "=", UBL_MESH_MIN_Y);
+    safe_delay(25);
+    SERIAL_ECHOLNPAIR("UBL_MESH_MAX_X  " STRINGIFY(UBL_MESH_MAX_X) "=", UBL_MESH_MAX_X);
+    SERIAL_ECHOLNPAIR("UBL_MESH_MAX_Y  " STRINGIFY(UBL_MESH_MAX_Y) "=", UBL_MESH_MAX_Y);
+    safe_delay(25);
     SERIAL_ECHOLNPAIR("GRID_MAX_POINTS_X  ", GRID_MAX_POINTS_X);
     SERIAL_ECHOLNPAIR("GRID_MAX_POINTS_Y  ", GRID_MAX_POINTS_Y);
     safe_delay(25);
-
     SERIAL_ECHOLNPAIR("MESH_X_DIST  ", MESH_X_DIST);
     SERIAL_ECHOLNPAIR("MESH_Y_DIST  ", MESH_Y_DIST);
     safe_delay(25);
@@ -1214,43 +1213,39 @@
     }
     SERIAL_EOL;
 
-    SERIAL_PROTOCOLLNPAIR("Free EEPROM space starts at: ", hex_address((void*)eeprom_start));
-    SERIAL_PROTOCOLLNPAIR("end of EEPROM: ", hex_address((void*)E2END));
-    safe_delay(25);
+    #if HAS_KILL
+      SERIAL_PROTOCOLPAIR("Kill pin on :", KILL_PIN);
+      SERIAL_PROTOCOLLNPAIR("  state:", READ(KILL_PIN));
+    #endif
+    SERIAL_EOL;
+    safe_delay(50);
 
-    SERIAL_PROTOCOLPAIR("sizeof(ubl.state) : ", (int)sizeof(state));
+    SERIAL_PROTOCOLLNPAIR("ubl_state_at_invocation :", ubl_state_at_invocation);
+    SERIAL_EOL;
+    SERIAL_PROTOCOLLNPAIR("ubl_state_recursion_chk :", ubl_state_recursion_chk);
+    SERIAL_EOL;
+    safe_delay(50);
+
+    SERIAL_PROTOCOLPAIR("Meshes go from ", hex_address((void*)settings.get_start_of_meshes()));
+    SERIAL_PROTOCOLLNPAIR(" to ", hex_address((void*)settings.get_end_of_meshes()));
+    safe_delay(50);
+
+    SERIAL_PROTOCOLLNPAIR("sizeof(ubl) :  ", (int)sizeof(ubl));
     SERIAL_EOL;
     SERIAL_PROTOCOLLNPAIR("z_value[][] size: ", (int)sizeof(z_values));
     SERIAL_EOL;
     safe_delay(25);
 
-    SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)k));
-    safe_delay(25);
+    SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)(settings.get_end_of_meshes() - settings.get_start_of_meshes())));
+    safe_delay(50);
 
-    SERIAL_PROTOCOLPAIR("EEPROM can hold ", k / sizeof(z_values));
+    SERIAL_PROTOCOLPAIR("EEPROM can hold ", settings.calc_num_meshes());
     SERIAL_PROTOCOLLNPGM(" meshes.\n");
     safe_delay(25);
 
-    SERIAL_PROTOCOLPAIR("\nGRID_MAX_POINTS_X  ", GRID_MAX_POINTS_X);
-    SERIAL_PROTOCOLPAIR("\nGRID_MAX_POINTS_Y  ", GRID_MAX_POINTS_Y);
-    safe_delay(25);
-    SERIAL_EOL;
-
-    SERIAL_ECHOPGM("UBL_MESH_MIN_X  " STRINGIFY(UBL_MESH_MIN_X));
-    SERIAL_ECHOLNPAIR("=", UBL_MESH_MIN_X );
-    SERIAL_ECHOPGM("UBL_MESH_MIN_Y  " STRINGIFY(UBL_MESH_MIN_Y));
-    SERIAL_ECHOLNPAIR("=", UBL_MESH_MIN_Y );
-    safe_delay(25);
-
-    SERIAL_ECHOPGM("UBL_MESH_MAX_X  " STRINGIFY(UBL_MESH_MAX_X));
-    SERIAL_ECHOLNPAIR("=", UBL_MESH_MAX_X);
-    SERIAL_ECHOPGM("UBL_MESH_MAX_Y  " STRINGIFY(UBL_MESH_MAX_Y));
-    SERIAL_ECHOLNPAIR("=", UBL_MESH_MAX_Y);
-    safe_delay(25);
-
     if (!sanity_check()) {
-      say_ubl_name();
-      SERIAL_PROTOCOLLNPGM("sanity checks passed.");
+      echo_name();
+      SERIAL_PROTOCOLLNPGM(" sanity checks passed.");
     }
   }
 
@@ -1284,27 +1279,32 @@
    * use cases for the users. So we can wait and see what to do with it.
    */
   void g29_compare_current_mesh_to_stored_mesh() {
-    float tmp_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
+    int16_t a = settings.calc_num_meshes();
+
+    if (!a) {
+      SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
+      return;
+    }
 
     if (!code_has_value()) {
-      SERIAL_PROTOCOLLNPGM("?Mesh # required.\n");
+      SERIAL_PROTOCOLLNPGM("?Storage slot # required.");
+      SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
       return;
     }
+
     storage_slot = code_value_int();
 
-    int16_t j = (UBL_LAST_EEPROM_INDEX - ubl.eeprom_start) / sizeof(tmp_z_values);
-
-    if (!WITHIN(storage_slot, 0, j - 1) || ubl.eeprom_start <= 0) {
-      SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n");
+    if (!WITHIN(storage_slot, 0, a - 1)) {
+      SERIAL_PROTOCOLLNPGM("?Invalid storage slot.");
+      SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
       return;
     }
 
-    j = UBL_LAST_EEPROM_INDEX - (storage_slot + 1) * sizeof(tmp_z_values);
-    eeprom_read_block((void *)&tmp_z_values, (void *)j, sizeof(tmp_z_values));
+    float tmp_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
+    settings.load_mesh(storage_slot, &tmp_z_values);
 
-    SERIAL_ECHOPAIR("Subtracting Mesh ", storage_slot);
-    SERIAL_PROTOCOLLNPAIR(" loaded from EEPROM address ", hex_address((void*)j)); // Soon, we can remove the extra clutter of printing
-                                                                        // the address in the EEPROM where the Mesh is stored.
+    SERIAL_PROTOCOLPAIR("Subtracting mesh in slot ", storage_slot);
+    SERIAL_PROTOCOLLNPGM(" from current mesh.");
 
     for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
       for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)
@@ -1396,7 +1396,7 @@
 
     memset(not_done, 0xFF, sizeof(not_done));
 
-    LCD_MESSAGEPGM("Fine Tuning Mesh");
+    LCD_MESSAGEPGM("Fine Tuning Mesh"); // TODO: Make translatable string
 
     do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
     do_blocking_move_to_xy(lx, ly);
@@ -1454,7 +1454,7 @@
           lcd_return_to_status();
           //SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped.");
           do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
-          LCD_MESSAGEPGM("Mesh Editing Stopped");
+          LCD_MESSAGEPGM("Mesh Editing Stopped"); // TODO: Make translatable string
 
           while (ubl_lcd_clicked()) idle();
 
@@ -1481,7 +1481,7 @@
 
     do_blocking_move_to_xy(lx, ly);
 
-    LCD_MESSAGEPGM("Done Editing Mesh");
+    LCD_MESSAGEPGM("Done Editing Mesh"); // TODO: Make translatable string
     SERIAL_ECHOLNPGM("Done Editing Mesh");
   }
 
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index 0c211791272..6b3784bac7b 100644
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -1425,10 +1425,6 @@ void kill_screen(const char* lcd_msg) {
 
     static uint8_t manual_probe_index;
 
-    #if ENABLED(PROBE_MANUALLY)
-      extern bool g29_in_progress;
-    #endif
-
     // LCD probed points are from defaults
     constexpr uint8_t total_probe_points = (
       #if ENABLED(AUTO_BED_LEVELING_3POINT)
@@ -1645,6 +1641,10 @@ void kill_screen(const char* lcd_msg) {
 
   #if ENABLED(LCD_BED_LEVELING) || HAS_ABL
 
+    #if ENABLED(PROBE_MANUALLY)
+      extern bool g29_in_progress;
+    #endif
+
     /**
      * Step 2: Continue Bed Leveling...
      */
diff --git a/Marlin/utility.cpp b/Marlin/utility.cpp
index 03b336af42b..43544106eb7 100644
--- a/Marlin/utility.cpp
+++ b/Marlin/utility.cpp
@@ -34,6 +34,19 @@ void safe_delay(millis_t ms) {
   thermalManager.manage_heater(); // This keeps us safe if too many small safe_delay() calls are made
 }
 
+#if ENABLED(EEPROM_SETTINGS)
+
+  void crc16(uint16_t *crc, const void * const data, uint16_t cnt) {
+    uint8_t *ptr = (uint8_t*)data;
+    while (cnt-- > 0) {
+      *crc = (uint16_t)(*crc ^ (uint16_t)(((uint16_t)*ptr++) << 8));
+      for (uint8_t x = 0; x < 8; x++)
+        *crc = (uint16_t)((*crc & 0x8000) ? ((uint16_t)(*crc << 1) ^ 0x1021) : (*crc << 1));
+    }
+  }
+
+#endif // EEPROM_SETTINGS
+
 #if ENABLED(ULTRA_LCD)
 
   char conv[8] = { 0 };
diff --git a/Marlin/utility.h b/Marlin/utility.h
index 7306b053c63..f14b272fb4c 100644
--- a/Marlin/utility.h
+++ b/Marlin/utility.h
@@ -25,6 +25,10 @@
 
 void safe_delay(millis_t ms);
 
+#if ENABLED(EEPROM_SETTINGS)
+  void crc16(uint16_t *crc, const void * const data, uint16_t cnt);
+#endif
+
 #if ENABLED(ULTRA_LCD)
 
   // Convert unsigned int to string with 12 format