RT1176 PWM startup failed

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

RT1176 PWM startup failed

183 Views
liu626
Contributor I

I am using PWM + fault + QTimer to implement motor pulse control, but the PWM3 submodule 0 PWM_A channel occasionally fails to start, where after the first high level it remains constant and subsequent pulses do not appear.After the inspection, it was found that the "run" bit of the pwm was not correctly set. Even though repeated startup operations were added in the program later, this anomaly still occurred.

liu626_0-1782287927569.png

 

0 Kudos
Reply
2 Replies

112 Views
Pablo_Ramos
NXP Employee
NXP Employee

Hi @liu626,

Are you using a custom board or an EVK? If you are using the EVK, did you make any rework to it?

Could you share the configuration you are using for PWM3?

Are you using an example as a reference? If so, which one?

If you try to replicate the issue using a project with only PWM3, does the problem persist?

Does this only happen with PWM3 submodule 0 PWM_A channel? Has this occurred on other PWM modules or submodules?

Is there any other task or interrupt that manipulates PWM3 registers and could affect or overwrite the run bit?

Best Regards,
Pablo

0 Kudos
Reply

93 Views
liu626
Contributor I
hi,I used a custom circuit board. I didn't refer to any examples. This was a problem that was discovered during the official development of the project. I configured six PWM channels for pulse control. Only this channel had problems, while no such issue occurred on the other sub-modules. I checked and found that only this channel was using the PWM3 module. No other interfering factors were detected. Below is my configuration.
static 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,
.faultNum = 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,
.faultNum = 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,
.faultNum = 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,
.faultNum = 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,
.faultNum = 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,
.faultNum = 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.enableCombinationalPath = false;
faultConfig.faultClearingMode = kPWM_ManualSafety;
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;
faultFilter.faultFilterPeriod = 255U;
faultFilter.faultFilterCount = 7U;
faultFilter.faultGlitchStretch = false;

/* 记录每个 PWM 实例上已配置的 fault channel,避免重复设置 */
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 实例的每个 fault channel 只设一次) */
{
uint16_t *faultDone;
if (ax->pwmBase == PWM1) faultDone = &pwm1FaultDone;
else if (ax->pwmBase == PWM2) faultDone = &pwm2FaultDone;
else if (ax->pwmBase == PWM3) faultDone = &pwm3FaultDone;
else faultDone = &pwm4FaultDone;

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

/* Fault 时输出低电平 */
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);

if (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);
EnableIRQ(TMR1_IRQn);
EnableIRQ(TMR2_IRQn);
EnableIRQ(TMR3_IRQn);
}static bool APP_PWM_Config_Pulse(axis_ctrl_t *axis,
uint32_t highCnt400M,
uint32_t lowCnt400M)
{
pwm_clock_prescale_t prescale;
uint16_t periodTicks;
uint32_t totalCnt400M = highCnt400M + lowCnt400M;

if ((axis == NULL) || (totalCnt400M == 0U)) return false;
if (!APP_PWM_SelectPrescaler_FromPeriodCnt400M(totalCnt400M, &prescale, &periodTicks))
return false;

uint32_t highTicks32 = (uint32_t)(((uint64_t)periodTicks * (uint64_t)highCnt400M +
((uint64_t)totalCnt400M / 2ULL)) /
(uint64_t)totalCnt400M);
if (highTicks32 == 0U) highTicks32 = 1U;
if (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;
if (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;
if (desiredLeadCnt400M < minLeadCnt400M) desiredLeadCnt400M = minLeadCnt400M;

uint32_t desiredLeadTicks32 = (uint32_t)(((uint64_t)periodTicks * (uint64_t)desiredLeadCnt400M +
((uint64_t)totalCnt400M / 2ULL)) /
(uint64_t)totalCnt400M);
if (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);
if (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;
if (maxRiseByHalfTicks32 >= desiredLeadTicks32)
{
selectedRiseTicks32 = desiredLeadTicks32;
if (selectedRiseTicks32 > maxRiseByHalfTicks32)
selectedRiseTicks32 = maxRiseByHalfTicks32;
}
else if (maxRiseByPostGuardTicks32 >= desiredLeadTicks32)
{
selectedRiseTicks32 = desiredLeadTicks32;
if (selectedRiseTicks32 > maxRiseByPostGuardTicks32)
selectedRiseTicks32 = maxRiseByPostGuardTicks32;
}
else
{
selectedRiseTicks32 = maxRiseByPostGuardTicks32;
}

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

if (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(prescale);
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);
if (axis->pwmChannel == kPWM_PwmA) {
axis->pwmBase->SM[axis->pwmModule].VAL2 = riseTicks;
axis->pwmBase->SM[axis->pwmModule].VAL3 = fallTicks;
} else if (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;
return true;
}
0 Kudos
Reply