Parcourir la source

修复输出起始频率不对

Signed-off-by: hanyongwei <2043702190@qq.com>
dev1
hanyongwei il y a 3 semaines
Parent
révision
8ebd1b7382
6 fichiers modifiés avec 555 ajouts et 426 suppressions
  1. +0
    -4
      iar/plsr.dep
  2. +439
    -379
      plsr/accel_curve/plsr_accel_curve.c
  3. +16
    -14
      plsr/accel_curve/plsr_accel_curve.h
  4. +85
    -25
      plsr/pulse_driver/plsr_pulse_driver.c
  5. +5
    -0
      plsr/pulse_driver/plsr_pulse_driver.h
  6. +10
    -4
      plsr/run_control/plsr_run_control.c

+ 0
- 4
iar/plsr.dep Voir le fichier

@@ -2775,10 +2775,6 @@
<name>BICOMP</name> <name>BICOMP</name>
<file> 171</file> <file> 171</file>
</tool> </tool>
<tool>
<name>ICCARM</name>
<file> 190</file>
</tool>
</outputs> </outputs>
<inputs> <inputs>
<tool> <tool>


+ 439
- 379
plsr/accel_curve/plsr_accel_curve.c
Fichier diff supprimé car celui-ci est trop grand
Voir le fichier


+ 16
- 14
plsr/accel_curve/plsr_accel_curve.h Voir le fichier

