🔧 Allow SMOOTH_LIN_ADVANCE + NONLINEAR_EXTRUSION (#27861)

This commit is contained in:
Vovodroid 2025-05-20 22:52:51 +03:00 committed by GitHub
parent af553d5fbd
commit d5723fcafd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 74 additions and 48 deletions

View file

@ -44,9 +44,9 @@
extern uint32_t GetStepperTimerClkFreq();
// Timer prescaler calculations
#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / STEPPER_TIMER_RATE) // Prescaler = 30
#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / STEPPER_TIMER_RATE) // Prescaler = 30
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Stepper timer ticks per µs
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Stepper timer ticks per µs
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
@ -57,7 +57,7 @@ extern uint32_t GetStepperTimerClkFreq();
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP)
#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP)
#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP)
#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP)
#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP)
extern void Step_Handler();

View file

@ -49,6 +49,12 @@ void GcodeSuite::M592() {
if (parser.seenval('A')) stepper.ne.A = parser.value_float();
if (parser.seenval('B')) stepper.ne.B = parser.value_float();
if (parser.seenval('C')) stepper.ne.C = parser.value_float();
#if ENABLED(SMOOTH_LIN_ADVANCE)
stepper.ne_q30.A = _BV32(30) * (stepper.ne.A * planner.mm_per_step[E_AXIS_N(0)] * planner.mm_per_step[E_AXIS_N(0)]);
stepper.ne_q30.B = _BV32(30) * (stepper.ne.B * planner.mm_per_step[E_AXIS_N(0)]);
stepper.ne_q30.C = _BV32(30) * stepper.ne.C;
#endif
}
#endif // NONLINEAR_EXTRUSION

View file

@ -868,8 +868,6 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L
#error "SMOOTH_LIN_ADVANCE requires a 32-bit CPU."
#elif ENABLED(S_CURVE_ACCELERATION)
#error "SMOOTH_LIN_ADVANCE is not compatible with S_CURVE_ACCELERATION."
#elif ENABLED(NONLINEAR_EXTRUSION)
#error "SMOOTH_LIN_ADVANCE doesn't currently support NONLINEAR_EXTRUSION."
#elif ENABLED(INPUT_SHAPING_E_SYNC) && NONE(INPUT_SHAPING_X, INPUT_SHAPING_Y)
#error "INPUT_SHAPING_E_SYNC requires INPUT_SHAPING_X or INPUT_SHAPING_Y."
#endif

View file

