2385575_zh-CN

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

2385575_zh-CN

2385575_zh-CN

RT1176 PWM启动失败

我使用PWM+故障+QTimer来实现电机脉冲控制,但PWM3子模块0的PWM_A通道偶尔无法启动,在第一个高电平之后就一直保持高电平,后续脉冲不再出现。检查后发现,PWM的“运行”位没有正确设置。即使后来在程序中添加了重复启动操作,这种异常情况仍然发生。

liu626_0-1782287927569.png


Re: RT1176 PWM startup failed

你好@liu626

你用的是定制板还是EVK板?如果你使用的是 EVK,你对它进行过任何修改吗?

能否分享一下您使用的PWM3配置?

您是使用示例作为参考吗?如果是,是哪一个?

如果尝试使用仅包含 PWM3 的项目来重现该问题,问题是否仍然存在?

这种情况是否只发生在 PWM3 子模块 0 PWM_A 通道上?其他PWM模块或子模块是否也出现过这种情况?

是否还有其他任务或中断会操作 PWM3 寄存器,从而影响或覆盖运行位?

此致,
巴勃罗

Re: RT1176 PWM startup failed您好,我使用的是定制电路板。我没有举任何例子。这是在项目正式开发过程中发现的问题。我配置了六个PWM通道用于脉冲控制。只有这个通道出现了问题,其他子模块都没有出现此类问题。我检查后发现,只有这个通道使用了 PWM3 模块。未检测到其他干扰因素。以下是我的配置。
静态 axis_ctrl_t g_axes[AXIS_NUM] =
{
{
。ID= AXIS_X1,.name= "X1",
.pwmBase= PWM1,.pwmModule= kPWM_Module_0,.pwmChannel= kPWM_PwmA,
.tmrBase= TMR3,.lowCh= kQTMR_Channel_2,.highCh= kQTMR_Channel_3,
.tmrInputsrc=kQTMR_ClockCounter2InputPin,.cascadePcs= 6U,
故障编号= 0U,.hwExactSupported= true,.outTrigMask= kPWM_ValueRegisterMask_3,
},

{
。ID= AXIS_X2,.name= "X2",
.pwmBase= PWM2,.pwmModule= kPWM_Module_0,.pwmChannel= kPWM_PwmA,
.tmrBase= TMR2,.lowCh= kQTMR_Channel_0, .highCh= kQTMR_Channel_1,
.tmrInputsrc=kQTMR_ClockCounter0InputPin,.cascadePcs= 4U,
故障编号= 0U,.hwExactSupported= true,.outTrigMask= kPWM_ValueRegisterMask_3,
},

{
。ID= AXIS_Y,.name= "Y",
.pwmBase= PWM3,.pwmModule= kPWM_Module_0,.pwmChannel= kPWM_PwmA,
.tmrBase= TMR3,.lowCh= kQTMR_Channel_0, .highCh= kQTMR_Channel_1,
.tmrInputsrc=kQTMR_ClockCounter0InputPin,.cascadePcs= 4U,
故障编号= 0U,.hwExactSupported= true,.outTrigMask= kPWM_ValueRegisterMask_3,
},

{
。ID= AXIS_Z,.name= "Z",
.pwmBase= PWM4,.pwmModule= kPWM_Module_0,.pwmChannel= kPWM_PwmA,
.tmrBase= TMR1,.lowCh= kQTMR_Channel_0, .highCh= kQTMR_Channel_1,
.tmrInputsrc=kQTMR_ClockCounter0InputPin,.cascadePcs= 4U,
故障编号= 0U,.hwExactSupported= true,.outTrigMask= kPWM_ValueRegisterMask_3,
},

{
。ID= AXIS_EX1,.name= "EX1",
.pwmBase= PWM1,.pwmModule= kPWM_Module_1,.pwmChannel= kPWM_PwmA,
.tmrBase= TMR1,.lowCh= kQTMR_Channel_2,.highCh= kQTMR_Channel_3,
.tmrInputsrc=kQTMR_ClockCounter2InputPin,.cascadePcs= 6U,
故障编号= 1U,.hwExactSupported= true,.outTrigMask= kPWM_ValueRegisterMask_3,
},

{
。ID= AXIS_EX2,.name= "EX2",
.pwmBase= PWM2,.pwmModule= kPWM_Module_1,.pwmChannel= kPWM_PwmA,
.tmrBase= TMR2,.lowCh= kQTMR_Channel_2,.highCh= kQTMR_Channel_3,
.tmrInputsrc=kQTMR_ClockCounter2InputPin,.cascadePcs= 6U,
故障编号= 1U,.hwExactSupported= true,.outTrigMask= kPWM_ValueRegisterMask_3,
},
};static void APP_Init_PWM_QTMR(void)
{
pwm_config_t pwmConfig;
pwm_fault_param_t faultConfig;
qtmr_config_t qtmrConfig;

PWM_GetDefaultConfig(&pwmConfig);
pwmConfig.pairOperation= kPWM_Independent;
pwmConfig.reloadLogic = kPWM_ReloadImmediate;

PWM_FaultDefaultConfig(&faultConfig);
faultConfig.faultLevel = true;

faultConfig.enableCombinationPath= false;
faultConfig.faultClearingMode= kPWM_手动安全;
faultConfig.recoverMode = kPWM_NoRecovery;

QTMR_GetDefaultConfig(&qtmrConfig);
CLOCK_EnableClock(kCLOCK_Qtimer1);
CLOCK_EnableClock(kCLOCK_Qtimer2);
CLOCK_EnableClock(kCLOCK_Qtimer3);

PWM_StopTimer(PWM1, 0x0FU); PWM_StopTimer(PWM2, 0x0FU);
PWM_StopTimer(PWM3, 0x0FU); PWM_StopTimer(PWM4, 0x0FU);
pwm_fault_input_filter_param_t faultFilter;
故障过滤器.故障过滤器周期= 255U;
faultFilter.faultFilterCount= 7U;
faultFilter.faultGlitchStretch= false;

/* 记录每个PWM实例上已配置的故障通道,避免重复设置 */
uint16_t pwm1FaultDone = 0U, pwm2FaultDone = 0U, pwm3FaultDone = 0U, pwm4FaultDone = 0U;

for (uint8_t i = 0U; i < AXIS_NUM; i++)
{
axis_ctrl_t *ax = &g_axes[i];
PWM_Init(ax->pwmBase, ax->pwmModule, &pwmConfig);
PWM_SetupFaults(ax->pwmBase, (pwm_fault_input_t)ax->faultNum, &faultConfig);

/* 故障提示(每个 PWM 实例的每个故障通道只设置一次) */
{
uint16_t *faultDone;
如果 (ax->pwmBase == PWM1) faultDone = &pwm1FaultDone;
否则如果 (ax->pwmBase == PWM2) faultDone = &pwm2FaultDone;
否则如果 (ax->pwmBase == PWM3) faultDone = &pwm3FaultDone;
否则 faultDone = &pwm4FaultDone;

uint16_t faultBit = (uint16_t)(1U << ax->faultNum);
如果 ((*faultDone & faultBit) == 0U)
{
PWM_SetupFaultInputFilterExt(ax->pwmBase,
(pwm_fault_channels_t)ax->faultNum,
&faultFilter);
*faultDone |= faultBit;
}
}

/* 故障时输出低电平 */
ax->pwmBase->SM[ax->pwmModule].OCTRL &= ~(PWM_OCTRL_PWMAFS_MASK | PWM_OCTRL_PWMBFS_MASK);

APP_PWM_Unmap_Selected_Fault(ax);
APP_PWM_ClearFault_Safe(ax);

ax->pwmBase->SM[ax->pwmModule].INIT = 0U;
ax->pwmBase->SM[ax->pwmModule].VAL0 = 0U;
ax->pwmBase->SM[ax->pwmModule].VAL1 = 1U;
ax->pwmBase->SM[ax->pwmModule].VAL2 = 0U;
ax->pwmBase->SM[ax->pwmModule].VAL3 = 0U;
ax->pwmBase->SM[ax->pwmModule].VAL4 = 0U;
ax->pwmBase->SM[ax->pwmModule].VAL5 = 0U;
ax->pwmBase->SM[ax->pwmModule].TCTRL = PWM_TCTRL_OUT_TRIG_EN(ax->outTrigMask);
APP_PWM_Disable_Output(ax);

如果 (ax->hwExactSupported)
{
qtmrConfig.primarySource= ax->tmrInputSrc;
QTMR_Init(ax->tmrBase, ax->lowCh, &qtmrConfig);
QTMR_Init(ax->tmrBase, ax->highCh, &qtmrConfig);

ax->tmrBase->CHANNEL[ax->lowCh].CTRL = TMR_CTRL_CM(kQTMR_PriSrcRiseEdge)
| TMR_CTRL_PCS(ax->tmrInputSrc);
ax->tmrBase->CHANNEL[ax->highCh].CTRL = TMR_CTRL_CM(kQTMR_CascadeCount)
| TMR_CTRL_PCS(ax->cascadePcs);

APP_QTMR_Disable_Low_OFLAG_Output(ax);
QTMR_DisableInterrupts(ax->tmrBase, ax->lowCh, 0xFFU);
QTMR_DisableInterrupts(ax->tmrBase, ax->highCh, 0xFFU);
QTMR_ClearStatusFlags(ax->tmrBase, ax->lowCh, 0xFFU);
QTMR_ClearStatusFlags(ax->tmrBase, ax->highCh, 0xFFU);
}

ax->phase = kAxisIdle;

ax->armed = false;
ax->running = false;
ax->done = true;
#if HARD_PWM_STATE_GUARD_ENABLE
APP_StateGuard_Reset(ax);
#endif
}

/* 使能 QTMR 中断 */
NVIC_SetPriority(TMR1_IRQn, 2U);
NVIC_SetPriority(TMR2_IRQn, 2U);
NVIC_SetPriority(TMR3_IRQn, 2U);
启用IRQ(TMR1_IRQn);
启用IRQ(TMR2_IRQn);
启用IRQ(TMR3_IRQn);
}static bool APP_PWM_Config_Pulse(axis_ctrl_t *axis,
uint32_t highCnt400M,
uint32_t lowCnt400M)
{
pwm_clock_prescale_t 预分频;
uint16_t periodTicks;
uint32_t totalCnt400M = highCnt400M + lowCnt400M;

如果 ((axis == NULL) || (totalCnt400M == 0U)) 返回 false;
如果 (!APP_PWM_SelectPrescaler_FromPeriodCnt400M(totalCnt400M, &prescale, &periodTicks))
返回 false;

uint32_t highTicks32 = (uint32_t)(((uint64_t)periodTicks * (uint64_t)highCnt400M +
((uint64_t)totalCnt400M / 2ULL)) /
(uint64_t)totalCnt400M);
如果 (highTicks32 == 0U) highTicks32 = 1U;
如果 (highTicks32 >= periodTicks) highTicks32 = (uint32_t)periodTicks - 1U;

uint32_t riseTicks32 = 0U;
uint32_t fallTicks32 = highTicks32;

#if HARD_PWM_LOW_START_PHASE_ENABLE
uint32_t lowTicks32 = (uint32_t)periodTicks - highTicks32;
如果 (lowTicks32 >= (2U * HARD_PWM_LOW_START_PHASE_MIN_TICKS))
{
uint32_t desiredLeadCnt400M = highCnt400M;
uint32_t minLeadCnt400M = (uint32_t)HARD_PWM_LOW_START_PHASE_MIN_US * 400U;
如果 (desiredLeadCnt400M < minLeadCnt400M) desiredLeadCnt400M = minLeadCnt400M;

uint32_t desiredLeadTicks32 = (uint32_t)(((uint64_t)periodTicks * (uint64_t)desiredLeadCnt400M +
((uint64_t)totalCnt400M / 2ULL)) /
(uint64_t)totalCnt400M);
如果 (desiredLeadTicks32 < HARD_PWM_LOW_START_PHASE_MIN_TICKS)
desiredLeadTicks32 = HARD_PWM_LOW_START_PHASE_MIN_TICKS;

uint32_t maxRiseByHalfTicks32 = lowTicks32 / 2U;
uint32_t postGuardTicks32 = (uint32_t)(((uint64_t)periodTicks *
(uint64_t)(HARD_PWM_VAL3_POST_LOW_GUARD_US * 400U) +
((uint64_t)totalCnt400M / 2ULL)) /
(uint64_t)totalCnt400M);
如果 (postGuardTicks32 < HARD_PWM_VAL3_POST_LOW_GUARD_MIN_TICKS)
postGuardTicks32 = HARD_PWM_VAL3_POST_LOW_GUARD_MIN_TICKS;
uint32_t maxRiseByPostGuardTicks32 = (lowTicks32 > postGuardTicks32) ?
(lowTicks32 - postGuardTicks32):0U;

uint32_t selectedRiseTicks32;
如果 (maxRiseByHalfTicks32 >= desiredLeadTicks32)
{
selectedRiseTicks32 = desiredLeadTicks32;
如果 (selectedRiseTicks32 > maxRiseByHalfTicks32)
selectedRiseTicks32 = maxRiseByHalfTicks32;
}
否则如果(maxRiseByPostGuardTicks32 >= desiredLeadTicks32)
{
selectedRiseTicks32 = desiredLeadTicks32;
如果 (selectedRiseTicks32 > maxRiseByPostGuardTicks32)
selectedRiseTicks32 = maxRiseByPostGuardTicks32;
}
别的
{
selectedRiseTicks32 = maxRiseByPostGuardTicks32;
}

如果 (selectedRiseTicks32 >= HARD_PWM_LOW_START_PHASE_MIN_TICKS)
{
riseTicks32 = selectedRiseTicks32;
fallTicks32 = riseTicks32 + highTicks32;
}
}
#endif

如果 (fallTicks32 >= (uint32_t)periodTicks) fallTicks32 = (uint32_t)periodTicks - 1U;
uint16_t riseTicks = (uint16_t)riseTicks32;
uint16_t fallTicks = (uint16_t)fallTicks32;
PWM_SetPwmLdok(axis->pwmBase, APP_PwmModuleMask(axis), false);
uint16_t ctrl = axis->pwmBase->SM[axis->pwmModule].CTRL;
ctrl &= (uint16_t)(~PWM_CTRL_PRSC_MASK);
ctrl |= PWM_CTRL_PRSC(预分频);
axis->pwmBase->SM[axis->pwmModule].CTRL = ctrl;

axis->pwmBase->SM[axis->pwmModule].INIT = 0U;
axis->pwmBase->SM[axis->pwmModule].VAL0 = 0U;
axis->pwmBase->SM[axis->pwmModule].VAL1 = (uint16_t)(periodTicks - 1U);
如果 (axis->pwmChannel == kPWM_PwmA) {
axis->pwmBase->SM[axis->pwmModule].VAL2 = riseTicks;
axis->pwmBase->SM[axis->pwmModule].VAL3 = fallTicks;
} 否则如果 (axis->pwmChannel == kPWM_PwmB) {
axis->pwmBase->SM[axis->pwmModule]。VAL4 = riseTicks;
axis->pwmBase->SM[axis->pwmModule].VAL5 = fallTicks;
}
axis->pwmBase->SM[axis->pwmModule].TCTRL = PWM_TCTRL_OUT_TRIG_EN(axis->outTrigMask);

PWM_SetPwmLdok(axis->pwmBase, APP_PwmModuleMask(axis), true);
PWM_SetPwmLdok(axis->pwmBase, APP_PwmModuleMask(axis), true);
axis->pwmConfigValid = true;
axis->cachedHighCnt400M = highCnt400M;
axis->cachedLowCnt400M = lowCnt400M;
返回 true;
}
Re: RT1176 PWM startup failed

