i.MX 7Dual平台Flextimer(FTM)多中断标志位C语言处理方案问询
i.MX 7D FTM 共享中断问题解决方案
同模块多中断标志的处理方法
共享同一ISR的多个中断不需要硬件优先级支持,用软件快照+自定义处理优先级即可解决,核心逻辑如下:
- 进入ISR后第一时间一次性读取所有中断标志寄存器和当前计数值,后续所有逻辑都基于刚读取的快照值处理,不要中途再次读取硬件寄存器,避免处理过程中硬件标志更新导致遗漏。
- 软件自定义处理优先级,优先处理溢出中断,再处理脉冲捕获中断,避免计算捕获值时漏掉溢出计数。
示例代码如下:
// 全局溢出计数,需定义为volatile避免编译器优化 volatile uint32_t g_ftm_overflow_cnt = 0; void FTM0_IRQHandler(void) { // 一次性快照所有需要的寄存器值 const uint32_t ftm_status = FTM0->STATUS; const uint16_t ftm_cnt = FTM0->CNT; // 优先处理溢出中断 if (ftm_status & FTM_STATUS_TOF_MASK) { // i.MX FTM寄存器标志位为写1清0 FTM0->STATUS = FTM_STATUS_TOF_MASK; g_ftm_overflow_cnt++; } // 处理脉冲捕获中断(这里假设用通道0做捕获) if (ftm_status & FTM_STATUS_CH0F_MASK) { FTM0->STATUS = FTM_STATUS_CH0F_MASK; // 拼接得到完整的32位计数值,不会出现偏小的问题 const uint32_t total_cnt = ((uint32_t)g_ftm_overflow_cnt << 16) | ftm_cnt; // 后续脉冲数量计算逻辑用total_cnt即可 } }
主循环读计数值的临界区防护
如果你需要在中断外读取定时器计数值,需增加简单的临界区防护,避免读的过程中触发溢出:
uint32_t ftm_get_total_count(void) { uint32_t ovf_cnt; uint16_t cnt; // 关中断仅持续几个寄存器操作,耗时不足1us,不影响实时性 __disable_irq(); cnt = FTM0->CNT; ovf_cnt = g_ftm_overflow_cnt; // 额外校验:如果读完成后刚好触发了溢出且计数值偏小,补上溢出计数 if ((FTM0->STATUS & FTM_STATUS_TOF_MASK) && cnt < 0x8000) { ovf_cnt++; } __enable_irq(); return (ovf_cnt << 16) | cnt; }
新增定时器的可行性
不需要更换更长位宽的定时器,新增定时器完全可以解决问题:
- 如果有空闲FTM模块,可以把定时功能和脉冲捕获功能拆分到两个独立FTM,各自用独立ISR,完全避免冲突
- 也可以用两个16位定时器级联组成32位定时器,硬件自动累加溢出,不需要软件处理溢出中断,完全规避软件漏计溢出的问题
额外优化建议
如果没有多余定时器,还可以通过以下方式降低溢出频率减少出错概率:
- 调整FTM预分频系数,在满足脉冲检测精度要求的前提下降低计数时钟频率,比如预分频设为8,16位定时器的溢出间隔可以从800ns级提升到ms级
- 直接读取FTM通道的捕获锁存寄存器而非实时计数寄存器,i.MX 7D的FTM在捕获触发时会自动锁存当前计数值到通道寄存器,读取锁存值不会出现中途计数变化的问题
内容的提问来源于stack exchange,提问作者D0z1
相关产品推荐
相关产品推荐

