1

我想同时在 ST2M32F103REY Cortex M3 上使用通用定时器的溢出、比较匹配和捕获功能。CC1 配置为比较匹配,CC3 配置为捕获。IRQ 处理程序如下所示:

void TIM3_IRQHandler(void) {
  if(TIM3->SR & TIM_SR_UIF){
      TIM3->SR &= ~TIM_SR_UIF;
      // do something on overflow
  }

  if(TIM3->SR & TIM_SR_CC1IF) {
     TIM3->SR &= ~TIM_SR_CC1IF;
     // do something on compare match
  }

  if(TIM3->SR & TIM_SR_CC3IF) {
     TIM3->SR &= ~TIM_SR_CC3IF;
     // do something on capture
  }
}

原则上,它工作得很好,但有时似乎跳过了一部分。我的理论是,这是因为重置 IRQ 标志的操作,例如TIM3->SR &= ~TIM_SR_UIF,不是原子的*,因此可能会发生例如在加载和存储之间发生的 TIM_SR_CC1IF 被覆盖的情况。

* 指令的反汇编如下

8012e02:    8a13        ldrh    r3, [r2, #16]
8012e06:    f023 0301   bic.w   r3, r3, #1
8012e0a:    041b        lsls    r3, r3, #16
8012e0c:    0c1b        lsrs    r3, r3, #16
8012e0e:    8213        strh    r3, [r2, #16]
  • 这合理吗?TIM3->SR寄存器的内容可以在IRQ处理程序执行过程中改变吗?
  • 是否有可能对 TIM3->SR 寄存器进行原子读写?
  • 还有其他合适的解决方案吗?

顺便说一句:有一个类似的问题,但问题是关于保护多个进程或内核的访问,而不是保护软件和硬件的同时访问。

4

1 回答 1

2

参考手册(CD00171190)的第15.4.5节规定所有位在rc_w0模式下工作(或保留)。TIMx->SR

根据编程手册(PM0056):

读取/清除 (rc_w0):软件可以通过写入 0 读取和清除该位。写入“1”对位值没有影响。

这意味着您可以简化代码以完全避免读取-修改-写入循环,而只需使用TIM3->SR = ~TIM_SR_UIF

许多应用笔记使用 read-modify-write 来清除中断,例如 Keil 的示例,但正如您所经历的那样,这是不必要的并且具有潜在的危险。在 ST 应用笔记DM00236305(第 1.3.2 节)中,仅使用了写操作。

但是请注意,在使用NVIC时,用于重置的寄存器是rc_w1

于 2016-12-20T08:33:39.330 回答