System Tick rollover on STM32 32bit ARM architecture - c

Having trouble understanding what happens when the 32bit system tick on a STM32 MCU rolls over using the ST supplied HAL platform.
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).
What happens if you have a timer that running across the rollover point?
Example code creating 100ms delay on a rollover event:
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. Hence 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 :
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
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. How does 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?

This is a characteristic of modular arithmetic. Or modulo wrapping is what happens when an unsigned integer overflows.
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. 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 (i.e., 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.
How does 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?
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). (Because according to modular arithmetic, "0x0_0000_0000 and 0x1_0000_0000 are congruent modulo 0x1_0000_0000"). Then it should become obvious that the difference is 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
0x00000000 - 0xffffffff will be 1 as 1 needs to be added to 0xffffffff to get 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.

Related

Generating random 64/32/16/ and 8-bit integers in C

I'm hoping that somebody can give me an understanding of why the code works the way it does. I'm trying to wrap my head around things but am lost.
My professor has given us this code snippet which we have to use in order to generate random numbers in C. The snippet in question generates a 64-bit integer, and we have to adapt it to also generate 32-bit, 16-bit, and 8-bit integers. I'm completely lost on where to start, and I'm not necessarily asking for a solution, just on how the original snippet works, so that I can adapt it form there.
long long rand64()
{
int a, b;
long long r;
a = rand();
b = rand();
r = (long long)a;
r = (r << 31) | b;
return r;
}
Questions I have about this code are:
Why is it shifted 31 bits? I thought rand() generated a number between 0-32767 which is 16 bits, so wouldn't that be 48 bits?
Why do we say | (or) b on the second to last line?
I'm making the relatively safe assumption that, in your computer's C implementation, long long is a 64-bit data type.
The key here is that, since long long r is signed, any value with the highest bit set will be negative. Therefore, the code shifts r by 31 bits to avoid setting that bit.
The | is a logical bit operator which combines the two values by setting all of the bits in r which are set in b.
EDIT:
After reading some of the comments, I realized that my answer needs correction. rand() returns a value no more than RAND_MAX which is typically 2^31-1. Therefore, r is a 31-bit integer. If you shifted it 32 bits to the left, you'd guarantee that its 31st bit (0-up counting) would always be zero.
rand() generates a random value [0...RAND_MAX] of questionable repute - but let us set that reputation aside and assume rand() is good enough and it is a
Mersenne number (power-of-2 - 1).
Weakness to OP's code: If RAND_MAX == pow(2,31)-1, a common occurrence, then OP's rand64() only returns values [0...pow(2,62)). #Nate Eldredge
Instead, loop as many times as needed.
To find how many random bits are returned with each call, we need the log2(RAND_MAX + 1). This fortunately is easy with an awesome macro from Is there any way to compute the width of an integer type at compile-time?
#include <stdlib.h>
/* Number of bits in inttype_MAX, or in any (1<<k)-1 where 0 <= k < 2040 */
#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
#define RAND_MAX_BITWIDTH (IMAX_BITS(RAND_MAX))
Example: rand_ul() returns a random value in the [0...ULONG_MAX] range, be unsigned long 32-bit, 64-bit, etc.
unsigned long rand_ul(void) {
unsigned long r = 0;
for (int i=0; i<IMAX_BITS(ULONG_MAX); i += RAND_MAX_BITWIDTH) {
r <<= RAND_MAX_BITWIDTH;
r |= rand();
}
return r;
}

Reading bits serially in C

