【问题标题】:Timer overflow race condition定时器溢出竞争条件
【发布时间】:2020-08-19 22:14:56
【问题描述】:

我正在使用一个带有 16 位定时器的微控制器。当前值可以从寄存器中读取。但是我需要一个 32 位计数器。每次定时器溢出,它都会产生一个中断。我当前的解决方案类似于下面的代码。每次计时器溢出时,变量counter_high 就会递增。当前计数器值被读取为counter_high 和定时器寄存器的组合。

volatile uint16_t counter_high = 0;

uint32_t get_counter(void)
{
    return (counter_high << 16) | timer->counter;
}

void timer_overflow(void)
{
    counter_high++;
}

这似乎有效。但是我开始想知道如果在执行get_counter() 时计时器溢出会发生什么?我可以得到counter_high 的旧值与timer-&gt;counter 的新值相结合,反之亦然。

是否有防止此问题的最佳做法?

【问题讨论】:

  • 你基本上是想读低,然后检查溢出。如果溢出然后调高并重新采​​样低,你应该是安全的。或者你可以根据你希望函数调用的哪一端最接近实时来设置低零。

标签: timer overflow microcontroller


【解决方案1】:

在阅读timer-&gt;counter 之前和之后阅读counter_high。如果counter_high 读取的值没有改变,那么您知道timer-&gt;counter 在读取之间没有翻转,因此您可以信任从timer-&gt;counter 读取的值。

但是,如果counter_high 在两次读取之间发生了变化,那么您知道timer-&gt;counter 在两次读取之间的某个时间发生了翻转。这意味着您不能信任从timer-&gt;counter 读取的值,因为您不知道您是在翻转之前还是之后读取它。但是现在您知道timer-&gt;counter 最近刚刚翻车,因此您可以再次阅读它并知道它不会再次翻车。

uint32_t get_counter(void)
{
    uint32_t first_counter_high = counter_high;
    uint32_t counter_low = timer->counter;
    uint32_t second_counter_high = counter_high;
    if (first_counter_high != second_counter_high)
    {
        counter_low = timer->counter;  // Read timer->counter again, after rollover.
    }
    return (second_counter_high << 16) | counter_low;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多