1.问题背景
软件:SDK1_4_1版本及之前版本
硬件:YTM32B1系列
问题描述:
29f7e312-1bdd-4491-87e8-1dc050315286-image.png
执行软件触发mask更新操作时,偶发出现 PWM 通道波形无变化,写入的 CHMASK 值未生效
2. 问题分析
2.1 代码分析
2.1.1 chmask软件触发更新驱动代码
eTMR_DRV_SetChnOutMask() 根据 softwareTrigger 选择 CHMASK 的加载方式。软件触发分支会暂存原有加载配置,设置软件触发源,写入新的 CHMASK 值并触发加载,最后恢复原配置;另一分支则随寄存器同步加载。
status_t eTMR_DRV_SetChnOutMask(uint32_t instance, uint8_t maskEn, uint16_t maskVal, bool softwareTrigger)
{
DEV_ASSERT(instance < eTMR_INSTANCE_COUNT);
eTMR_Type *etmrBase = g_etmrBase[instance];
etmr_sync_trig_src_t trigSrc;
etmr_mask_sync_sel_t opportunity;
eTMR_ClearLdok(etmrBase);
if (softwareTrigger)
{
/* keep mask loading trigger source */
trigSrc = (etmr_sync_trig_src_t)eTMR_GetMaskLoadTrigSrc(etmrBase);
/* keep mask loading opportunity */
opportunity = (etmr_mask_sync_sel_t)eTMR_GetMaskLoadOpportunity(etmrBase);
/* select CHMASK loading trigger source */
eTMR_SetMaskLoadTrigSrc(etmrBase, SW_TRIGGER);
/* select CHMASK loading opportunity */
eTMR_SetMaskLoadOpportunity(etmrBase, CHMASK_SYNC_WITH_TRIG);
}
else // sync with register loading
{
/* select CHMASK loading trigger source */
eTMR_SetMaskLoadTrigSrc(etmrBase, DISABLE_TRIGGER);
/* select CHMASK loading opportunity */
eTMR_SetMaskLoadOpportunity(etmrBase, CHMASK_SYNC_WITH_REG);
}
/* set channel Mask enable and value */
eTMR_SetChnOutMask(etmrBase, maskVal, maskEn);
/* set ldok */
eTMR_SetLdok(etmrBase);
if (softwareTrigger)
{
/* generate one bus clock cycle pulse trigger */
eTMR_GenSoftwareTrigger(etmrBase, true);
/* restore CHMASK loading trigger source */
eTMR_SetMaskLoadTrigSrc(etmrBase, trigSrc);
/* restore CHMASK loading opportunity */
eTMR_SetMaskLoadOpportunity(etmrBase, opportunity);
}
return STATUS_SUCCESS;
}
2d4f461f-3243-4d04-b11e-76ced0fcd753-image.png
2.1.2 软件触发路径的寄存器写入顺序
在 softwareTrigger 为 true 的分支中,与 CHMASK 加载直接相关的寄存器写入可概括为以下四步:
① eTMR0->SYNC |= CLDOK; // 清 LDOK,锁定本次加载
② eTMR0->CHMASK = ...; // 写入新值(暂存 buffer)
③ eTMR0->SYNC |= LDOK; // 置 LDOK,允许加载
④ eTMR0->SYNC |= SWTRIG; // 软件触发,将 CHMASK 从 buffer 载入输出
LDOK 是"加载许可"标志:只有 LDOK=1 时,软件触发才能将 CHMASK buffer 载入实际输出。一次加载完成或到达 MOD 加载点后,硬件自动将 LDOK 清零。
2.1.3 失效场景的 SYNC 配置:
在本次失效场景中,软件触发已启用(softwareTrigger=true),SYNC 寄存器的相关位域如下:
SYNC 寄存器位域
配置值
含义
REGLD[7:6]
0x01
REG 寄存器(VAL0/VAL1/MOD 等)在 CNT 到达 MOD 点时加载
MASKLD[15:14]
0x01
CHMASK 寄存器仅在触发源到来时加载
TRIGS2[13:12]
0x01
CHMASK 加载触发源 = 软件触发(写SYNC[16] SWTRIG)
关键点:REGLD[7:6]=01(MOD 同步),MASKLD[15:14] =01(触发同步)。这意味着 MOD 点会加载 REG 并清零 LDOK[0],但不会加载 CHMASK(CHMASK 只等 SWTRIG[16] 软件触发)。
2.2 问题原因
9a2c7c57-b28a-443d-857d-e33ac8266b38-image.png
正常段: SWTRIG 发生在 CNT 到达 MOD 之前。此时 LDOK 仍为 1,缓冲区中的 CHMASK 新值随软件触发加载为生效值,输出开始使用新掩码;本次加载完成后 LDOK 清零。
失效段: 置位 LDOK 后,CNT 先到达 MOD。该时刻 REG 按配置加载并清零 LDOK,而配置为触发加载的 CHMASK 仍停留在缓冲区。随后 SWTRIG 到来时 LDOK 已为 0,新的 CHMASK 不能成为生效值,输出继续使用旧掩码。
3. 规避方案
3.1 修复方案:合并 LDOK 与 SWTRIG 写操作(最小改动,推荐优先实施)
d7a7bf05-6e61-4211-9443-6222b205c79b-image.png
优点:改动最小,消除 CPU 周期级竞态窗口
局限:理论上仍存在硬件内部 LDOK 置位与 SWTRIG 处理之间的极短窗口(纳秒级),实际几乎不可触发
3.2 修复方案波形测试记录
c085020d-868f-4c44-a2fa-7888f43ba10b-image.png
3.3 测试例程