I am trying to convert a bit of code from Python to C. I have got it all working other than the section below. All the variables have been defined as ints. I believe the problem has to do with pointers and addresses but I can't work it out.
for(j=0; j<12; j++)
{
digitalWrite(CLOCK, 1);
sleep(0.001);
bit = digitalRead(DATA_IN);
sleep(0.001);
digitalWrite(CLOCK, 0);
value = bit * 2 ** (12-j-1); // error
anip = anip + value;
printf("j:%i bit:%i value:%i anip:%i", j, bit, value, anip);
}
The error is invalid type argument of unary β€˜*’ (have β€˜int’)
C has no exponentiation operator, which is what I guess you do ** for.
You can use e.g. pow if it's okay to typecast the result from a floating point value back to an integer.
In C, 1<<i is the best way to raise i to the power of 2.
Do not use ints for bit manipulation, because they vary in size by platform. Use uint32_t from /usr/include/stdint.h.
The sleep() function takes an integer argument and waits for the specified number of seconds. The argument 0.001 becomes 0, which is probably not what you want. Instead, try usleep(), which takes an argument that represents milliseconds.
The other answers will solve the generic problem of raising an arbitrary number to a power, or to a power of 2, but this is a very specific case.
The purpose of the loop is to read 11 bits serially from MSB to LSB and convert them into an integer. The implementation you've shown attempts to do this by reading a bit, shifting it to the correct position, and accumulating the result into anip. But there's an easier way:
anip = 0;
for (j=0; j<12; ++j) {
// Pulse the CLOCK line and read one bit, MSB first.
digitalWrite(CLOCK, 1);
usleep(1);
bit = digitalRead(DATA_IN);
usleep(1);
digitalWrite(CLOCK, 0);
// Accumulate the bits.
anip <<= 1; // Shift to make room for the new bit.
anip += bit; // Add the new bit.
printf("j:%i bit:%i anip:%i", j, bit, anip);
}
As an example, suppose the first 4 bits are 1,0,0,1. Then the output will be
j:0 bit:1 anip:1
j:1 bit:0 anip:10
j:2 bit:0 anip:100
j:3 bit:1 anip:1001
When the loop completes, anip will contain the value of the entire sequence of bits. This is a fairly standard idiom for reading data serially.
Although the advice to use uint32_t is generally appropriate, the C standard defines int to be at least 16 bits, which is more than the 12 you need (including the sign bit, if anip is signed). Moreover, you're probably writing this for a specific platform and therefore aren't worried about portability.

can someone explain this code - rtc roll over with bitwise (in c)?