你好@liu626

您能否帮我找出配置问题,并测试一下仅初始化 PWM3 时问题是否仍然存在?

在查看了您分享的配置后,为了尝试重现该行为,我有以下问题:

axis_ctrl_t 的定义是什么?

您的应用程序中是否启用了 HARD_PWM_LOW_START_PHASE_ENABLE 和 HARD_PWM_STATE_GUARD_ENABLE?

以下APP功能是做什么用的?

APP_PWM_Unmap_Selected_Fault
APP_PWM_ClearFault_Safe
APP_PWM_禁用输出
APP_QTMR_Disable_Low_OFLAG_Output
APP_StateGuard_Reset
APP_PWM_SelectPrescaler_FromPeriodCnt400M
APP_PwmModuleMask

此致,
巴勃罗

Re: RT1176 PWM startup failed

感谢你的回复。我使用的 GPIO 引脚是 rt1176 的 GPIO_EMC_B1_29。“axis_ctrl_t”是与电机轴相关的定义。

* PWM 输出脉冲 -> 触发 XBAR 信号 -> 脉冲下降沿驱动 QTMR 的外部时钟输入 ->
* QTMR 32 位级联计数器递减 1 -> 当计数器达到 0 时,触发 QTMR 比较中断 -> 中断内部关闭 PWM
* 同时,QTMR 触发硬件故障,直接拉低 PWM 的物理输出引脚。。ID= AXIS_Y,
。姓名= "Y", /* 用于串口日志记录或断点调试,以识别 Y 轴 */
/* ================= PWM 输出资源分配 ================= */
.pwmBase= PWM3, /* Y轴使用FlexPWM3模块 */
.pwm模块= kPWM_Module_0, /* 使用 PWM3 的子模块 0(每个 PWM 有 4 个子模块,编号从 0 到 3) */
.pwm通道= kPWM_PwmA, /* 使用子模块 0 的 A 相输出引脚,对应于物理引脚 GPIO_EMC_B1_29 */
/* ================= 32 位 QTMR 级联计数资源分配 ================= */
.tmrBase= TMR3, /* Y轴使用QTMR3外设(对应于IRQ中断号TMR3_IRQn) */
低= kQTMR_Channel_0, /* 16 位低计数器:使用 TMR3 的通道 0 */
.highCh= kQTMR_Channel_1,/* 16 位高位计数器:使用 TMR3 的通道 1 */
/* .lowCh 和 .highCh它们成对出现,在硬件层面上,它们会自动组合成一个 32 位计数器。
/* ================= 硬件级联时钟源配置(核心关键) ================= */ .tmrInputsrc=kQTMR_ClockCounter0InputPin,
/* 通道 0 的时钟源:设置为“外部引脚输入 0”。
在 XBAR 配置中,PWM3 脉冲的下降沿通过 XBAR 连接到 TMR3 通道 0 的输入引脚。
因此,每次 PWM 输出脉冲时,通道 0(16 位)将执行一次减量操作。*/