@@ -5,9 +5,9 @@
* @details 按起/峰/止频率、斜率时间与总脉冲规划三相脉冲预算,并在脉冲序号上取频。 * @details 按起/峰/止频率、斜率时间与总脉冲规划三相脉冲预算,并在脉冲序号上取频。
* 不读 wait_type,不碰 TIM/GPIO。 * 不读 wait_type,不碰 TIM/GPIO。
* *
* 直线:f_n = sqrt(f0^2 ± 2 a n)(脉冲域)。
* S/正弦:时间轴规划——S 为 jerk 升/恒加速/jerk 降(加速度梯形 1:2:1);
* 正弦为 raised-cosine;ISR 按累计时间取频,每拍推进 Δt=1/f
* 直线:f_n = sqrt(f0^2 ± 2 a n)(脉冲域,ISR 增量逼近)。
* S/正弦:开相时预计算频率表;ISR 只按脉冲序号查表(匀速相不改频)。
* acc_n/dec_n 与建表同一套离散逐拍仿真
* *
* 术语(全模块统一): * 术语(全模块统一):
* acc_n / dec_n / const_n — 加速/减速/匀速相各需的脉冲个数(规划预算,非 ms) * acc_n / dec_n / const_n — 加速/减速/匀速相各需的脉冲个数(规划预算,非 ms)
@@ -52,7 +52,7 @@ uint32_t PlsrAccelCurveResolveEndHz(uint32_t f_cfg,


/** /**
* 规划一整段脉冲域三相预算与实际峰值 * 规划一整段脉冲域三相预算与实际峰值
* 脉冲不够爬到 f_tgt 时 FitPeak 降峰(调用方可能写故障 0x02)
* 脉冲不够爬到 f_tgt 时先 const_n=0,再 FitPeak 降峰(调用方可能写故障 0x02)
*/ */
void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan, void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan,
uint32_t total_pulses, uint32_t total_pulses,
@@ -70,8 +70,8 @@ uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan,


/** /**
* 单相逐脉冲运行态(ISR 热路径,每来一个 UPDATE 调 Step 一次) * 单相逐脉冲运行态(ISR 热路径,每来一个 UPDATE 调 Step 一次)
* 直线:±1Hz 逼近 sqrt(f0²±2an)
* S/正弦:累计 t_us,按时间剖面取频;每拍 t += 1e6/f
* 直线:±1Hz 逼近 sqrt(f0^2±2an)
* S/正弦:查预计算频率表(开相 BeginAcc/BeginDec 时填好)
*/ */
typedef struct { typedef struct {
uint32_t f; /* 当前输出频率 Hz */ uint32_t f; /* 当前输出频率 Hz */
@@ -80,19 +80,21 @@ typedef struct {
uint32_t a; /* 本相加速度 Hz/s */ uint32_t a; /* 本相加速度 Hz/s */
uint32_t n; /* 本相已步进脉冲数 */ uint32_t n; /* 本相已步进脉冲数 */
uint32_t n_total; /* 本相总步进预算(= plan 里 acc_n 或 dec_n) */ uint32_t n_total; /* 本相总步进预算(= plan 里 acc_n 或 dec_n) */
uint32_t t_us; /* S/正弦:本相已累计时间 us */
uint32_t tj_us; /* S:jerk 段时长 us;正弦未用 */
uint32_t ta_us; /* S:恒加速段时长 us;正弦未用 */
uint32_t tramp_us; /* S/正弦:本相斜坡总时长 us */
uint32_t phase_q24; /* 保留 */
uint32_t step_q24;
uint32_t step_rem;
uint32_t rem_acc;
uint32_t t_us; /* 建表用:累计时间 us */
uint32_t tj_us; /* 建表用:S jerk 段 us */
uint32_t ta_us; /* 建表用:S 恒加速段 us */
uint32_t tramp_us; /* 建表用:斜坡总时长 us */
uint32_t tbl_stride; /* 查表:每 stride 个脉冲对应 1 个表项 */
uint32_t tbl_len; /* 表有效长度 */
uint8_t rising; /* 1=频率升高,0=降低 */ uint8_t rising; /* 1=频率升高,0=降低 */
uint8_t active; /* 1=本相仍在步进;0=已到 f1 */ uint8_t active; /* 1=本相仍在步进;0=已到 f1 */
uint8_t use_tbl; /* 1=S/正弦走查表 */
PlsrAccelMode_e mode; PlsrAccelMode_e mode;
} PlsrAccelPulseRt_t; } PlsrAccelPulseRt_t;


/** PlanSeg 后调用:预建 S/正弦加减速频率表(勿在 ISR) */
void PlsrAccelPulseRtPrebuild(const PlsrAccelPlan_t *plan);

void PlsrAccelPulseRtBeginAcc(PlsrAccelPulseRt_t *pulse_rt, void PlsrAccelPulseRtBeginAcc(PlsrAccelPulseRt_t *pulse_rt,
const PlsrAccelPlan_t *plan); const PlsrAccelPlan_t *plan);
void PlsrAccelPulseRtBeginDec(PlsrAccelPulseRt_t *pulse_rt, void PlsrAccelPulseRtBeginDec(PlsrAccelPulseRt_t *pulse_rt,


+ 85
- 25
plsr/pulse_driver/plsr_pulse_driver.c Voir le fichier

@@ -56,6 +56,14 @@ static volatile uint8_t s_req_pending;
*/ */
static uint8_t s_regs_prepared; static uint8_t s_regs_prepared;
static volatile uint8_t s_seg_end_fall_armed; /* 1=末拍 CC1 下降沿后强制拉低 */ static volatile uint8_t s_seg_end_fall_armed; /* 1=末拍 CC1 下降沿后强制拉低 */
/*
* 冷启动首拍保护:Commit 后第一次 SetFreqIsr 必须先钉住工作 ARR=起跳频,
* 再把下一拍写入影子。否则 ARPE 未生效时 ISR 会直接改写工作寄存器,
* 示波器上首周期频率变成「第 2 个脉冲」的频率(起跳越高越明显)。
*/
static volatile uint8_t s_protect_start_period;
static uint32_t s_protect_arr;
static uint32_t s_protect_ccr;


/*============================================================================*/ /*============================================================================*/
/* 路选择 / 时钟 / GPIO */ /* 路选择 / 时钟 / GPIO */
@@ -271,6 +279,9 @@ void PlsrPulseDriverInit(void)
s_locked_psc = 0U; s_locked_psc = 0U;
s_req_pending = 0U; s_req_pending = 0U;
s_req_freq = 0U; s_req_freq = 0U;
s_protect_start_period = 0U;
s_protect_arr = 0U;
s_protect_ccr = 0U;
s_active_htim = &htim10; s_active_htim = &htim10;
PlsrPulseDriverDirGpioInit(); PlsrPulseDriverDirGpioInit();
/* 三路都 Init + 空闲拉低,计数器关闭;出脉冲时只 Start 选中那路 */ /* 三路都 Init + 空闲拉低,计数器关闭;出脉冲时只 Start 选中那路 */
@@ -583,22 +594,26 @@ static void PlsrPulseDriverLoadRegs(uint32_t freq_hz)
} }


/** /**
* @brief 开沿:先 Forced Active 出首上升沿,再切 PWM1 连续发脉冲
* @brief 开沿:直写工作 ARR 后立刻打开预装载并同步影子,再使能计数
* *
* @note WAIT/换向后若首拍 CCR 工作值为 0,PWM1 会整拍低电平,示波器上就是
* 「延时 + 本段第一脉冲周期」。Forced Active 与 CNT/CCR 无关,首沿必须出现。
* Commit 内不再 UG,避免预装载影子把 CCR 又打回旧值/0。
* @note 必须先 ARPE+影子=起跳频,再 ENABLE。若先开表再开 ARPE,
* 高频下首拍 UPDATE 的 ISR 可能在 ARPE 仍关时改 ARR,工作寄存器
* 被直接写成 f(1),示波器上首周期就像「x=2」而不是起跳频。
* CNT=ARR:下一节拍产生 UPDATE,建立 PWM1 首上升沿并进入脉冲计数。
*/ */
static void PlsrPulseDriverCommitOutput(void) static void PlsrPulseDriverCommitOutput(void)
{ {
TIM_HandleTypeDef *htim = s_active_htim; TIM_HandleTypeDef *htim = s_active_htim;
uint32_t ccmr; uint32_t ccmr;
uint32_t ccr;


if ((htim == (TIM_HandleTypeDef *)0) || (htim->Instance == (TIM_TypeDef *)0)) if ((htim == (TIM_HandleTypeDef *)0) || (htim->Instance == (TIM_TypeDef *)0))
{ {
return; return;
} }


ccr = (s_last_ccr < 1U) ? 1U : s_last_ccr;

__HAL_TIM_DISABLE(htim); __HAL_TIM_DISABLE(htim);
__HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); __HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE);


@@ -606,32 +621,33 @@ static void PlsrPulseDriverCommitOutput(void)
htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE); htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE);
htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE); htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE);
htim->Instance->ARR = s_last_arr; htim->Instance->ARR = s_last_arr;
htim->Instance->CCR1 = (s_last_ccr < 1U) ? 1U : s_last_ccr;
htim->Instance->CNT = 0U;
htim->Instance->CCR1 = ccr;


