From 584280033e1d1c0f59c149e436f9f8a8c0e67e2f Mon Sep 17 00:00:00 2001 From: hanyongwei <2043702190@qq.com> Date: Thu, 20 Aug 2026 12:24:28 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=AF=B9os=E8=8A=82=E6=8B=8D?= =?UTF-8?q?=E7=9A=84=E4=BE=9D=E8=B5=96=EF=BC=8C=E7=BA=AF=E8=84=89=E5=86=B2?= =?UTF-8?q?=E8=AE=A1=E6=95=B0=E6=94=B9=E9=A2=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plsr/accel_curve/plsr_accel_curve.c | 240 ++++++++++++++++++++++++++ plsr/accel_curve/plsr_accel_curve.h | 36 +++- plsr/plsr.c | 2 +- plsr/pulse_driver/plsr_pulse_driver.c | 62 +++++++ plsr/pulse_driver/plsr_pulse_driver.h | 6 + plsr/run_control/plsr_run_control.c | 170 ++++++++++-------- plsr/run_control/plsr_run_control.h | 4 +- 7 files changed, 442 insertions(+), 78 deletions(-) diff --git a/plsr/accel_curve/plsr_accel_curve.c b/plsr/accel_curve/plsr_accel_curve.c index 10cad28..64ee353 100644 --- a/plsr/accel_curve/plsr_accel_curve.c +++ b/plsr/accel_curve/plsr_accel_curve.c @@ -1119,3 +1119,243 @@ uint32_t PlsrAccelCurveFreqAtSegTime(const PlsrAccelPlan_t *plan, approx_n = (uint32_t)(((uint64_t)seg_elapsed_ms * (uint64_t)f_ref) / 1000ULL); return PlsrAccelCurveFreqAtPulse(plan, approx_n); } + +static void PlsrAccelPulseRtSetupShape(PlsrAccelPulseRt_t *rt, uint32_t n_total) +{ + if (n_total < 1U) + { + rt->step_q24 = 0U; + rt->step_rem = 0U; + return; + } + /* (1<<24)/N 商余:逐拍累加,避免每拍 index/total 除法 */ + rt->step_q24 = 16777216UL / n_total; + rt->step_rem = 16777216UL % n_total; + rt->phase_q24 = 0U; + rt->rem_acc = 0U; +} + +void PlsrAccelPulseRtBeginAcc(PlsrAccelPulseRt_t *rt, + const PlsrAccelPlan_t *plan) +{ + if ((rt == (PlsrAccelPulseRt_t *)0) || (plan == (const PlsrAccelPlan_t *)0)) + { + return; + } + rt->f0 = plan->f_cur; + rt->f1 = plan->f_tgt; + rt->f = plan->f_cur; + rt->a = plan->a_acc; + rt->n = 0U; + rt->n_total = plan->acc_n; + rt->rising = (plan->f_tgt >= plan->f_cur) ? 1U : 0U; + rt->mode = plan->mode; + rt->active = (plan->acc_n > 0U) && (plan->f_cur != plan->f_tgt) ? 1U : 0U; + PlsrAccelPulseRtSetupShape(rt, rt->n_total); +} + +void PlsrAccelPulseRtBeginDec(PlsrAccelPulseRt_t *rt, + const PlsrAccelPlan_t *plan) +{ + if ((rt == (PlsrAccelPulseRt_t *)0) || (plan == (const PlsrAccelPlan_t *)0)) + { + return; + } + rt->f0 = plan->f_tgt; + rt->f1 = plan->f_end; + rt->f = plan->f_tgt; + rt->a = plan->a_dec; + rt->n = 0U; + rt->n_total = plan->dec_n; + rt->rising = (plan->f_end >= plan->f_tgt) ? 1U : 0U; + rt->mode = plan->mode; + rt->active = (plan->dec_n > 0U) && (plan->f_tgt != plan->f_end) ? 1U : 0U; + PlsrAccelPulseRtSetupShape(rt, rt->n_total); +} + +void PlsrAccelPulseRtBeginConst(PlsrAccelPulseRt_t *rt, + const PlsrAccelPlan_t *plan) +{ + if ((rt == (PlsrAccelPulseRt_t *)0) || (plan == (const PlsrAccelPlan_t *)0)) + { + return; + } + rt->f0 = plan->f_tgt; + rt->f1 = plan->f_tgt; + rt->f = plan->f_tgt; + rt->a = 0U; + rt->n = 0U; + rt->n_total = plan->const_n; + rt->rising = 1U; + rt->mode = plan->mode; + rt->active = 0U; /* 匀速:确认频率没变 → 复用 → 结束 */ + rt->step_q24 = 0U; + rt->step_rem = 0U; + rt->phase_q24 = 0U; + rt->rem_acc = 0U; +} + +/** + * 直线:用上一拍 f ±1 逼近 target_sq,不全量开方。 + * 低频 df/dn 大时循环次数多,但周期也长,ISR 仍可承受。 + */ +static uint32_t PlsrAccelPulseRtSquareStep(PlsrAccelPulseRt_t *rt) +{ + uint64_t target_sq; + uint64_t f_sq; + uint64_t f0_sq; + uint32_t f; + uint32_t guard; + + f0_sq = (uint64_t)rt->f0 * (uint64_t)rt->f0; + if (rt->rising != 0U) + { + target_sq = f0_sq + (2ULL * (uint64_t)rt->a * (uint64_t)rt->n); + } + else + { + uint64_t drop = 2ULL * (uint64_t)rt->a * (uint64_t)rt->n; + target_sq = (drop >= f0_sq) ? 0ULL : (f0_sq - drop); + } + + f = rt->f; + if (f < 1U) + { + f = 1U; + } + + for (guard = 0U; guard < 2048U; guard++) + { + f_sq = (uint64_t)f * (uint64_t)f; + if (rt->rising != 0U) + { + if ((f < rt->f1) && (((uint64_t)(f + 1U) * (uint64_t)(f + 1U)) <= target_sq)) + { + f++; + continue; + } + if ((f > 1U) && (f_sq > target_sq)) + { + f--; + continue; + } + break; + } + else + { + if ((f > rt->f1) && (f_sq > target_sq)) + { + f--; + continue; + } + if ((f < 100000U) && + (((uint64_t)(f + 1U) * (uint64_t)(f + 1U)) < target_sq)) + { + f++; + continue; + } + break; + } + } + + if (rt->rising != 0U) + { + if (f > rt->f1) + { + f = rt->f1; + } + } + else + { + if (f < rt->f1) + { + f = rt->f1; + } + } + if (f < 1U) + { + f = 1U; + } + return PlsrAccelCurveClampFreq(f); +} + +static uint32_t PlsrAccelPulseRtShapeStep(PlsrAccelPulseRt_t *rt) +{ + uint32_t ratio; + uint32_t f; + + if (rt->n_total < 1U) + { + return PlsrAccelCurveClampFreq(rt->f1); + } + + if (rt->n >= rt->n_total) + { + return PlsrAccelCurveClampFreq(rt->f1); + } + + rt->phase_q24 += rt->step_q24; + rt->rem_acc += rt->step_rem; + if (rt->rem_acc >= rt->n_total) + { + rt->rem_acc -= rt->n_total; + rt->phase_q24 += 1U; + } + if (rt->phase_q24 > 16777216UL) + { + rt->phase_q24 = 16777216UL; + } + + ratio = (uint32_t)(((uint64_t)rt->phase_q24 * 1000ULL) / 16777216ULL); + if (ratio > 1000U) + { + ratio = 1000U; + } + ratio = PlsrAccelCurveShapePermille(ratio, rt->mode); + f = PlsrAccelCurveLerp(rt->f0, rt->f1, ratio); + if (f < 1U) + { + f = 1U; + } + return PlsrAccelCurveClampFreq(f); +} + +uint32_t PlsrAccelPulseRtStep(PlsrAccelPulseRt_t *rt) +{ + if (rt == (PlsrAccelPulseRt_t *)0) + { + return 0U; + } + if (rt->active == 0U) + { + return PlsrAccelCurveClampFreq(rt->f); + } + + if (rt->n < 0xFFFFFFFFUL) + { + rt->n++; + } + + if (rt->mode == PLSR_ACCEL_LINEAR) + { + if (rt->a == 0U) + { + rt->f = rt->f1; + } + else + { + rt->f = PlsrAccelPulseRtSquareStep(rt); + } + } + else + { + rt->f = PlsrAccelPulseRtShapeStep(rt); + } + + if ((rt->n_total > 0U) && (rt->n >= rt->n_total)) + { + rt->f = rt->f1; + rt->active = 0U; + } + return rt->f; +} diff --git a/plsr/accel_curve/plsr_accel_curve.h b/plsr/accel_curve/plsr_accel_curve.h index 7b1d52d..bbfc4fd 100644 --- a/plsr/accel_curve/plsr_accel_curve.h +++ b/plsr/accel_curve/plsr_accel_curve.h @@ -107,14 +107,44 @@ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan, PlsrAccelMode_e mode); /** - * 按已完成脉冲数取频(任务上下文调用,勿进脉冲 ISR)。 - * pulse_done = 本段已发完的脉冲数(与 s_done 一致)。 + * 按已完成脉冲数取频(任务/预览可用)。 + * 运行热路径请用 PlsrAccelPulseRt(逐拍 ±1 / Q24,可进 ISR)。 */ uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan, uint32_t pulse_done); -/** @deprecated 时间轴取频;保留给旧预览,运行请用 FreqAtPulse */ +/** @deprecated 时间轴取频;保留给旧预览,运行请用脉冲域 */ uint32_t PlsrAccelCurveFreqAtSegTime(const PlsrAccelPlan_t *plan, uint32_t seg_elapsed_ms); +/** + * 逐拍运行态(ISR 热路径): + * - 直线:上一拍频率 ±1 逼近 sqrt(f0^2±2an),不全量 Isqrt64 + * - S/正弦:Begin 时算 Q24 步长,逐拍商余累加,不做 index/total 除法 + */ +typedef struct { + uint32_t f; /* 当前命令频率 */ + uint32_t f0; /* 本相起点频率 */ + uint32_t f1; /* 本相终点频率 */ + uint32_t a; /* Hz/s;直线用 */ + uint32_t n; /* 本相已完成脉冲 */ + uint32_t n_total; /* 本相总脉冲(距离只在 Begin 算) */ + uint32_t phase_q24; /* S/正弦进度 0..(1<<24) */ + uint32_t step_q24; + uint32_t step_rem; /* (1<<24) % n_total */ + uint32_t rem_acc; + uint8_t rising; + uint8_t active; /* 0=匀速保持,不 Step */ + PlsrAccelMode_e mode; +} PlsrAccelPulseRt_t; + +void PlsrAccelPulseRtBeginAcc(PlsrAccelPulseRt_t *rt, + const PlsrAccelPlan_t *plan); +void PlsrAccelPulseRtBeginDec(PlsrAccelPulseRt_t *rt, + const PlsrAccelPlan_t *plan); +void PlsrAccelPulseRtBeginConst(PlsrAccelPulseRt_t *rt, + const PlsrAccelPlan_t *plan); +/** 本相前进 1 脉冲,返回下一拍命令频率(匀速直接返回缓存 f) */ +uint32_t PlsrAccelPulseRtStep(PlsrAccelPulseRt_t *rt); + #endif diff --git a/plsr/plsr.c b/plsr/plsr.c index e28ffb3..8ba5502 100644 --- a/plsr/plsr.c +++ b/plsr/plsr.c @@ -88,7 +88,7 @@ void PlsrTask(void *pArg) PlsrCommandPoll(); /* 收 START/STOP 等,回写忙闲状态 */ PlsrPersistPoll(); /* 公共参数有改且空闲则追加写入 Flash */ - PlsrRunControlTickMs(); /* 方向延时、段间等待到期处理 */ + PlsrRunControlTickMs(); /* ACT/WAIT/EXT;改频在脉冲 ISR */ #if (PLSR_LOOP_TEST_EN != 0) /* 调试:空闲满 1s 自动从第 1 段再启 */ diff --git a/plsr/pulse_driver/plsr_pulse_driver.c b/plsr/pulse_driver/plsr_pulse_driver.c index cbc368b..c15c5e9 100644 --- a/plsr/pulse_driver/plsr_pulse_driver.c +++ b/plsr/pulse_driver/plsr_pulse_driver.c @@ -550,6 +550,68 @@ void PlsrPulseDriverSetFreq(uint32_t freq_hz) s_last_arr = arr; } +void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) +{ + uint32_t psc; + uint32_t arr; + uint32_t ccr; + uint32_t clk_hz; + TIM_HandleTypeDef *htim; + + /* 匀速热路径:频率未变 → 不算量化、不写寄存器 */ + if (freq_hz == s_last_freq) + { + return; + } + + if (freq_hz == 0U) + { + s_req_freq = 0U; + s_req_pending = 1U; + return; + } + + htim = s_active_htim; + if (htim == (TIM_HandleTypeDef *)0) + { + s_req_freq = freq_hz; + s_req_pending = 1U; + return; + } + + clk_hz = PlsrPulseDriverTimClkHz(htim); + + if (s_psc_locked != 0U) + { + psc = s_locked_psc; + PlsrPulseDriverCalcArrWithPsc(clk_hz, freq_hz, psc, &arr, &ccr); + } + else + { + PlsrPulseDriverCalcPscArr(clk_hz, freq_hz, &psc, &arr, &ccr); + if (psc != s_last_psc) + { + /* ISR 内禁止停表换 PSC,留给任务 */ + s_req_freq = freq_hz; + s_req_pending = 1U; + return; + } + } + + if ((psc == s_last_psc) && (arr == s_last_arr)) + { + s_last_freq = freq_hz; + return; + } + + __HAL_TIM_SET_AUTORELOAD(htim, arr); + __HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr); + + s_last_freq = freq_hz; + s_last_psc = psc; + s_last_arr = arr; +} + void PlsrPulseDriverRequestFreq(uint32_t freq_hz) { s_req_freq = freq_hz; diff --git a/plsr/pulse_driver/plsr_pulse_driver.h b/plsr/pulse_driver/plsr_pulse_driver.h index d18964b..875821a 100644 --- a/plsr/pulse_driver/plsr_pulse_driver.h +++ b/plsr/pulse_driver/plsr_pulse_driver.h @@ -33,6 +33,12 @@ void PlsrPulseDriverUnlockPsc(void); void PlsrPulseDriverStart(uint32_t freq_hz); void PlsrPulseDriverStartFreeRun(uint32_t freq_hz); void PlsrPulseDriverSetFreq(uint32_t freq_hz); +/** + * 脉冲 ISR 改频:仅写 ARR/CCR(预装载,下一拍生效)。 + * PSC 不变时直接改;若必须换 PSC 则挂起,由任务 ApplyPending。 + * 频率未变或 ARR 未变则立即返回(匀速热路径)。 + */ +void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz); /** 请求改频(ISR 周期边界再落到硬件) */ void PlsrPulseDriverRequestFreq(uint32_t freq_hz); /** 在更新中断里调用:应用挂起频率 */ diff --git a/plsr/run_control/plsr_run_control.c b/plsr/run_control/plsr_run_control.c index cdcae30..af8660a 100644 --- a/plsr/run_control/plsr_run_control.c +++ b/plsr/run_control/plsr_run_control.c @@ -12,10 +12,11 @@ * 3) 发送模式只影响本段 f_end(完成=止速;后续且不停表=下一段目标) * 4) PlanSeg / ChangeFreq 共用规划入口,便于后期动态改频 * - * 【运行节拍】脉冲 UPDATE:计 s_done;加/减速置 dirty,匀速不周期性改频。 - * 任务 TickMs:dirty 时 FreqAtPulse 改频。 - * TIM3 1ms:仅 ACT/WAIT 时基(不改频)。 - * 匀速“保持”≠禁止改频:ACT/EXT 打断、ChangeFreq、进减速、开下一段仍可 Start/SetFreq。 + * 【运行节拍】纯脉冲计数: + * UPDATE ISR:s_done++;加/减速逐拍 PlsrAccelPulseRtStep + SetFreqIsr; + * 匀速复用 ARR(不改频);remain<=dec_n 进减速。 + * 任务 TickMs:仅 ACT/WAIT/EXT/换向延时 + ApplyPending(极少换 PSC)。 + * TIM3 1ms:仅 ACT/WAIT 时基。 */ #include "plsr_run_control.h" #include "plsr_path_plan.h" @@ -61,11 +62,11 @@ static volatile uint8_t s_wait_expire_req; /* WAIT 时间到:ISR 只置位 */ static uint8_t s_wait_is_signal; /* RC_WAIT_COND:1=等 WAIT 沿,0=等时间 */ static PlsrAccelPlan_t s_accel_plan; +static PlsrAccelPulseRt_t s_pulse_rt; static volatile RunPhase_e s_phase; /* ISR 读相,须 volatile */ static uint32_t s_approach_from; static uint32_t s_decel_from; static uint8_t s_follow_cont; -static volatile uint8_t s_profile_dirty; /* 脉冲推进后由任务改频 */ static uint32_t s_chain_freq; static uint8_t s_chain_valid; @@ -630,6 +631,17 @@ static void PlsrRunControlApplyOutFreq(uint32_t profile_freq, uint8_t do_start) s_cur_freq = profile_freq; } +/** 脉冲 ISR:只走 ARR 预装载路径 */ +static void PlsrRunControlApplyOutFreqIsr(uint32_t profile_freq) +{ + if (profile_freq < 1U) + { + profile_freq = 1U; + } + PlsrPulseDriverSetFreqIsr(profile_freq); + s_cur_freq = profile_freq; +} + static void PlsrRunControlEnterPhase(RunPhase_e ph, uint32_t anchor_freq) { s_phase = ph; @@ -671,7 +683,8 @@ static void PlsrRunControlEnterDecel(uint32_t from_hz, uint32_t remain_pulses) s_accel_plan.dec_n = remain_pulses; s_accel_plan.f_tgt = from_hz; s_decel_from = from_hz; - s_profile_dirty = 1U; + PlsrAccelPulseRtBeginDec(&s_pulse_rt, &s_accel_plan); + s_pulse_rt.f = from_hz; if (remain_pulses == 0U) { @@ -685,7 +698,6 @@ static void PlsrRunControlEnterDecel(uint32_t from_hz, uint32_t remain_pulses) return; } - /* 时间字段仅预览兼容;运行取频走 FreqAtPulse */ if (s_accel_plan.t_dec_ms == 0U) { s_accel_plan.t_dec_ms = 1U; @@ -693,9 +705,7 @@ static void PlsrRunControlEnterDecel(uint32_t from_hz, uint32_t remain_pulses) } /** - * 进匀速:写一次 f_tgt,之后 RefreshProfile 不再周期性取频/改 ARR(防抖)。 - * 注意:这不是禁止改频——ACT/EXT 打断、ChangeFreq、进减速、开下一段 - * 都会离开 PH_CONST 或直接 Start/Stop,ApplyOutFreq 仍可改频。 + * 进匀速:写一次 f_tgt,之后 ISR 不改 ARR(复用缓存)。 */ static void PlsrRunControlEnterConstHold(uint8_t do_start) { @@ -706,9 +716,25 @@ static void PlsrRunControlEnterConstHold(uint8_t do_start) f_hold = 1U; } PlsrRunControlEnterPhase(PH_CONST, f_hold); + PlsrAccelPulseRtBeginConst(&s_pulse_rt, &s_accel_plan); + PlsrPulseDriverClearPending(); PlsrRunControlApplyOutFreq(f_hold, do_start); } +static void PlsrRunControlEnterConstHoldIsr(void) +{ + uint32_t f_hold = s_accel_plan.f_tgt; + + if (f_hold < 1U) + { + f_hold = 1U; + } + PlsrRunControlEnterPhase(PH_CONST, f_hold); + PlsrAccelPulseRtBeginConst(&s_pulse_rt, &s_accel_plan); + PlsrPulseDriverClearPending(); + PlsrRunControlApplyOutFreqIsr(f_hold); +} + static void PlsrRunControlRefreshProfile(uint8_t do_start) { uint32_t next; @@ -722,21 +748,13 @@ static void PlsrRunControlRefreshProfile(uint8_t do_start) } remain = PlsrRunControlRemainPulses(); - /* - * 匀速 → 减速:只看剩余脉冲,不反复算频。 - */ if ((s_phase == PH_CONST) && (PlsrRunControlHasDecel() != 0U) && (remain <= s_accel_plan.dec_n)) { - PlsrRunControlEnterPhase(PH_DECEL, s_accel_plan.f_tgt); + PlsrRunControlEnterDecel(s_accel_plan.f_tgt, remain); } - /* - * 匀速保持:跳过周期性 FreqAtPulse(防顶频抖动)。 - * 仍允许:do_start / 停表后重开 写一次;打断切段走 BeginSeg/PlanSeg - * 会改 s_phase,不再走本分支。 - */ if (s_phase == PH_CONST) { if ((do_start != 0U) || (s_pwm_on == 0U)) @@ -746,18 +764,15 @@ static void PlsrRunControlRefreshProfile(uint8_t do_start) return; } - /* 加速 / 减速:按脉冲域算下一频率 */ next = PlsrAccelCurveFreqAtPulse(&s_accel_plan, done_n); if (next < 1U) { next = 1U; } + s_pulse_rt.f = next; if (s_phase == PH_APPROACH) { - /* - * 加速结束:脉冲用完或频率已到峰值 → 匀速保持(或直接进减速)。 - */ if ((s_accel_plan.acc_n == 0U) || (done_n >= s_accel_plan.acc_n) || ((s_accel_plan.f_tgt >= s_accel_plan.f_cur) && @@ -769,7 +784,7 @@ static void PlsrRunControlRefreshProfile(uint8_t do_start) if ((PlsrRunControlHasDecel() != 0U) && (remain <= s_accel_plan.dec_n)) { - PlsrRunControlEnterPhase(PH_DECEL, next); + PlsrRunControlEnterDecel(next, remain); } else { @@ -882,7 +897,7 @@ static void PlsrRunControlPlanSeg(uint32_t total, uint32_t f_from, } /* - * 保持 AccelCurvePlan 算出的脉冲预算;运行时 FreqAtPulse 按 s_done 取频。 + * 保持 AccelCurvePlan 算出的脉冲预算;运行时逐拍 PulseRtStep。 */ /* * 纯减速段:已在目标速(或更高)且整段预算不超过 dec_n。 @@ -898,12 +913,13 @@ static void PlsrRunControlPlanSeg(uint32_t total, uint32_t f_from, else if (f_start == s_accel_plan.f_tgt) { PlsrRunControlEnterPhase(PH_CONST, f_start); + PlsrAccelPulseRtBeginConst(&s_pulse_rt, &s_accel_plan); } else { PlsrRunControlEnterPhase(PH_APPROACH, f_start); + PlsrAccelPulseRtBeginAcc(&s_pulse_rt, &s_accel_plan); } - s_profile_dirty = 1U; } static void PlsrRunControlFinishAll(void) @@ -918,7 +934,6 @@ static void PlsrRunControlFinishAll(void) s_follow_cont = 0U; s_chain_valid = 0U; s_chain_freq = 0U; - s_profile_dirty = 0U; s_act_armed = 0U; s_act_expire_req = 0U; s_act_cut_pending = 0U; @@ -1013,7 +1028,6 @@ static void PlsrRunControlBeginSeg(uint16_t seg_0) if (s_follow_cont != 0U) { PlsrPulseDriverClearOnePulseStop(); - s_profile_dirty = 0U; PlsrRunControlRefreshProfile(0U); s_state = RC_RUN; s_follow_cont = 0U; @@ -1046,7 +1060,6 @@ void PlsrRunControlInit(void) s_phase = PH_CONST; s_approach_from = 0U; s_decel_from = 0U; - s_profile_dirty = 0U; s_act_armed = 0U; s_act_expire_req = 0U; s_act_cut_pending = 0U; @@ -1100,7 +1113,6 @@ void PlsrRunControlStop(void) s_follow_cont = 0U; s_chain_valid = 0U; s_chain_freq = 0U; - s_profile_dirty = 0U; s_act_armed = 0U; s_act_expire_req = 0U; s_act_cut_pending = 0U; @@ -1134,7 +1146,6 @@ uint8_t PlsrRunControlChangeFreq(uint32_t new_tgt_hz) s_run_accel_ms, s_run_decel_ms); s_target = (int32_t)remain; s_done = 0; - s_profile_dirty = 0U; PlsrRunControlRefreshProfile(0U); return 1U; } @@ -1168,7 +1179,6 @@ void PlsrRunControlTickMs(void) if (PlsrRunControlOsTimeReached(s_dir_deadline) != 0U) { s_state = RC_RUN; - s_profile_dirty = 0U; PlsrRunControlRefreshProfile(1U); PlsrRunControlArmActExtOnPulseStart(); } @@ -1177,23 +1187,8 @@ void PlsrRunControlTickMs(void) if (s_state == RC_RUN) { - /* - * 仅加/减速(或匀速刚到进减速点)才改频。 - * 匀速锁定期间 dirty 不会置位,避免顶频反复写 ARR。 - */ - if ((s_profile_dirty != 0U) && (s_act_cut_pending == 0U)) - { - s_profile_dirty = 0U; - PlsrRunControlRefreshProfile(0U); - } - else if ((s_phase == PH_CONST) && - (PlsrRunControlHasDecel() != 0U) && - (s_act_cut_pending == 0U) && - (PlsrRunControlRemainPulses() <= s_accel_plan.dec_n)) - { - /* 任务侧兜底:进减速 */ - PlsrRunControlRefreshProfile(0U); - } + /* ISR 极少换 PSC 时挂起的改频 */ + PlsrPulseDriverApplyPending(); seg = PlsrParamGetSeg(s_cur_seg); @@ -1267,10 +1262,11 @@ void PlsrRunControlOn1ms(void) } } -/** 脉冲 UPDATE:计脉冲;仅加/减速置 dirty(匀速不改频) */ +/** 脉冲 UPDATE:计脉冲 + 逐拍改频(匀速复用 ARR) */ void PlsrRunControlOnPulseIsr(void) { uint32_t remain; + uint32_t next; if (s_state != RC_RUN) { @@ -1287,30 +1283,8 @@ void PlsrRunControlOnPulseIsr(void) s_acc_pulse--; } - /* - * 匀速:不置 dirty,定时器 ARR 保持不动。 - * 仅当剩余脉冲进入减速预算时置位,让任务切到 DECEL。 - */ - if (s_phase == PH_CONST) - { - if (PlsrRunControlHasDecel() != 0U) - { - remain = PlsrRunControlRemainPulses(); - if (remain <= s_accel_plan.dec_n) - { - s_profile_dirty = 1U; - } - } - } - else - { - s_profile_dirty = 1U; - } - /* * ACT 到期切段只在脉冲边界执行,避免半个 PWM 周期改段。 - * 同向衔接:不停表,任务里用当前频率规划下一段(丢掉本段剩余)。 - * 停表会把 pwm_on 清掉,Resolve 若再要求 pwm_on 就会误走起跳。 */ if (s_act_cut_pending != 0U) { @@ -1327,6 +1301,58 @@ void PlsrRunControlOnPulseIsr(void) return; } + remain = PlsrRunControlRemainPulses(); + + if (s_phase == PH_CONST) + { + /* + * 匀速热路径:频率未变 → 不写寄存器。 + * 制动区:remain <= dec_n(规划好的距离)→ 进减速。 + */ + if ((PlsrRunControlHasDecel() != 0U) && + (remain <= s_accel_plan.dec_n)) + { + PlsrRunControlEnterDecel(s_accel_plan.f_tgt, remain); + next = PlsrAccelPulseRtStep(&s_pulse_rt); + PlsrRunControlApplyOutFreqIsr(next); + } + } + else if (s_phase == PH_APPROACH) + { + next = PlsrAccelPulseRtStep(&s_pulse_rt); + + if ((s_accel_plan.acc_n == 0U) || + (s_pulse_rt.active == 0U) || + (s_pulse_rt.n >= s_accel_plan.acc_n) || + ((s_accel_plan.f_tgt >= s_accel_plan.f_cur) && + (next >= s_accel_plan.f_tgt)) || + ((s_accel_plan.f_tgt < s_accel_plan.f_cur) && + (next <= s_accel_plan.f_tgt))) + { + next = s_accel_plan.f_tgt; + if ((PlsrRunControlHasDecel() != 0U) && + (remain <= s_accel_plan.dec_n)) + { + PlsrRunControlEnterDecel(next, remain); + next = PlsrAccelPulseRtStep(&s_pulse_rt); + PlsrRunControlApplyOutFreqIsr(next); + } + else + { + PlsrRunControlEnterConstHoldIsr(); + } + } + else + { + PlsrRunControlApplyOutFreqIsr(next); + } + } + else /* PH_DECEL */ + { + next = PlsrAccelPulseRtStep(&s_pulse_rt); + PlsrRunControlApplyOutFreqIsr(next); + } + if (s_done >= (s_target - 1)) { if (PlsrRunControlWillFollowKeep(s_cur_seg) == 0U) diff --git a/plsr/run_control/plsr_run_control.h b/plsr/run_control/plsr_run_control.h index de79263..f48f8bf 100644 --- a/plsr/run_control/plsr_run_control.h +++ b/plsr/run_control/plsr_run_control.h @@ -12,8 +12,8 @@ uint8_t PlsrRunControlStart(uint16_t start_seg_1based); void PlsrRunControlStop(void); uint8_t PlsrRunControlChangeFreq(uint32_t new_tgt_hz); void PlsrRunControlOn1ms(void); /* TIM3 1ms:仅 ACT/WAIT 时基 */ -void PlsrRunControlOnPulseIsr(void); /* 脉冲 UPDATE:计脉冲 + dirty */ -void PlsrRunControlTickMs(void); /* 任务:脉冲域改频 + EXT/到期切段 */ +void PlsrRunControlOnPulseIsr(void); /* 脉冲 UPDATE:计数 + 逐拍改频 */ +void PlsrRunControlTickMs(void); /* 任务:ACT/WAIT/EXT + ApplyPending */ uint8_t PlsrRunControlIsBusy(void); int32_t PlsrRunControlGetAccPulse(void); void PlsrRunControlClearAccPulse(void);