can anyone explain this ((~(preRtcInseconds <<1)+1)>>1)
unsigned long preInseconds;
unsigned long curInSeconds;
unsigned long elapsedInSeconds;
if(curInSeconds>=preInseconds)
{
elapsedInSeconds = curInSeconds - preInseconds;//does easy thing. no needs roll over
}
else{ //rollover
preInseconds = ((~(preInseconds <<1)+1)>>1);
elapsedInSeconds = curInSeconds + preInseconds;
}
Let the width of unsigned long be w. Then the maximal value an unsigned long can hold is
ULONG_MAX = 2^w - 1
Let preInseconds = a + b, where
a = preInseconds & (1ul << (w-1))
b = preInseconds & ((1ul << (w-1)) - 1)
a is either 0 or 2^(w-1), depending on whether preInseconds >= 2^(w-1). Then the initial left shift annihilates a, so
preInseconds << 1
gives b << 1 or 2*b.
Then the bitwise complement is taken,
~(b << 1)
gives ULONG_MAX - (b << 1).
If b == 0, adding 1 to ULONG_MAX - (b << 1) results in 0, otherwise
~(b << 1) + 1
gives
2^w - (b << 1)
Then shifting one bit to the right produces 0 if b == 0 and
2^(w-1) - b
otherwise. Hence
preInseconds = ((~(preInseconds <<1)+1)>>1);
sets preInseconds to
2^(w-1) - b
if b != 0, and to 0 if b == 0.
Finally,
elapsedInSeconds = curInSeconds + preInseconds;
therefore sets elapsedInSeconds to the value of curInSeconds if preInseconds was 2^(w-1) [if the else branch is taken, preInseconds > curInSeconds, so it's not 0] and to
curInSeconds - (preInseconds & (ULONG_MAX >> 1)) + 2^(w-1)
otherwise.
I'm not sure what the purpose of that operation is. For preInseconds > curInSeconds, the computation
curInSeconds - preInseconds
would result in
(2^w - preInseconds) + curInSeconds
which is the same as (mathematically)
(2^w + curInSeconds) - preInseconds
which would be the elapsed time if the curInSeconds counter rolled over once since the last time preInseconds was taken, which presumably happened if the current counter value is smaller than the previous. That would make sense.
With the gymnastics done in the else branch,
if preInseconds <= 2^(w-1), elapsedInSeconds becomes curInSeconds - preInseconds + 2^(w-1), the difference between the rolled-over current counter and the previous counter minus 2^(w-1)
if preInseconds > 2^(w-1), since x - 2^(w-1) == x + 2^(w-1) in unsigned arithmetic, we obtain the same result as with curInSeconds - preInSeconds.
So, assuming curInSeconds rolled over once, it calculates the elapsed seconds between the previous and current event, unless the roll-over took place 2^(w-1) or more seconds after the previous event, in which case 2^(w-1) seconds are subtracted from the actual elapsed time.
It looks like buggy rollover code written by someone who doesn't understand that C unsigned arithmetic is mod 2^n (or doesn't understand mod 2^n arithmetic.) It is in fact exactly equivalent to:
elapsedInSeconds = curInSeconds - preInseconds;
if (curInSeconds < UNLONG_MAX/2 && preInseconds < ULONG_MAX/2)
elapsedInSeconds &= ULONG_MAX/2;
That is, it does a mod 2^n subtraction, but in a few cases (that were probably never hit in any test case), it gets to top bit wrong (clear instead of set).
It is vaguely possible that this is intentional, since what is going on here is that it does a mod 2^n-1 subtraction if both numbers are <2^n-1 and a mod 2^n subtraction if either number is >= 2^n-1 (where n is the size of an unsigned long in bits). If the times are coming from some hardware device which might be always clearing the top bit or might not, this might make sense.
First of all, everything in my discussion below assumes that your unsigned long type is 32 bits wide. If it's not, that's OK; it doesn't really matter how wide it is, but all my examples assume it's 32 bits wide. And I simply use uint32 to denote that, knowing that uint32 isn't actually a standard type like uint32_t, please don't bother telling me that.
Daniel Fischer has done a fine job of explaining each low-level operation in detail, and I won't repeat that here. But I think what you're interested in isn't so much the meaning of each of the low-level operations as much as the necessity of all of those operations applied as a group. Which as I'll explain below, aren't necessary anyway. In fact, they're slightly wrong, but only in the case that the "current" counter reading is more than halfway back around the circle to the "previous" reading.
Before I get to the "meaning" behind the mathematics of your implementation, let's first just look at a trivial example of how it computes elapsedInSeconds in the case of the smallest rollover possible:
If preInseconds = 0xffffffff and curInSeconds = 0x00000000, elapsedInSeconds should be 1.
preInseconds = preInseconds<<1; // 0xfffffffe
preInseconds = ~preInseconds; // 0x00000001
preInseconds = preInseconds+1 // 0x00000002
preInseconds = preInseconds>>1; // 0x00000001
elapsedInSeconds = curInSeconds + preInseconds;
... = 0x00000000 + 0x00000001 = 1
...which is exactly what we expect. Great.
However, the interesting thing is that none of the rollover handling logic is necessary. At all. Every time I've ever seen someone try to calculate the difference between a 'current' and 'previous' counter value, I always see them jumping through hoops to handle the rollover case, and more often than not they do it wrong. The shame of the situation is that handling the rollover with a special case is never necessary for power-of-2-sized counters. If the counter's full scale (point at which it rolls over) is smaller than the size of your data type, you'd need to mask the result back to the number of bits in the counter, but that's the only rollover handling you really ever need, and in that case you'd just do the masking every time without worrying whether it rolled over or not (which also avoids branch instructions so it's faster). Since your rollover point is the full-scale value of a uint32, you don't even need to mask the result.
Here's why:
Assume, as above, that preInseconds=0xffffffff and curInSeconds=0. Again, the result should be 1. If you weren't concerned about rollover, you'd just take curInSeconds-preInseconds as the result. But in the case of rollover, the subtract operation will produce an underflow. What does that mean? It means that if you had more bits that you were dealing with (i.e. another uint32 being used as the high word of a 64-bit compound counter), then you'd need to borrow 1 from the high word (just like grade-school subtraction with decimal numbers). But in your case, there's no higher word to borrow from. That's OK. Really. You don't care about those bits anyway. You still get the difference value you were looking for:
elapsedInSeconds = curInSeconds - preInseconds;
... = 0x00000000 - 0xffffffff = 1
...which gives the expected result without any special rollover handling logic at all.
And so you may be thinking, "Sure, that works for your trivial example, but what if the rollover is HUGE?" OK, well, let's explore that possibility. Assume then that preInseconds=0xffffffff and curInSeconds=0xfffffffe. In this example, we've ALMOST wrapped completely back around from the previous sample; in fact, we're only one count away from it. In this case, our result should be 0xffffffff (i.e. one less count than the number of values that can be represented by a uint32):
elapsedInSeconds = curInSeconds - preInseconds;
... = 0xfffffffe - 0xffffffff = 0xffffffff
Don't believe me? Try this:
#include <stdio.h>
typedef unsigned long uint32;
int main()
{
uint32 prev = 0xffffffff;
uint32 cur = 0xfffffffe;
uint32 result = cur - prev;
printf("0x%08x - 0x%08x = 0x%08x\n", cur, prev, result);
}
NOW, let's get back to the math behind your implementation:
That computation "sort of" computes the two's complement of preInseconds and assigns the result back to preInseconds. And if you know anything about computer representations of numbers and two's complement addition and subtraction, you know that computing the difference A-B is the same as computing the sum of A and the two's complement of B, i.e. A+(-B). If you've never investigated it before, look up on Wikipedia or wherever about how two's complement makes a computer's ALU able to re-use their addition circuitry for subtraction.
Now on to what's actually "wrong" with the code you've shown:
To compute the two's complement of a number, you invert the number (change all of its 0 bits to 1, and all of its 1 bits to 0), and then add one. It's that simple. And that's "sort of" what your code is doing, but not quite.
preInseconds = preInseconds<<1; // oops, here we lose the top bit
preInseconds = ~preInseconds; // do the 2's complement inversion step*
preInseconds = preInseconds+1 // do the 2's complement addition step*
preInseconds = preInseconds>>1; // shift back to where it ought to be,
// but without that top bit we wish we kept
*NOTE: The +1 above only works here because the low bit is
guaranteed to be 1 after the ~ operation, which carries a 1
up into the 2nd bit, where it matters.
So we see here that essentially what the math is doing is manually negating the value of preInseconds by performing a "nearly" two's complement conversion of it. Unfortunately it's also losing the top bit in the process, which makes the rollover logic only work up to a maximum of elapsedInSeconds = 0x7fffffff, not what should really be its full scale limit of 0xffffffff.
You could convert it to the following, and eliminate the loss of the top bit:
preInseconds = ~preInseconds; // do the 2's complement inversion step
preInseconds = preInseconds+1 // do the 2's complement addition step
So now you've computed the two's complement directly, and you can compute the result:
elapsedInSeconds = curInSeconds + preInseconds; // (preInseconds is the 2's compl of its original value)
But the silly thing is that this is computationally equivalent to simply doing this...
elapsedInSeconds = curInSeconds - preInseconds; // (preInseconds is its unconverted original value)
And once you realize that, your code example becomes:
if(curInSeconds>=preInseconds)
{
elapsedInSeconds = curInSeconds - preInseconds;
}
else // rollover
{
elapsedInSeconds = curInSeconds - preInseconds;
}
...which should make it clear that there's no need to handle rollover as a special case in the first place.

