问题描述
我正在尝试将计时器 (TIM9) 及其中断处理程序配置为单步执行程序。我的方法是先中断第一条指令,然后在中断处理程序中配置定时器,使其在从 ISR 返回后立即触发中断。
现在我仍在努力正确地迈出第一步。
这是我现在正在使用的一段示例代码。我已将计时器配置为在其计数器等于某个比较值时生成中断。 我将比较值设置为等于 1,以便代码在定时器的 1 个周期后中断。根据参考手册,计数器在设置使能位后开始计数 1 个周期,所以我添加了一个 nop。
/*
* TIM9 is configured to generate an interrupt when counter s equal to compare value
*/
TIM9->CCR1 = 1; // set compare 1 value to 1
TIM9->CR1 |= 1; // enable TIM9
__ISB(); // flush pipeline
__asm volatile ("nop"); // from reference manual: counter starts counting 1 cycle after setting CEN bit
__asm volatile("MOV r8,#1 \n\t"); // expect to interrupt this instruction
__asm volatile("MOV r8,#2 \n\t");
__asm volatile("MOV r8,#3 \n\t");
__asm volatile("MOV r8,#4 \n\t");
为了验证正确的指令被中断了我在进入中断处理程序后使用GDB检查寄存器r8的内容,我发现它实际上等于6。这意味着延迟比1个周期长得多或者我只是错过了一些东西。
我可以简单地在第一条 MOV 指令之前添加 5 个 nop 指令,以便在正确的时间发生中断,但我不明白为什么这是必要的。据我所知,我现在拥有的代码应该会在第一条 MOV 指令期间产生一个中断。
为什么我会出现这种行为?为什么在启用定时器和产生中断之间似乎有这么长的延迟?
这是否可能是因为计数器值等于比较值与中断的实际生成之间存在延迟?
或者这可能与管道的工作方式有关吗?
我已将定时器的预分频器设置为 0,并且没有发生内部时钟分频,因此定时器应具有与系统时钟相同的频率。
解决方法
我不知道你为什么要检查它。它可以正常工作。
- NOP 是增加延迟的最糟糕方式。它与 8 位 AVR 的 NOP 不同。它会立即从管道中冲洗掉,只能用作填充。
- CEN 后 1 个时钟表示一个定时器时钟,而不是 HCLK 时钟(它们可以相同)
- CCRx = 1 表示两个时钟。
- 如果您从 FLASH 运行 - 会添加等待状态
- 管道执行状态不容易确定。被打断的实际指令不一定是您实际想到的指令。中断的时间是确定的,但不是实际的指令。