/*
* 唯一的脉冲启动入口。通道必须在 CEN 前使能;TIM10/11/13 在
* 运行中由 CC1E=0 -> 1 不保证重新建立当前 PWM1 电平,会保持无输出。
* CNT 从 ARR 开始,下一计数节拍产生真实 UPDATE:该 UPDATE 同时建立
* PWM1 首上升沿并进入现有脉冲 ISR 计数,边沿与 s_done 保持一一对应。
*/
ccmr = htim->Instance->CCMR1; ccmr = htim->Instance->CCMR1;
ccmr &= (uint32_t)(~TIM_CCMR1_OC1M); ccmr &= (uint32_t)(~TIM_CCMR1_OC1M);
ccmr |= TIM_OCMODE_PWM1; ccmr |= TIM_OCMODE_PWM1;
htim->Instance->CCMR1 = ccmr; htim->Instance->CCMR1 = ccmr;
htim->Instance->CCER |= TIM_CCER_CC1E; htim->Instance->CCER |= TIM_CCER_CC1E;


/*
* 先打开预装载并把影子钉成同一频率,再 ENABLE。
* 否则首拍 ISR 的 SetFreqIsr 可能落在 ARPE=0 窗口,直接改写工作 ARR。
*/
htim->Instance->CR1 |= TIM_CR1_ARPE;
htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE;
htim->Instance->ARR = s_last_arr;
htim->Instance->CCR1 = ccr;

htim->Instance->CNT = s_last_arr; htim->Instance->CNT = s_last_arr;
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE);
__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE); __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);
__HAL_TIM_ENABLE(htim); __HAL_TIM_ENABLE(htim);


/* 运行期改频仍走预装载 */
htim->Instance->CR1 |= TIM_CR1_ARPE;
htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE;
htim->Instance->ARR = s_last_arr;
htim->Instance->CCR1 = (s_last_ccr < 1U) ? 1U : s_last_ccr;
/* 记录起跳工作寄存器,供首拍 ISR 保护当前周期 */
s_protect_arr = s_last_arr;
s_protect_ccr = ccr;
s_protect_start_period = 1U;


