ESP8266 硬件定时器,uS to ticks 奇怪的宏

ESP8266 hadrware timer, uS to ticks strange macro

谁能解释一下为什么这个宏是这样写的?!?...

试图了解 ESP8266 硬件定时器的工作原理,因为制造商没有提供太多数据,他们的示例只是意大利面条代码。

现在定时器就是定时器,只是根据它的硬件时钟计数(在 ESP8266 中计数为 0),在这种情况下是 APB/4 或 20 MHz。

TICKS 的 uS 应该这么简单:

ticks = uS * MHz

现在 Espressif 示例显示了一个宏,它基本上与上述相同,具体取决于幻数 0x35A... ???

魔法路径相当于:

ticks = uS/4 (no float, rounded dwn) * MHz * 4
        +
        us%4 * MHz

这是为什么?我错过了什么吗?

原版:

#define US_TO_RTC_TIMER_TICKS(t)          \
    ((t) ?                                   \
     (((t) > 0x35A) ?                   \
      (((t)>>2) * ((APB_CLK_FREQ>>4)/250000) + ((t)&0x3) * ((APB_CLK_FREQ>>4)/1000000))  :    \
      (((t) *(APB_CLK_FREQ>>4)) / 1000000)) :    \
     0)

现在破门而入,原来是:

#define US_TO_RTC_TIMER_TICKS(t)          
    (

    (t) ? ( // if t, ok for now

        // hmmm... magic number for a timer 0x35A or 858 dec  
        ((t) > 0x35A) ?

        ( // if greater than magic number

            ((t)>>2) * ((APB_CLK_FREQ>>4)/250000) + ((t)&0x3) * ((APB_CLK_FREQ>>4)/1000000)

            // t/4[uS] * 80 equivalent with t * 20 but with match round
            // Example
            // 103uS normal would be 103uS * 20 = 2060 (as count)
            //
            // 103/4 = 25 * 80 = 2000 + 3 * 20 = 2000 + 60 = 2060 
            // hmmm.. correct but why?

        )  :    
        (
            // if lower than MAGIC
            // t / period = count <=> t[uS] * freq[MHz] = count
            //
            // t * 20   this is understandable :) 
            // 
            ((t) *(APB_CLK_FREQ>>4)) / 1000000
        )


        ) :   0 



     )

这只是为了防止溢出。如果起始值大于 "not a magic number",则与 'clock frequency / 4' 的乘积会导致溢出。为防止这种情况,您可以先将数字除以四(按 bit-shifting 所以:'>> 2')但这会丢失低两位的分辨率,因为它们会丢失。所以把低两位分开再占。

你可以通过将 int 的最大值除以 APB_CLK_FREQ >> 4 得到幻数,即

(2 ^ 32 - 1) / ((80 * 10 ^ 6) / 16) = 858.99

我们将四舍五入为一个较低的值,因此我们可以直接处理的最大值是 858 或 0x35A。

我还想在抽搐方面纠正你。硬件定时器以 CPU 频率运行,hw_timer 源使用 16 的预分频器,但您可以修改源(需要一些努力 - 阅读 esp8266 技术手册中的寄存器定义)以使用1 或 256 的预分频器与 16 相距太远。

所以我们的抽搐是

us * 80 * 10 ^ 6 / <pre-scaler>