2013-04-03 2:27 AM
Hello, i run in to a problem, where i need to do math with single precision floating point.
it looks like if(...) condition, and printing floating point to uint16_t is very slow. so i have two questions: first, what is the fastest way to print float to integer ? ( float will be between -10 and +10, and that should correspond to 0x0000 and 0xFFFF in integer.) and second, how can i read binary data from float variable to u32 variables, so i can make if(...) condition faster (i need to set floating point to zero, if it is more than 10.0 or less that -10.0 ( i know that floating point variable is in memory with adress of 0x2000000C so all i need to do is to copy raw binary data to u32 variable, and check mantissa and exponent to see if it goes off the limit, but i don't know how to copy 32b data to 32b unsigned integer, if i try to do that with pointers i get error, or compiler do conversion for me, and slow my program)2013-04-03 2:39 AM
Doing printf() of anything is pretty slow in the scale of things.
float foo = 1.23; uint32_t bar; bar = *((uint32_t *)&foo); // Convert 32-bit float into it's binary representation IEEE-7542013-04-03 2:49 AM
bar = *((uint32_t *)&foo); // Convert 32-bit float into it's binary representation IEEE-754i can do tones of integer math with very little speed reduction
as example code like thisa++;
a=a*b+a*c+a*d+a*e;2013-04-03 2:59 AM
As clive said, avoiding printf() calls would help, especially such with floating point arguments.
For an uint16, you can write your own printf substitution.it looks like if(...) condition, ... is very slow.Are you really sure ? I can hardly believe this. But you might try ''
-mfloat-abi=hard
'', to use the FPU directly. And turning on at least minimal optimization (-O1
) might help, too.2013-04-03 3:09 AM
I think one of your problems here is that you don't have a clue what code the compiler is actually generating, or removing via optimization. If you want to play machine cycle level games, then use assembler.
Write some numeric output routines which are efficient, and relate to the range of numbers you wish to represent.2013-04-03 3:19 AM
Are you really sure ?
I can hardly believe this. But you might try ''
-mfloat-abi=hard
'', to use the FPU directly. And turning on at least minimal optimization (-O1
) might help, too. ok, as it turns out, that was compiler personality. if in while(1) cycle end i write:if(phase>0)
phase=0;
if(phase<-0)
phase=0;if(faze>0)
faze=0;
if(faze<-0)
faze=0;
a=a+1;// simple void counter with no other use, just count to 0xFFFF2013-04-03 3:19 AM
ok, that is just compiler skipping code and not compiling it right, when i added breakpoint, it show error that this code does not exist in ASM, so yes, if() for float is slow, and f32 to u32 conversion is slow,
my guess that floating point is good for MAC but and that all. so go back for old approach, check mantissa and exponent in integer format where ALU is fast to do the job.2013-04-03 3:53 AM
if(phase>0) ...
Are you aware that you use double constants ? Rephrase it toif(phase>0f) ...
could help here. And, if i remember correctly, the FPU has an VABS instruction, so something likeif (fabs(phase < 0f) ...
could also speed up things, too.2013-04-03 4:09 AM
ok, thanks for the tip.
i cross checked asm code and loop cycle speed, and now i know real problem. in main loop i was doing floating point MAC, 256 times with adc data. when i write anything what will going to use data from MAC compiler will include my floating point operations to assembler code. so in short, when i try to print calculated phase from main loop to DAC, it start to include all floating point operations from main loop, so in general f32 to in32 is fast only problem i have more floating point operations elsewhere. so that was wrong interpretation what compiler is doing, and it's doing quite a good job. original loop to see what i did...while(k<
128
)
{
cosinusas[k]=cosf((6.28318531*k*POINT)/N);
sinusas[k] =sinf((6.28318531*k*POINT)/N);
k++;
}
while(1)
{
while(GPIOA->IDR < 
32766
);
GPIOD->BSRRL= GPIO_Pin_13; 
while(GPIOA->IDR > 32766);
while(GPIOA->IDR < 
32766
);
GPIOD->BSRRH= GPIO_Pin_13;
imag=0;
real=0;
i=0;
a=0;
while(i<
128
)
{
while(GPIOC->IDR < 
32766
);
CLK_LOW;
CLK_HIGH;
k
=
GPIOB
->IDR;
real+=k*cosinusas[i]; // FMAC
imag-=k*sinusas[i]; // FMAC
i++;
}
faze=faze-(0.2*Angle(imag,real));
if(fabsf(faze)>0f)
faze=0;
DAC_DATA=(int)(faze*375+32767);
}
 while(GPIOC->IDR < 
32766
)n
while(i<
128
)2013-04-03 4:43 AM
I guess this is no commercial project, otherwise project management would slap on your fingers.
As the output data for the DAC are 12 bit, you could easily do it with scaled integer math on a cheap M3 or even a M0. But nevermind ... But I suggest to append anf
to all non-integral constants. According to the C standard, they are otherwise double by default.