s_regs_prepared = 0U; s_regs_prepared = 0U;
} }
@@ -737,23 +753,53 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz)
uint32_t clk_hz; uint32_t clk_hz;
TIM_HandleTypeDef *htim; TIM_HandleTypeDef *htim;


/* 匀速热路径:频率未变 → 不算量化、不写寄存器 */
if (freq_hz == s_last_freq)
htim = s_active_htim;
if (htim == (TIM_HandleTypeDef *)0)
{ {
if (freq_hz == 0U)
{
s_req_freq = 0U;
s_req_pending = 1U;
return;
}
s_req_freq = freq_hz;
s_req_pending = 1U;
return; return;
} }


if (freq_hz == 0U)
/*
* 冷启动首拍:无论下一频是否变化,先把工作 ARR 钉回起跳频,再开预装载。
* 必须在「freq==last 早退」之前做,否则首拍保护标志清不掉。
*/
if (s_protect_start_period != 0U)
{
s_protect_start_period = 0U;
htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE);
htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE);
htim->Instance->ARR = s_protect_arr;
htim->Instance->CCR1 = (s_protect_ccr < 1U) ? 1U : s_protect_ccr;
htim->Instance->CR1 |= TIM_CR1_ARPE;
htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE;
/* 影子也先钉成起跳,下面再写入真正的下一拍频率 */
htim->Instance->ARR = s_protect_arr;
htim->Instance->CCR1 = (s_protect_ccr < 1U) ? 1U : s_protect_ccr;
}
else
{
/* 常规路径:确保预装载开启,禁止直写工作寄存器 */
htim->Instance->CR1 |= TIM_CR1_ARPE;
htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE;
}

/* 匀速热路径:频率未变 → 不算量化、不写寄存器 */
if (freq_hz == s_last_freq)
{ {
s_req_freq = 0U;
s_req_pending = 1U;
return; return;
} }


htim = s_active_htim;
if (htim == (TIM_HandleTypeDef *)0)
if (freq_hz == 0U)
{ {
s_req_freq = freq_hz;
s_req_freq = 0U;
s_req_pending = 1U; s_req_pending = 1U;
return; return;
} }
@@ -783,12 +829,19 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz)
return; return;
} }


if (ccr < 1U)
{
ccr = 1U;
}

/* 此时 ARPE 已开:只改影子,下一 UPDATE 才切换,当前起跳周期不受影响 */
__HAL_TIM_SET_AUTORELOAD(htim, arr); __HAL_TIM_SET_AUTORELOAD(htim, arr);
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr); __HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr);


s_last_freq = freq_hz; s_last_freq = freq_hz;
s_last_psc = psc; s_last_psc = psc;
s_last_arr = arr; s_last_arr = arr;
s_last_ccr = ccr;
} }


/** @brief 丢弃挂起(见 plsr_pulse_driver.h) */ /** @brief 丢弃挂起(见 plsr_pulse_driver.h) */
@@ -797,6 +850,12 @@ void PlsrPulseDriverClearPending(void)
s_req_pending = 0U; s_req_pending = 0U;
} }


/** @brief 取消冷启动首拍保护(见 plsr_pulse_driver.h) */
void PlsrPulseDriverClearStartPeriodProtect(void)
{
s_protect_start_period = 0U;
}

