简体   繁体   English

STM32 32 位 ARM 架构上的系统时钟翻转

[英]System Tick rollover on STM32 32bit ARM architecture

Having trouble understanding what happens when the 32bit system tick on a STM32 MCU rolls over using the ST supplied HAL platform.无法理解当 STM32 MCU 上的 32 位系统滴答使用 ST 提供的 HAL 平台翻转时会发生什么。

If the MCU has been running until HAL_GetTick() returns its maximum of 2^32 -1 =0xFFFFFFFF which is 4,294,967,295 / 1000 / 60 / 60 / 24 = approx 49 days (when calculating the 1ms tick to the maximum duration that can be measured).如果 MCU 一直运行到 HAL_GetTick() 返回其最大值 2^32 -1 =0xFFFFFFFF 即 4,294,967,295 / 1000 / 60 / 60 / 24 = 大约 49 天(计算 1ms 滴答到可以测量的最大持续时间时)。 What happens if you have a timer that running across the rollover point?如果您有一个在翻转点上运行的计时器会发生什么?

Example code creating 100ms delay on a rollover event:在翻转事件上创建 100 毫秒延迟的示例代码:

uint32_t start = HAL_GetTick()  // start = 0xFFFF FFFF (in this example)

--> Interrupt increments systick which rolls it over to 0 at this point

while ((HAL_GetTick() - start) < 100);

So when the expression in the loop is first evaluated HAL_GetTick() = 0x0000 0000 and start = 0xFFFF FFFF.因此,当第一次评估循环中的表达式时,HAL_GetTick() = 0x0000 0000 和 start = 0xFFFF FFFF。 Hence 0x0000 00000 - 0xFFFF FFFF =?因此 0x0000 00000 - 0xFFFF FFFF =? (This number doesn't exist as it's negative and we are doing unsigned arithmetic) (这个数字不存在,因为它是负数,我们正在做无符号算术)

However when I run the following code on my STM32 that is compiled with the GCC ARM:但是,当我在使用 GCC ARM 编译的 STM32 上运行以下代码时:

   uint32_t a = 0xFFFFFFFFUL;
   uint32_t b = 0x00000000UL;
   uint32_t c = b - a;
   printf("a =%lu b=%lu c=%lu\r\n", a, b, c);

The output is: a =4294967295 b=0 c=1 output 为:a =4294967295 b=0 c=1

The fact that c=1 is good from the point of view of the code functioning properly across the overflow but I don't understand what is actually happening here at the low level.从代码在溢出中正常运行的角度来看,c=1 的事实很好,但我不明白在低级别实际发生了什么。 How does 0 - 4294967295 = 1?? 0 - 4294967295 = 1 怎么算? How would I calculate this on paper to show what the arithmetic logic unit inside the MCU is doing when this situation is encountered?当遇到这种情况时,我将如何在纸上计算以显示 MCU 内的算术逻辑单元在做什么?

This is a characteristic of modular arithmetic .这是模运算的一个特点。 Or modulo wrapping is what happens when an unsigned integer overflows .或者当无符号integer 溢出时会发生模换行。

When working with a fixed number of digits/bits, arithmetic operations can overflow the fixed number of digits.当使用固定位数/位时,算术运算可能会溢出固定位数。 But the overflow portion cannot be represented in the fixed number of digits/bits and is basically masked away.但是溢出部分不能用固定的位数/位数表示,基本上被屏蔽掉了。 The overflow portion can be considered a modulus and the portion within the fixed number of digits/bits is the remainder or modulo.溢出部分可以被认为是模数,固定位数/位内的部分是余数或模数。 Given the modulus, the modulo value remains correct/congruent after the operation that caused the overflow.给定模数,模值在导致溢出的操作之后保持正确/一致。

The best way to understand is to do a few operations with a pen on paper.最好的理解方法是用笔在纸上做一些操作。 Choose a base.选择一个基地。 Hexadecimal is great but it works for decimal, binary, and every base.十六进制很好,但它适用于十进制、二进制和所有基数。 Choose a fixed number of digits/bits.选择固定数量的位数/位。 For uint32_t you have 8 hex digits or 32 bits.对于 uint32_t,您有 8 个十六进制数字或 32 位。 Choose two values that will overflow the fixed number of digits when you add them.选择两个在添加时会溢出固定位数的值。 Do the math on paper and include any overflow into an extra digit.在纸上做数学运算,并将任何溢出包含到一个额外的数字中。 Now perform the modulo operation by covering the overflow with your hand.现在通过用手覆盖溢出来执行模运算。 Your CPU does this modulo operation automatically by virtue of having a fixed number of digits (ie, uint32_t).您的 CPU 通过具有固定位数(即 uint32_t)自动执行此模运算。 Repeat this with different numbers and repeat with a subtraction/underflow.用不同的数字重复这个,然后用减法/下溢重复。 Eventually you'll start to trust that it works.最终你会开始相信它是有效的。

You do have to be careful when setting up this operation.设置此操作必须小心。 Use unsigned types and subtract the start ticks value from the current ticks value, like is done in your example code.使用无符号类型并从当前刻度值中减去起始刻度值,就像在您的示例代码中所做的那样。 (Do not, for example, add the delay to start ticks and compare with the current ticks.) Raymond Chen's article,Using modular arithmetic to avoid timing overflow problems has more information. (例如,不要添加延迟以开始滴答并与当前滴答进行比较。) Raymond Chen 的文章,使用模运算避免时序溢出问题有更多信息。

How does 0 - 4294967295 = 1?? 0 - 4294967295 = 1 怎么算? How would I calculate this on paper to show what the arithmetic logic unit inside the MCU is doing when this situation is encountered?当遇到这种情况时,我将如何在纸上计算以显示 MCU 内的算术逻辑单元在做什么?

First write it in hex like this:首先用十六进制写成这样:

     0000_0000
 -   FFFF_FFFF
 _____________
 

Then realize that there can be a modulus value of 0x1_0000_0000 on the first value (minuend).然后意识到在第一个值(被减数)上可以有一个模值 0x1_0000_0000。 (Because according to modular arithmetic, "0x0_0000_0000 and 0x1_0000_0000 are congruent modulo 0x1_0000_0000"). (因为根据模运算,“0x0_0000_0000 和 0x1_0000_0000 模 0x1_0000_0000 是全等的”)。 Then it should become obvious that the difference is 1.那么很明显,差异为 1。

   1_0000_0000
 - 0_FFFF_FFFF
 _____________
   0_0000_0001

Nothing bad will happen.不会有什么不好的事情发生。 It will work the same as before the wraparound.它将与环绕之前一样工作。

int main(void)
{
    uint32_t start = UINT32_MAX - 20;
    uint32_t current = start;

    for(uint32_t x = 0; x < 100; x++)
    {
        printf("start = 0x%08"PRIx32" current = 0x%08"PRIx32 " current - start = %"PRIu32"\n", start, current, current-start);
        current++;
    }
}

You can see it here: https://godbolt.org/z/jx4T4fhsW你可以在这里看到它: https://godbolt.org/z/jx4T4fhsW

0x00000000 - 0xffffffff will be 1 as 1 needs to be added to 0xffffffff to get 0x00000000. 0x00000000 - 0xffffffff 将为 1,因为需要将 1 添加到 0xffffffff 以获得 0x00000000。 Same with other numbers.与其他号码相同。

BTW it is much easier to understand if you use hex numbers instead of decimals which have very limited use in programming.顺便说一句,如果您使用十六进制数字而不是在编程中使用非常有限的十进制数字,则更容易理解。

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

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