STM32F4 number overflow - Page 1
Forum section: electronics / general

author: pyrohaz
author_rank: Regular Contributor
timestamp: July 14, 2014, 08:49:21 pm
content: After all the love I've given to STM32 series microcontrollers these past few days, they're not loving me back and I feel like ripping my hair out!I've literally got a program as simple as it gets: Incrementing a number.The main code is as follows:Code:int main(void){uint32_t X = 0;while(1){X+=1e7;}}Now I'm using the debugger to track the value of X and it just seems to saturate at 2^32 - 1 (4294967295)! Its literally just declared as an unsigned integer so I expect it to overflow not saturate! Could anybody care to enlighten me on why the hell this is happening?I'm using CooCox, an STM32F405 with an STLink V2.Absolutely any help is appreciated!Harris

author: bwat
author_rank: Frequent Contributor
timestamp: July 14, 2014, 08:59:18 pm
content: Change the float to an int. What happens then?Floats are contagious and the conversion of a big float (X+1e7) to the unsigned int (X) will end up as the max int. That's what I'm guessing anyway.

author: Kjelt
author_rank: Super Contributor
timestamp: July 14, 2014, 09:11:28 pm
content: If your main variable is an (unsigned) integer you should add with an (unsigned) integer or at least cast it to an (unsigned) integer.