@ -3252,6 +3252,10 @@ void Planner::refresh_acceleration_rates() {
void Planner::refresh_positioning() {
#if ENABLED(EDITABLE_STEPS_PER_UNIT)
LOOP_DISTINCT_AXES(i) mm_per_step[i] = 1.0f / settings.axis_steps_per_mm[i];
#if ALL(NONLINEAR_EXTRUSION, SMOOTH_LIN_ADVANCE)
stepper.ne_q30.A = _BV32(30) * (stepper.ne.A * mm_per_step[E_AXIS_N(0)] * mm_per_step[E_AXIS_N(0)]);
stepper.ne_q30.B = _BV32(30) * (stepper.ne.B * mm_per_step[E_AXIS_N(0)]);
#endif
#endif
set_position_mm(current_position);
refresh_acceleration_rates();

View file

@ -531,9 +531,7 @@ class Planner {
static void set_advance_k(const_float_t k, const uint8_t e=active_extruder) {
UNUSED(e);
extruder_advance_K[E_INDEX_N(e)] = k;
#if ENABLED(SMOOTH_LIN_ADVANCE)
extruder_advance_K_q27[E_INDEX_N(e)] = k * (1UL << 27);
#endif
TERN_(SMOOTH_LIN_ADVANCE, extruder_advance_K_q27[E_INDEX_N(e)] = k * _BV32(27));
}
static float get_advance_k(const uint8_t e=active_extruder) {
UNUSED(e);

View file

@ -257,9 +257,16 @@ uint32_t Stepper::advance_divisor = 0,
#if ENABLED(NONLINEAR_EXTRUSION)
ne_coeff_t Stepper::ne;
ne_fix_t Stepper::ne_fix;
int32_t Stepper::ne_edividend;
uint32_t Stepper::ne_scale;
#if NONLINEAR_EXTRUSION_Q24
ne_q24_t Stepper::ne_q24;
#else
ne_q30_t Stepper::ne_q30;
#endif
// private:
#if NONLINEAR_EXTRUSION_Q24
int32_t Stepper::ne_edividend;
uint32_t Stepper::ne_scale_q24;
#endif
#endif
#if HAS_ZV_SHAPING
@ -2241,13 +2248,13 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) {
#endif // !CPU_32_BIT
}
#if ENABLED(NONLINEAR_EXTRUSION)
void Stepper::calc_nonlinear_e(uint32_t step_rate) {
const uint32_t velocity = ne_scale * step_rate; // Scale step_rate first so all intermediate values stay in range of 8.24 fixed point math
int32_t vd = (((((int64_t)ne_fix.A * velocity) >> 24) * velocity) >> 24) + (((int64_t)ne_fix.B * velocity) >> 24);
NOLESS(vd, 0);
#if NONLINEAR_EXTRUSION_Q24
void Stepper::calc_nonlinear_e(const uint32_t step_rate) {
const uint32_t velocity_q24 = ne_scale_q24 * step_rate; // Scale step_rate first so all intermediate values stay in range of 8.24 fixed point math
int32_t vd_q24 = (((((int64_t)ne_q24.A * velocity_q24) >> 24) * velocity_q24) >> 24) + (((int64_t)ne_q24.B * velocity_q24) >> 24);
NOLESS(vd_q24, 0);
advance_dividend.e = (uint64_t(ne_fix.C + vd) * ne_edividend) >> 24;
advance_dividend.e = (uint64_t(ne_q24.C + vd_q24) * ne_edividend) >> 24;
}
#endif
@ -2463,9 +2470,7 @@ hal_timer_t Stepper::block_phase_isr() {
acceleration_time += interval;
deceleration_time = 0; // Reset since we're doing acceleration first.
#if ENABLED(NONLINEAR_EXTRUSION)
calc_nonlinear_e(acc_step_rate << oversampling_factor);
#endif
calc_nonlinear_e(acc_step_rate << oversampling_factor);
#if HAS_ROUGH_LIN_ADVANCE
if (la_active) {
@ -2529,9 +2534,7 @@ hal_timer_t Stepper::block_phase_isr() {
interval = calc_multistep_timer_interval(step_rate << oversampling_factor);
deceleration_time += interval;
#if ENABLED(NONLINEAR_EXTRUSION)
calc_nonlinear_e(step_rate << oversampling_factor);
#endif
calc_nonlinear_e(step_rate << oversampling_factor);
#if HAS_ROUGH_LIN_ADVANCE
if (la_active) {
@ -2584,9 +2587,7 @@ hal_timer_t Stepper::block_phase_isr() {
TERN_(SMOOTH_LIN_ADVANCE, curr_step_rate = current_block->nominal_rate;)
deceleration_time = ticks_nominal / 2;
#if ENABLED(NONLINEAR_EXTRUSION)
calc_nonlinear_e(current_block->nominal_rate << oversampling_factor);
#endif
calc_nonlinear_e(current_block->nominal_rate << oversampling_factor);
#if HAS_ROUGH_LIN_ADVANCE
if (la_active)
@ -2836,18 +2837,18 @@ hal_timer_t Stepper::block_phase_isr() {
acc_step_rate = current_block->initial_rate;
#endif
#if ENABLED(NONLINEAR_EXTRUSION)
#if NONLINEAR_EXTRUSION_Q24
ne_edividend = advance_dividend.e;
const float scale = (float(ne_edividend) / advance_divisor) * planner.mm_per_step[E_AXIS_N(current_block->extruder)];
ne_scale = (1L << 24) * scale;
ne_scale_q24 = _BV32(24) * scale;
if (current_block->direction_bits.e && ANY_AXIS_MOVES(current_block)) {
ne_fix.A = (1L << 24) * ne.A;
ne_fix.B = (1L << 24) * ne.B;
ne_fix.C = (1L << 24) * ne.C;
ne_q24.A = _BV32(24) * ne.A;
ne_q24.B = _BV32(24) * ne.B;
ne_q24.C = _BV32(24) * ne.C;
}
else {
ne_fix.A = ne_fix.B = 0;
ne_fix.C = (1L << 24);
ne_q24.A = ne_q24.B = 0;
ne_q24.C = _BV32(24);
}
#endif
@ -2856,9 +2857,7 @@ hal_timer_t Stepper::block_phase_isr() {
// Initialize ac/deceleration time as if half the time passed.
acceleration_time = deceleration_time = interval / 2;
#if ENABLED(NONLINEAR_EXTRUSION)
calc_nonlinear_e(current_block->initial_rate << oversampling_factor);
#endif
calc_nonlinear_e(current_block->initial_rate << oversampling_factor);
#if ENABLED(LIN_ADVANCE)
#if ENABLED(SMOOTH_LIN_ADVANCE)
@ -2885,13 +2884,23 @@ hal_timer_t Stepper::block_phase_isr() {
uint32_t Stepper::extruder_advance_tau_ticks[DISTINCT_E],
Stepper::extruder_advance_alpha_q30[DISTINCT_E];
void Stepper::set_la_interval(const int32_t rate) {
if (rate == 0) {
void Stepper::set_la_interval(int32_t step_rate) {
if (step_rate == 0) {
la_interval = LA_ADV_NEVER;
}
else {
const bool forward_e = rate > 0;
la_interval = calc_timer_interval(uint32_t(ABS(rate)));
const bool forward_e = step_rate > 0;
#if ENABLED(NONLINEAR_EXTRUSION)
if (forward_e && ANY_AXIS_MOVES(current_block)) {
// Maximum polynomial value is just above 1, like 1.05..1.2, less than 2 anyway, so we can use 30 bits for fractional part
int32_t vd_q30 = ne_q30.A*step_rate*step_rate + ne_q30.B*step_rate;
NOLESS(vd_q30, 0);
step_rate = (int64_t(step_rate) * (ne_q30.C + vd_q30)) >> 30;
}
#endif
la_interval = calc_timer_interval(uint32_t(ABS(step_rate)));
if (forward_e != motor_direction(E_AXIS)) {
last_direction_bits.toggle(E_AXIS);
count_direction.e = -count_direction.e;

View file

@ -285,7 +285,12 @@ constexpr ena_mask_t enable_overlap[] = {
#if ENABLED(NONLINEAR_EXTRUSION)
typedef struct { float A, B, C; void reset() { A = B = 0.0f; C = 1.0f; } } ne_coeff_t;
typedef struct { int32_t A, B, C; } ne_fix_t;
#if DISABLED(SMOOTH_LIN_ADVANCE)
#define NONLINEAR_EXTRUSION_Q24 1
typedef struct { int32_t A, B, C; } ne_q24_t;
#else
typedef struct { int32_t A, B, C; } ne_q30_t;
#endif
#endif
//
@ -343,6 +348,11 @@ class Stepper {
#if ENABLED(NONLINEAR_EXTRUSION)
static ne_coeff_t ne;
#if NONLINEAR_EXTRUSION_Q24
static ne_q24_t ne_q24;
#else
static ne_q30_t ne_q30;
#endif
#endif
#if ENABLED(ADAPTIVE_STEP_SMOOTHING_TOGGLE)
@ -467,10 +477,9 @@ class Stepper {
#endif
#endif
#if ENABLED(NONLINEAR_EXTRUSION)
#if NONLINEAR_EXTRUSION_Q24
static int32_t ne_edividend;
static uint32_t ne_scale;
static ne_fix_t ne_fix;
static uint32_t ne_scale_q24;
#endif
#if ENABLED(BABYSTEPPING)
@ -531,7 +540,7 @@ class Stepper {
// The Linear advance ISR phase
static void advance_isr();
#if ENABLED(SMOOTH_LIN_ADVANCE)
static void set_la_interval(const int32_t rate);
static void set_la_interval(int32_t step_rate);
static hal_timer_t smooth_lin_adv_isr();
#endif
#endif
@ -738,8 +747,10 @@ class Stepper {
// Evaluate axis motions and set bits in axis_did_move
static void set_axis_moved_for_current_block();
#if ENABLED(NONLINEAR_EXTRUSION)
static void calc_nonlinear_e(uint32_t step_rate);
#if NONLINEAR_EXTRUSION_Q24
static void calc_nonlinear_e(const uint32_t step_rate);
#else
static void calc_nonlinear_e(const uint32_t) {}
#endif
#if ENABLED(S_CURVE_ACCELERATION)

View file

@ -14,7 +14,7 @@
<a href="https://fosstodon.org/@marlinfirmware"><img alt="Siga MarlinFirmware no Mastodon" src="https://img.shields.io/mastodon/follow/109450200866020466?domain=https%3A%2F%2Ffosstodon.org&logoColor=%2300B&style=social"></a>
</p>
Documentação adicional pode ser encontrada na [Página Inicial do Marlin](//marlinfw.org/).
Documentação adicional pode ser encontrada na [Página Inicial do Marlin](//marlinfw.org/).
Por favor, teste este firmware e nos avise se encontrar algum problema. Voluntários estão prontos para ajudar!
## Branch de Correções do Marlin 2.1