.cascadePcs = 4U,
/* 高 16 位通道(通道 1)的时钟源 (PCS) 配置。
在 i.MX RT 的 QTMR 寄存器中,PCS 值对应如下:
0-3 = 外部引脚输入;
4 = 通道 0 的溢出/终止事件;
5 = 通道 1 的溢出/终止事件;
6 = 通道 2 的溢出/终止事件;
7 = 通道 3 的溢出/终止事件。
这里配置为 4U,意思是:让“TMR3 的通道 1”监测“TMR3 的通道 0 的溢出事件”。

已启用 HARD_PWM_LOW_START_PHASE_ENABLE 和 HARD_PWM_STATE_GUARD_ENABLE。APP_PWM_Unmap_Selected_Fault

功能:移除与当前轴对应的故障引脚映射。调用底层 PWM_SetupFaultDisableMap 函数来禁用故障。目的是为了:在不需要硬件故障的情况下,防止意外的外部干扰导致 PWM 关闭,从而方便底层调试过程。
APP_PWM_ClearFault(原始代码函数)
功能:清除 PWM 模块的故障状态标志(axis->pwmBase->FSTS)。触发硬件故障后,必须先清除此标志,然后才能允许 PWM 重新启动。
APP_PWM_禁用输出

功能:立即停止 PWM 定时器,强制引脚输出低电平(PWM_SetPwmForceOutputToZero),并启用输出。它的目的是确保在电机启动之前,引脚不会因为浮空或处于默认状态而输出高电平,这可能会导致电机运动不规则。
APP_QTMR_Disable_Low_OFLAG_Output

功能:禁用 QTMR 的 OFLAG(状态标志)输出,并强制 OFLAG 处于低电平。它与 XBAR 硬件配合使用,其作用是切断 QTMR 输出到 PWM 故障引脚的路径,防止在启动前意外触发故障。
APP_StateGuard_Reset

功能:清除国家卫队(看门狗)的计数器和旗帜。如果启用 HARD_PWM_STATE_GUARD_ENABLE 时系统遇到长时间无脉冲变化或死锁,则此功能用于在停止或重新启动系统之前重置这些保护变量。
APP_PWM_SelectPrescaler_FromPeriodCnt400M

功能:这是一个非常核心的底层频率计算函数。它接收高电平 + 低电平的总 400MHz 计数值,并计算应设置多少个预分频器 (PRSC) 和 PWM 周期 (PERIOD) 才能放入 16 位 PWM 寄存器中。请注意:如果计算出的周期超过 65535 且除法系数超出范围,则此函数将返回 false,导致电机无法启动。
APP_PwmModuleMask

功能:将 PWM 子模块的索引号(例如,值为 0 的 kPWM_Module_0)转换为左移 N 位的位掩码。NXP 的许多 PWM 寄存器(例如 OUTEN、MCTRL)都是逐位控制的。该函数负责生成正确的二进制掩码。

タグ(1)
評価なし
バージョン履歴
最終更新日:
2 週間前
更新者: