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>
谁能解释一下为什么这个宏是这样写的?!?...
试图了解 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>