Homework - C bit puzzle - Perform % using C bit operations (no looping, conditionals, function calls, etc)

I'm completely stuck on how to do this homework problem and looking for a hint or two to keep me going. I'm limited to 20 operations (= doesn't count in this 20).
I'm supposed to fill in a function that looks like this:
/* Supposed to do x%(2^n).
For example: for x = 15 and n = 2, the result would be 3.
Additionally, if positive overflow occurs, the result should be the
maximum positive number, and if negative overflow occurs, the result
should be the most negative number.
*/
int remainder_power_of_2(int x, int n){
int twoToN = 1 << n;
/* Magic...? How can I do this without looping? We are assuming it is a
32 bit machine, and we can't use constants bigger than 8 bits
(0xFF is valid for example).
However, I can make a 32 bit number by ORing together a bunch of stuff.
Valid operations are: << >> + ~ ! | & ^
*/
return theAnswer;
}
I was thinking maybe I could shift the twoToN over left... until I somehow check (without if/else) that it is bigger than x, and then shift back to the right once... then xor it with x... and repeat? But I only have 20 operations!
Hint: In decadic system to do a modulo by power of 10, you just leave the last few digits and null the other. E.g. 12345 % 100 = 00045 = 45. Well, in computer numbers are binary. So you have to null the binary digits (bits). So look at various bit manipulation operators (&, |, ^) to do so.
Since binary is base 2, remainders mod 2^N are exactly represented by the rightmost bits of a value. For example, consider the following 32 bit integer:
00000000001101001101000110010101
This has the two's compliment value of 3461525. The remainder mod 2 is exactly the last bit (1). The remainder mod 4 (2^2) is exactly the last 2 bits (01). The remainder mod 8 (2^3) is exactly the last 3 bits (101). Generally, the remainder mod 2^N is exactly the last N bits.
In short, you need to be able to take your input number, and mask it somehow to get only the last few bits.
A tip: say you're using mod 64. The value of 64 in binary is:
00000000000000000000000001000000
The modulus you're interested in is the last 6 bits. I'll provide you a sequence of operations that can transform that number into a mask (but I'm not going to tell you what they are, you can figure them out yourself :D)
00000000000000000000000001000000 // starting value
11111111111111111111111110111111 // ???
11111111111111111111111111000000 // ???
00000000000000000000000000111111 // the mask you need
Each of those steps equates to exactly one operation that can be performed on an int type. Can you figure them out? Can you see how to simplify my steps? :D
Another hint:
00000000000000000000000001000000 // 64
11111111111111111111111111000000 // -64
Since your divisor is always power of two, it's easy.
uint32_t remainder(uint32_t number, uint32_t power)
{
power = 1 << power;
return (number & (power - 1));
}
Suppose you input number as 5 and divisor as 2
`00000000000000000000000000000101` number
AND
`00000000000000000000000000000001` divisor - 1
=
`00000000000000000000000000000001` remainder (what we expected)
Suppose you input number as 7 and divisor as 4
`00000000000000000000000000000111` number
AND
`00000000000000000000000000000011` divisor - 1
=
`00000000000000000000000000000011` remainder (what we expected)
This only works as long as divisor is a power of two (Except for divisor = 1), so use it carefully.

Overflow of 32 bit variable

Currently I am implementing an equation (2^A)[X + Y*(2^B)] in one of my applications.
The issue is with the overflow of 32 bit value and I cannot use 64 bit data type.
Suppose when B = 3 and Y = 805306367, it overflows 32bit value, but when X = -2147483648, the result comes backs to 32 bit range.
So I want to store the result of (Y*2^B). Can anyone suggest some solution for this.... A and B are having value from -15 to 15 and X,Y can have values from 2147483647..-2147483648.
Output can range from 0...4294967295.
If the number is too big for a 32 bit variable, then you either use more bits (either by storing in a bigger variable, or using multiple variables) or you give up precision and store it in a float. Since Y can be MAX_INT, by definition you can't multiply it by a number greater than 1 and still have it fit in a 32 bit int.
I'd use loop, instead of multiplication, in this case. Something like this:
int newX = X;
int poweredB = ( 1 << B ); // 2^B
for( int i = 0; i < poweredB ; ++i )
{
newX += Y; // or change X directly, if you will not need it later.
}
int result = ( 1 << A ) * newX;
But note : this will work only for some situations - only if you have the guarantee, that this result will not overflow. In your case, when Y is large positive and X is large negative number ("large" - argh, this is too subjective), this will definitely work. But if X is large positive and Y is large positive - there will be overflow again. And not only in this case, but with many others.
Based on the values for A and B in the assignment I suppose the expected solution would involve this:
the following are best done unsigned so store the signs for X and Y and operate on their absolute value
Store X and Y in two variables each, one holding the high 16 bits the other holding the low bits
something like
int hiY = Y & 0xFFFF0000;
int loY = Y & 0x0000FFFF;
Shift the high parts right so that all the variables have the high bits 0
Y*(2^B) is actually a shift of Y to the left by B bits. It is equivalent to shifting the high and low parts by B bits and, since you've shifted the high part, both operations will fit inside their 32 bit integer
Process X similarly in the high and low parts
Keeping track of the signs of X and Y calculate X + Y*(2^B) for the high and low parts
Again shift both the high and low results by A bits
Join the high and low parts into the final result
If you can't use 64-bits because your local C does not support them rather than some other overriding reason, you might consider The GNU Multiple Precision Arithmetic Library at http://gmplib.org/

Resources