/** @brief 消费挂起改频(见 plsr_pulse_driver.h) */ /** @brief 消费挂起改频(见 plsr_pulse_driver.h) */
void PlsrPulseDriverApplyPending(void) void PlsrPulseDriverApplyPending(void)
{ {
@@ -827,6 +886,7 @@ void PlsrPulseDriverStop(void)
{ {
s_req_pending = 0U; s_req_pending = 0U;
s_regs_prepared = 0U; s_regs_prepared = 0U;
s_protect_start_period = 0U;
PlsrPulseDriverStopHtim(&htim10); PlsrPulseDriverStopHtim(&htim10);
PlsrPulseDriverStopHtim(&htim11); PlsrPulseDriverStopHtim(&htim11);
PlsrPulseDriverStopHtim(&htim13); PlsrPulseDriverStopHtim(&htim13);


+ 5
- 0
plsr/pulse_driver/plsr_pulse_driver.h Voir le fichier

@@ -94,6 +94,11 @@ void PlsrPulseDriverApplyPending(void);
/** @brief 丢弃未生效的改频请求(进匀速锁定时用) */ /** @brief 丢弃未生效的改频请求(进匀速锁定时用) */
void PlsrPulseDriverClearPending(void); void PlsrPulseDriverClearPending(void);


/**
* @brief 取消冷启动首拍 ARR 保护(进入匀速、无首拍改频时调用)
*/
void PlsrPulseDriverClearStartPeriodProtect(void);

/** /**
* @brief 停止三路脉冲 TIM,空闲 Forced inactive 拉低 * @brief 停止三路脉冲 TIM,空闲 Forced inactive 拉低
* @note 不清方向脚;不清 PSC 锁(由上层 Unlock) * @note 不清方向脚;不清 PSC 锁(由上层 Unlock)


+ 10
- 4
plsr/run_control/plsr_run_control.c Voir le fichier

@@ -1009,6 +1009,7 @@ static void PlsrRunControlEnterConstHold(uint8_t do_start)
s_phase = PH_CONST; s_phase = PH_CONST;
PlsrAccelPulseRtBeginConst(&s_pulse_rt, &s_accel_plan); PlsrAccelPulseRtBeginConst(&s_pulse_rt, &s_accel_plan);
PlsrPulseDriverClearPending(); PlsrPulseDriverClearPending();
PlsrPulseDriverClearStartPeriodProtect();
PlsrRunControlApplyOutFreq(f_hold, do_start); PlsrRunControlApplyOutFreq(f_hold, do_start);
} }


@@ -1023,6 +1024,7 @@ static void PlsrRunControlEnterConstHoldIsr(void)
s_phase = PH_CONST; s_phase = PH_CONST;
PlsrAccelPulseRtBeginConst(&s_pulse_rt, &s_accel_plan); PlsrAccelPulseRtBeginConst(&s_pulse_rt, &s_accel_plan);
PlsrPulseDriverClearPending(); PlsrPulseDriverClearPending();
PlsrPulseDriverClearStartPeriodProtect();
PlsrRunControlApplyOutFreqIsr(f_hold); PlsrRunControlApplyOutFreqIsr(f_hold);
} }


@@ -1161,12 +1163,15 @@ static void PlsrRunControlPlanSeg(uint32_t total, uint32_t f_from,
s_plan_dec_n = s_accel_plan.dec_n; s_plan_dec_n = s_accel_plan.dec_n;
s_decel_budget = 0U; s_decel_budget = 0U;


/* S/正弦:在任务上下文预建频率表,ISR 只查表 */
PlsrAccelPulseRtPrebuild(&s_accel_plan);

/* 运行层使用规划后的实际起始频率。 */ /* 运行层使用规划后的实际起始频率。 */
f_start = s_accel_plan.f_cur; f_start = s_accel_plan.f_cur;


/* /*
* 脉冲域:运行时按已完成脉冲数 FreqAtPulse 取频
* 禁止再用时间轴二次拟合,否则规划与运行不一致
* 脉冲域:ISR 用 PulseRtStep(直线现场算 / S·正弦查预建表)
* FreqAtPulse 仅任务侧 RefreshProfile 对齐用,勿再做时间轴二次拟合
*/ */


/* 本段频率范围锁 PSC,升降只改 ARR;跨度过大则 LockPscRange 自动不锁 */ /* 本段频率范围锁 PSC,升降只改 ARR;跨度过大则 LockPscRange 自动不锁 */
@@ -1829,9 +1834,10 @@ void PlsrRunControlOnPulseIsr(void)
if (s_phase == PH_CONST) if (s_phase == PH_CONST)
{ {
/* /*
* 匀速热路径:频率未变 → 不写寄存器
* ARPE 超前:remain<=dec_n+1 进减速,使末拍 ARR 为 f_end
* 匀速:不改频、不写 ARR(热路径几乎空转)
* 仅在 remain 进入减速窗口时切相并查表改频
*/ */
PlsrPulseDriverClearStartPeriodProtect();
if (PlsrRunControlShouldEnterDecel(remain) != 0U) if (PlsrRunControlShouldEnterDecel(remain) != 0U)
{ {
PlsrRunControlEnterDecel(s_accel_plan.f_tgt, PlsrRunControlEnterDecel(s_accel_plan.f_tgt,


Chargement…
Annuler
Enregistrer