Add OPTIMIZED_MESH_STORAGE option (for UBL) (#20371)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
parent
2d88a2cfb7
commit
844a8c7074
@ -1739,6 +1739,10 @@
|
|||||||
//#define MESH_MAX_Y Y_BED_SIZE - (MESH_INSET)
|
//#define MESH_MAX_Y Y_BED_SIZE - (MESH_INSET)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if BOTH(AUTO_BED_LEVELING_UBL, EEPROM_SETTINGS)
|
||||||
|
//#define OPTIMIZED_MESH_STORAGE // Store mesh with less precision to save EEPROM space
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repeatedly attempt G29 leveling until it succeeds.
|
* Repeatedly attempt G29 leveling until it succeeds.
|
||||||
* Stop after G29_MAX_RETRIES attempts.
|
* Stop after G29_MAX_RETRIES attempts.
|
||||||
|
@ -286,6 +286,7 @@
|
|||||||
#define RSQRT(x) (1.0f / sqrtf(x))
|
#define RSQRT(x) (1.0f / sqrtf(x))
|
||||||
#define CEIL(x) ceilf(x)
|
#define CEIL(x) ceilf(x)
|
||||||
#define FLOOR(x) floorf(x)
|
#define FLOOR(x) floorf(x)
|
||||||
|
#define TRUNC(x) truncf(x)
|
||||||
#define LROUND(x) lroundf(x)
|
#define LROUND(x) lroundf(x)
|
||||||
#define FMOD(x, y) fmodf(x, y)
|
#define FMOD(x, y) fmodf(x, y)
|
||||||
#define HYPOT(x,y) SQRT(HYPOT2(x,y))
|
#define HYPOT(x,y) SQRT(HYPOT2(x,y))
|
||||||
|
@ -42,9 +42,7 @@
|
|||||||
|
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
void unified_bed_leveling::echo_name() {
|
void unified_bed_leveling::echo_name() { SERIAL_ECHOPGM("Unified Bed Leveling"); }
|
||||||
SERIAL_ECHOPGM("Unified Bed Leveling");
|
|
||||||
}
|
|
||||||
|
|
||||||
void unified_bed_leveling::report_current_mesh() {
|
void unified_bed_leveling::report_current_mesh() {
|
||||||
if (!leveling_is_valid()) return;
|
if (!leveling_is_valid()) return;
|
||||||
@ -86,9 +84,7 @@
|
|||||||
|
|
||||||
volatile int16_t unified_bed_leveling::encoder_diff;
|
volatile int16_t unified_bed_leveling::encoder_diff;
|
||||||
|
|
||||||
unified_bed_leveling::unified_bed_leveling() {
|
unified_bed_leveling::unified_bed_leveling() { reset(); }
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void unified_bed_leveling::reset() {
|
void unified_bed_leveling::reset() {
|
||||||
const bool was_enabled = planner.leveling_active;
|
const bool was_enabled = planner.leveling_active;
|
||||||
@ -113,6 +109,31 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLED(OPTIMIZED_MESH_STORAGE)
|
||||||
|
|
||||||
|
constexpr float mesh_store_scaling = 1000;
|
||||||
|
constexpr int16_t Z_STEPS_NAN = INT16_MAX;
|
||||||
|
|
||||||
|
void unified_bed_leveling::set_store_from_mesh(const bed_mesh_t &in_values, mesh_store_t &stored_values) {
|
||||||
|
auto z_to_store = [](const float &z) {
|
||||||
|
if (isnan(z)) return Z_STEPS_NAN;
|
||||||
|
const int32_t z_scaled = TRUNC(z * mesh_store_scaling);
|
||||||
|
if (z_scaled == Z_STEPS_NAN || !WITHIN(z_scaled, INT16_MIN, INT16_MAX))
|
||||||
|
return Z_STEPS_NAN; // If Z is out of range, return our custom 'NaN'
|
||||||
|
return int16_t(z_scaled);
|
||||||
|
};
|
||||||
|
GRID_LOOP(x, y) stored_values[x][y] = z_to_store(in_values[x][y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unified_bed_leveling::set_mesh_from_store(const mesh_store_t &stored_values, bed_mesh_t &out_values) {
|
||||||
|
auto store_to_z = [](const int16_t z_scaled) {
|
||||||
|
return z_scaled == Z_STEPS_NAN ? NAN : z_scaled / mesh_store_scaling;
|
||||||
|
};
|
||||||
|
GRID_LOOP(x, y) out_values[x][y] = store_to_z(stored_values[x][y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPTIMIZED_MESH_STORAGE
|
||||||
|
|
||||||
static void serial_echo_xy(const uint8_t sp, const int16_t x, const int16_t y) {
|
static void serial_echo_xy(const uint8_t sp, const int16_t x, const int16_t y) {
|
||||||
SERIAL_ECHO_SP(sp);
|
SERIAL_ECHO_SP(sp);
|
||||||
SERIAL_CHAR('(');
|
SERIAL_CHAR('(');
|
||||||
@ -127,7 +148,7 @@
|
|||||||
|
|
||||||
static void serial_echo_column_labels(const uint8_t sp) {
|
static void serial_echo_column_labels(const uint8_t sp) {
|
||||||
SERIAL_ECHO_SP(7);
|
SERIAL_ECHO_SP(7);
|
||||||
for (int8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
|
LOOP_L_N(i, GRID_MAX_POINTS_X) {
|
||||||
if (i < 10) SERIAL_CHAR(' ');
|
if (i < 10) SERIAL_CHAR(' ');
|
||||||
SERIAL_ECHO(i);
|
SERIAL_ECHO(i);
|
||||||
SERIAL_ECHO_SP(sp);
|
SERIAL_ECHO_SP(sp);
|
||||||
|
@ -41,6 +41,10 @@ struct mesh_index_pair;
|
|||||||
#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / float(GRID_MAX_POINTS_X - 1))
|
#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / float(GRID_MAX_POINTS_X - 1))
|
||||||
#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / float(GRID_MAX_POINTS_Y - 1))
|
#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / float(GRID_MAX_POINTS_Y - 1))
|
||||||
|
|
||||||
|
#if ENABLED(OPTIMIZED_MESH_STORAGE)
|
||||||
|
typedef int16_t mesh_store_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
|
||||||
|
#endif
|
||||||
|
|
||||||
class unified_bed_leveling {
|
class unified_bed_leveling {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -106,6 +110,10 @@ class unified_bed_leveling {
|
|||||||
static int8_t storage_slot;
|
static int8_t storage_slot;
|
||||||
|
|
||||||
static bed_mesh_t z_values;
|
static bed_mesh_t z_values;
|
||||||
|
#if ENABLED(OPTIMIZED_MESH_STORAGE)
|
||||||
|
static void set_store_from_mesh(const bed_mesh_t &in_values, mesh_store_t &stored_values);
|
||||||
|
static void set_mesh_from_store(const mesh_store_t &stored_values, bed_mesh_t &out_values);
|
||||||
|
#endif
|
||||||
static const float _mesh_index_to_xpos[GRID_MAX_POINTS_X],
|
static const float _mesh_index_to_xpos[GRID_MAX_POINTS_X],
|
||||||
_mesh_index_to_ypos[GRID_MAX_POINTS_Y];
|
_mesh_index_to_ypos[GRID_MAX_POINTS_Y];
|
||||||
|
|
||||||
@ -182,6 +190,12 @@ class unified_bed_leveling {
|
|||||||
return z1 + (z2 - z1) * (a0 - a1) / (a2 - a1);
|
return z1 + (z2 - z1) * (a0 - a1) / (a2 - a1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef UBL_Z_RAISE_WHEN_OFF_MESH
|
||||||
|
#define _UBL_OUTER_Z_RAISE UBL_Z_RAISE_WHEN_OFF_MESH
|
||||||
|
#else
|
||||||
|
#define _UBL_OUTER_Z_RAISE NAN
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* z_correction_for_x_on_horizontal_mesh_line is an optimization for
|
* z_correction_for_x_on_horizontal_mesh_line is an optimization for
|
||||||
* the case where the printer is making a vertical line that only crosses horizontal mesh lines.
|
* the case where the printer is making a vertical line that only crosses horizontal mesh lines.
|
||||||
@ -195,13 +209,7 @@ class unified_bed_leveling {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The requested location is off the mesh. Return UBL_Z_RAISE_WHEN_OFF_MESH or NAN.
|
// The requested location is off the mesh. Return UBL_Z_RAISE_WHEN_OFF_MESH or NAN.
|
||||||
return (
|
return _UBL_OUTER_Z_RAISE;
|
||||||
#ifdef UBL_Z_RAISE_WHEN_OFF_MESH
|
|
||||||
UBL_Z_RAISE_WHEN_OFF_MESH
|
|
||||||
#else
|
|
||||||
NAN
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float xratio = (rx0 - mesh_index_to_xpos(x1_i)) * RECIPROCAL(MESH_X_DIST),
|
const float xratio = (rx0 - mesh_index_to_xpos(x1_i)) * RECIPROCAL(MESH_X_DIST),
|
||||||
@ -224,13 +232,7 @@ class unified_bed_leveling {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The requested location is off the mesh. Return UBL_Z_RAISE_WHEN_OFF_MESH or NAN.
|
// The requested location is off the mesh. Return UBL_Z_RAISE_WHEN_OFF_MESH or NAN.
|
||||||
return (
|
return _UBL_OUTER_Z_RAISE;
|
||||||
#ifdef UBL_Z_RAISE_WHEN_OFF_MESH
|
|
||||||
UBL_Z_RAISE_WHEN_OFF_MESH
|
|
||||||
#else
|
|
||||||
NAN
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float yratio = (ry0 - mesh_index_to_ypos(y1_i)) * RECIPROCAL(MESH_Y_DIST),
|
const float yratio = (ry0 - mesh_index_to_ypos(y1_i)) * RECIPROCAL(MESH_Y_DIST),
|
||||||
|
@ -543,7 +543,7 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const float cvf = parser.value_float();
|
const float cvf = parser.value_float();
|
||||||
switch ((int)truncf(cvf * 10.0f) - 30) { // 3.1 -> 1
|
switch ((int)TRUNC(cvf * 10.0f) - 30) { // 3.1 -> 1
|
||||||
#if ENABLED(UBL_G29_P31)
|
#if ENABLED(UBL_G29_P31)
|
||||||
case 1: {
|
case 1: {
|
||||||
|
|
||||||
|
@ -2385,12 +2385,14 @@ void MarlinSettings::postprocess() {
|
|||||||
// or down a little bit without disrupting the mesh data
|
// or down a little bit without disrupting the mesh data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MESH_STORE_SIZE sizeof(TERN(OPTIMIZED_MESH_STORAGE, mesh_store_t, ubl.z_values))
|
||||||
|
|
||||||
uint16_t MarlinSettings::calc_num_meshes() {
|
uint16_t MarlinSettings::calc_num_meshes() {
|
||||||
return (meshes_end - meshes_start_index()) / sizeof(ubl.z_values);
|
return (meshes_end - meshes_start_index()) / MESH_STORE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MarlinSettings::mesh_slot_offset(const int8_t slot) {
|
int MarlinSettings::mesh_slot_offset(const int8_t slot) {
|
||||||
return meshes_end - (slot + 1) * sizeof(ubl.z_values);
|
return meshes_end - (slot + 1) * MESH_STORE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarlinSettings::store_mesh(const int8_t slot) {
|
void MarlinSettings::store_mesh(const int8_t slot) {
|
||||||
@ -2407,9 +2409,17 @@ void MarlinSettings::postprocess() {
|
|||||||
int pos = mesh_slot_offset(slot);
|
int pos = mesh_slot_offset(slot);
|
||||||
uint16_t crc = 0;
|
uint16_t crc = 0;
|
||||||
|
|
||||||
|
#if ENABLED(OPTIMIZED_MESH_STORAGE)
|
||||||
|
int16_t z_mesh_store[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
|
||||||
|
ubl.set_store_from_mesh(ubl.z_values, z_mesh_store);
|
||||||
|
uint8_t * const src = (uint8_t*)&z_mesh_store;
|
||||||
|
#else
|
||||||
|
uint8_t * const src = (uint8_t*)&ubl.z_values;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Write crc to MAT along with other data, or just tack on to the beginning or end
|
// Write crc to MAT along with other data, or just tack on to the beginning or end
|
||||||
persistentStore.access_start();
|
persistentStore.access_start();
|
||||||
const bool status = persistentStore.write_data(pos, (uint8_t *)&ubl.z_values, sizeof(ubl.z_values), &crc);
|
const bool status = persistentStore.write_data(pos, src, MESH_STORE_SIZE, &crc);
|
||||||
persistentStore.access_finish();
|
persistentStore.access_finish();
|
||||||
|
|
||||||
if (status) SERIAL_ECHOLNPGM("?Unable to save mesh data.");
|
if (status) SERIAL_ECHOLNPGM("?Unable to save mesh data.");
|
||||||
@ -2435,12 +2445,27 @@ void MarlinSettings::postprocess() {
|
|||||||
|
|
||||||
int pos = mesh_slot_offset(slot);
|
int pos = mesh_slot_offset(slot);
|
||||||
uint16_t crc = 0;
|
uint16_t crc = 0;
|
||||||
|
#if ENABLED(OPTIMIZED_MESH_STORAGE)
|
||||||
|
int16_t z_mesh_store[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
|
||||||
|
uint8_t * const dest = (uint8_t*)&z_mesh_store;
|
||||||
|
#else
|
||||||
uint8_t * const dest = into ? (uint8_t*)into : (uint8_t*)&ubl.z_values;
|
uint8_t * const dest = into ? (uint8_t*)into : (uint8_t*)&ubl.z_values;
|
||||||
|
#endif
|
||||||
|
|
||||||
persistentStore.access_start();
|
persistentStore.access_start();
|
||||||
const uint16_t status = persistentStore.read_data(pos, dest, sizeof(ubl.z_values), &crc);
|
const uint16_t status = persistentStore.read_data(pos, dest, MESH_STORE_SIZE, &crc);
|
||||||
persistentStore.access_finish();
|
persistentStore.access_finish();
|
||||||
|
|
||||||
|
#if ENABLED(OPTIMIZED_MESH_STORAGE)
|
||||||
|
if (into) {
|
||||||
|
float z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
|
||||||
|
ubl.set_mesh_from_store(z_mesh_store, z_values);
|
||||||
|
memcpy(into, z_values, sizeof(z_values));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ubl.set_mesh_from_store(z_mesh_store, ubl.z_values);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (status) SERIAL_ECHOLNPGM("?Unable to load mesh data.");
|
if (status) SERIAL_ECHOLNPGM("?Unable to load mesh data.");
|
||||||
else DEBUG_ECHOLNPAIR("Mesh loaded from slot ", slot);
|
else DEBUG_ECHOLNPAIR("Mesh loaded from slot ", slot);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user