author: pyrohaz
author_rank: Regular Contributor
timestamp: July 14, 2014, 09:30:09 pm
content: Oh my gosh, I feel completely stupid! Thats solved it, thank you both very much! I never knew that declaring a number in the e notation instantly made it a float (I'm used to using scientific e notation for generally large numbers).Thank you all again!

author: dannyf
author_rank: Super Contributor
timestamp: July 14, 2014, 09:33:08 pm
content: type promotion: 1e7 is a floating number / double.

author: andyturk
author_rank: Frequent Contributor
timestamp: July 15, 2014, 06:26:21 pm
content: Quote from: pyrohaz on July 14, 2014, 08:49:21 pmQuoteGlad you solved your problem. However, it would be instructive to know exactly why your uint variable was saturating.1e7 is 10000000, and well within what can be represented by uint32_t. The fact that you got weird behavior suggests that something else is at work here. Maybe you could post the assembly listing output from the compiler so we can figure it out?

author: pyrohaz
author_rank: Regular Contributor
timestamp: July 15, 2014, 07:03:33 pm
content: Happily!080000d2: ldr r0, [r7, #4]080000d4: bl 0x8001014 <__aeabi_ui2d>080000d8: adds r3, r0, #0080000da: adds r4, r1, #0080000dc: adds r0, r3, #0080000de: adds r1, r4, #0080000e0: ldr r3, [pc, #32] ; (0x8000104 <main+60>)080000e2: ldr r2, [pc, #28] ; (0x8000100 <main+56>)080000e4: bl 0x8000300 <__aeabi_dadd>080000e8: adds r3, r0, #0080000ea: adds r4, r1, #0080000ec: adds r0, r3, #0080000ee: adds r1, r4, #0080000f0: bl 0x80002c0 <__fixunsdfsi>080000f4: adds r3, r0, #0080000f6: str r3, [r7, #4](The there are a few more lines to just loop back to the top)My best assumption to the unsigned + float could be the instruction 0x80002c0. I've searched for __fixunsdfsi on the internet but didn't seem to get many results. At a guess, it could mean fix unsigned float sum ...?

author: bwat
author_rank: Frequent Contributor
timestamp: July 15, 2014, 07:04:49 pm
content: Quote from: andyturk on July 15, 2014, 06:26:21 pmIt was answered in the first post. In the case X gets close to 0xffffffff then floating contagion turns X into a float, adds 1e7 which is greater than 0xffffffff so conversion to the unsigned int "sticks" at 0xffffffff. To get at the nub of the problem, try this on a platform where unsigned int are 32-bits and see how the compiler doesn't want to wrap around back to zero. It actually makes sense from a mathematician's point of view, but not from a ALU designer's. The overflow status bit should be enough but C doesn't let you get at that bit from your code.Code:#include <stdio.h>int main(void){unsigned int x;x = (unsigned int)99e99;printf("%x\n", x);}I getCode:bwat@eeepc:~/slask$ uname -aLinux eeepc 2.6.32-57-generic #119-Ubuntu SMP Wed Feb 19 01:04:55 UTC 2014 i686 GNU/Linuxbwat@eeepc:~/slask$ make contagioncc contagion.c -o contagionbwat@eeepc:~/slask$ ./contagionffffffffEdit: OK, my claim that it was answered in the first post is me being oversure. I don't have the specific compiler and platform to test it on. I am however pretty confident

author: andyturk
author_rank: Frequent Contributor
timestamp: July 15, 2014, 09:09:03 pm
content: Quote from: bwat on July 15, 2014, 07:04:49 pmYou could be right. But here's a piece of theC99 standard (Section 6.2.5):QuoteThe left-hand side (lhs) of "X += 1e7;" is certainly unsigned, but the rhs isn't. Maybe it depends on when/how the float is "promoted" to unsigned int? There's some subtlety at work here.

author: gxti
author_rank: Frequent Contributor
timestamp: July 15, 2014, 09:15:38 pm
content: It's expanding to "x = (uint32_t)( (double) x + 1e7 )", so it does a floating-point add then truncates. There's no integer math happening at all, thus no overflow or modulus math.

author: andyturk
author_rank: Frequent Contributor
timestamp: July 15, 2014, 10:00:30 pm
content: Quote from: gxti on July 15, 2014, 09:15:38 pmYup, looks that way. And in the case where a floating point value isn't representable in the target of the conversion, the standard says the result is undefined. I.e., it's up to whoever wrote the compiler or the library of intrinsics.In pyrohaz's assembly code, __eabi_dadd is adding two floating point values. The name of the function suggests it's doing this in *double-precision* floating point, not the single-precision which is supported natively by the STM32F4. So this is probably a bad thing even if you wanted floating point in the first place, because it relies on software emulation of (double precision) floating point. FYI, here's a header file that lists these functions:http://users.sosdg.org/~qiyong/mxr/source/sys/arch/arm/include/aeabi.h#L41__fixunsdfsi is the routine that converts a double to an unsigned int. One implementation is here:http://opensource.apple.com/source/clang/clang-137/src/projects/compiler-rt/lib/fixunsdfsi.cIt's not the one that pyrohaz's compiler uses though. The one he's using probably maps double values that are outside the range of uint23_t to 0xffffffff.Pyrohaz, can you dig up the source to your __fixunsdfsi routine and check this?

author: Gridstop
author_rank: Contributor
timestamp: July 17, 2014, 01:17:35 am
content: 1e7 is a double, not a float. That's why it's doing double math. 1e7f is a float.

author: Kjelt
author_rank: Super Contributor
timestamp: July 23, 2014, 06:10:18 pm
content: I am on holiday so terrible connection but reading an arm book i just read that the cortex M4 has saturation instructions, this might also be a cause of not overflowing.

author: mrflibble
author_rank: Super Contributor
timestamp: July 23, 2014, 06:27:50 pm
content: Quote from: Kjelt on July 23, 2014, 06:10:18 pmThat would be an interesting luxury problem, in reverse! What C/C++ constructs do you use (aside from asm) to get saturated arithmetic using a regular compiler?Put another way: it would be really interesting if you accidentally got saturating arithmetic. If so, would you be so kind to post the exact code and compiler used? That would help in duplicating the accident.

author: jeremy
author_rank: Super Contributor
timestamp: July 23, 2014, 08:55:51 pm
content: if i recall correctly, the cmsis dsp library uses lots of saturating arithmetic. It is indeed part of the M4.

author: dannyf
author_rank: Super Contributor
timestamp: July 24, 2014, 12:16:16 am
content: -cortex M4 has saturation instructions, this might-you can easily verify if this is a C-thing or a cortex thing by typecasting a sufficiently large float or double type to an integer type.or reading the C standards or a decent C book.

author: Kjelt
author_rank: Super Contributor
timestamp: July 24, 2014, 09:31:55 am
content: I agree its a long shot and improbable, still its a good thing to know that these instructions exist.They are mostly used for audio calculations to prevent overflow and get clipping which is the lesser of both bad options.I was also surprised that there are a lot of different Cortex M3 revisions and that the board i am now playing with STM32F100 has an older r1 revision core.