繁体   English   中英

加速 AVR ISR

[英]speed up the AVR ISR

我想知道是否可以在不更改预分频器的情况下加快 ISR。 我有一个带有 2 个比较寄存器 A 和 B 的计时器。

COMPA 用于 22% 到 100% 左右的 PWM 输出。 这有一个固定的频率,我不能改变它至少不多。

现在我想使用速度大约是 4 倍但占空比为 50% 的固定 COMPB。

如果我在 TIMSK0 中为 attiny13 设置 OCIE0B 位,我可以执行以下操作来加快速度吗? 或者我在这里误解了什么?

ISR(TIM0_COMPB_vect){
    switch (timing){
        case 0:
            OCR0B = 63;
            PORTB ^= (1 << PB3);
            timing = 1;
            break;
        case 1:
            OCR0B = 127;
            PORTB ^= (1 << PB3);
            timing = 2;
            break;
        case 2:
            OCR0B = 191;
            PORTB ^= (1 << PB3);
            timing = 3;
            break;
        case 3:
            OCR0B = 255;
            PORTB ^= (1 << PB3);
            timing = 0;
            break;
    }
}

任何帮助表示赞赏。 谢谢:D

您可以通过创造性地使用普通模式来非常有效地做到这一点。

诀窍是设置预分频器以获得一个时钟周期,该时钟周期是您希望可变占空比 PWM 信号运行的两倍 因此,例如,如果您希望它以 1Mhz 进行 PWM,请将预分频器设置为 2Mhz。

假设可变占空比 PWM 在引脚 A 上,固定 50% 4x 时钟信号在引脚 B 上。(您也可以交换这些并更新代码,一切仍然有效)

  1. 为“On compare match B”和“Overflow”启用中断。

  2. 强制引脚A与强制比较匹配的高电平。 (或者,您可以跳过此步骤,而在步骤 7 中使用所需占空比的倒数)

  3. 将“A”的COM位设置为Toggle on match

  4. BCOM位保留为关闭。 假设您已将此引脚的 DDR 设置为普通 GPIO。

  5. BOCR设置为128

  6. 将 WGM 定时器模式设置为0 - “正常模式”。

  7. A的 OCR 设置为您想要的可变占空比。 请注意,您可能需要在此处针对0和/或255的极端值设置特殊情况,具体取决于您想要发生的情况(只需使用 GPIO 将引脚ONOFF )。

您可以随时重复第 6 步来更改A的占空比,它将在下一个TOP更新。

完成这些步骤后, A引脚将在预分频器时钟的 1/2 处输出所需的占空比, B将在预分频器时钟的 2 倍时输出 50% 的占空比(这是所需的A周期的 4 倍)。

这是 ISR 代码(请注意,我不确定在 attiny13 标头中调用的 TOV 向量[有时在 AVR 中有所不同],因此您可能必须编辑TIM0_OVF_vect名称)...

ISR(TIM0_COMPB_vect,TIM0_OVF_vect){
    PINB |= (1 << PB3);   // Compiles to a single cycle SBI
}

看看这是如何工作的?

请注意,在PIN寄存器中设置一个位实际上会切换PORT位。 这是数据表中记录的 AVR GPIO 的一个怪癖。

希望这足够快。 如果您真的想挤出最后一个周期,您甚至可以通过将 ISR 编译成的单个SBI指令直接放入带有尾随RETI的中断向量表中,从而从中断向量中节省 RJMP 的 2 个周期,但是这更复杂!

仅关注 C 代码方面,然后可以将其优化为:

ISR(TIM0_COMPB_vect)
{
  static const uint8_t OCR[4] = {63,127,191,255};
  OCR0B = OCR[timing];

  PORTB ^= 1u << PB3;

  timing++;
  if(timing==4)
    timing=0;
}

在 gcc AVR -O3 上反汇编(所有变量/寄存器都是易失的)这将指令数量从 ~50 减少到 ~20,因此它的速度大约是原来的两倍并且占用的内存更少。

如果您只想要所提供代码的最快等效版本,那么它就是...

ISR(TIM0_COMPB_vect){
    OCR0B += 64;
    PINB |= (1 << PB3);
}
  • OCR0B将每 4 遍溢出,这是定义的行为。 OCR0B初始化为一些非零数字(如1 )以避免边缘情况可能是明智的。
  • 这避免了所有变量和内存访问 - 只有寄存器访问。
  • 避免所有比较和分支。
  • 切换引脚的PINB方法编译为单个SBI指令,而不是 PUSH、加载、XOR、存储、POP 序列。

...但同样,如果它不起作用并且除非您使用两种“立即 OCR 更新”模式中的一种,否则这些都无关紧要,然后在计时器周期中间更新 OCR 将无效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM