cancel
Showing results for 
Search instead for 
Did you mean: 

SVPWM and sinf() slow calculation.

SProg
Associate III
Posted on June 19, 2016 at 16:46

Hello to everyone, i am building an old project with STM32F107 now.

I am trying to calculate the SVPWM values on the fly but seems like compiler's code is so long.I am running on 72MHz.

The fuction below needs around 60-65 usec,which is too much to fit on 20Khz timing.

I am using KEIL uvision 5 and 3lvl optimization.

float THETA;

int SECTOR=0;

float Ua=0;

float Ub=0;

float Uc=0;

float PI=3.14;

float T=0.0000625;  // 16kHz

float MAXMODINDEX = 2250;

volatile float n=0;

volatile float i=0;

float  FREF =50;

int   MAXn;

//--------------------------------//

void SVPWM(int count)

{

__disable_irq();

THETA= 2*PI*FREF*count*T;

SECTOR = THETA/(PI/3);

Ua = (FREF/50)*sinf((PI/3)-(THETA-SECTOR*(PI/3)));

Ub = (FREF/50)*sinf(THETA-SECTOR*(PI/3));

Uc = 1.0-Ua-Ub;

switch(SECTOR)

{

case 0:       TIM3->CCR1 = MAXMODINDEX*(Ua + Ub + 0.5*Uc);

             TIM3->CCR2 = MAXMODINDEX*(Ub + 0.5*Uc);

             TIM3->CCR3 = MAXMODINDEX*(0.5*Uc);

break;

case 1:

         TIM3->CCR1 = MAXMODINDEX*(Ua + 0.5*Uc);

TIM3->CCR2 = MAXMODINDEX*(Ua + Ub + 0.5*Uc);

TIM3->CCR3 = MAXMODINDEX*(0.5*Uc);

break;

case 2:       TIM3->CCR1 = MAXMODINDEX*(0.5*Uc);

                TIM3->CCR2 = MAXMODINDEX*(Ua + Ub + 0.5*Uc);

                 TIM3->CCR3 = MAXMODINDEX*(Ub + 0.5*Uc);

break;

case 3:       TIM3->CCR1 = MAXMODINDEX*(0.5*Uc);

                TIM3->CCR2 = MAXMODINDEX*(Ua + 0.5*Uc);

                TIM3->CCR3 = MAXMODINDEX*(Ua + Ub + 0.5*Uc);

break;

case 4:      TIM3->CCR1 = MAXMODINDEX*(Ub + 0.5*Uc);

               TIM3->CCR2 = MAXMODINDEX*(0.5*Uc);

               TIM3->CCR3 = MAXMODINDEX*(Ua + Ub + 0.5*Uc);

break;

case 5:       TIM3->CCR1 = MAXMODINDEX*(Ua + Ub + 0.5*Uc);

                TIM3->CCR2 = MAXMODINDEX*(0.5*Uc);

                TIM3->CCR3 = MAXMODINDEX*(Ua + 0.5*Uc);

break;

default: break;

        }

__enable_irq();

}

10 REPLIES 10
AvaTar
Lead
Posted on June 19, 2016 at 16:59

The F107 is a Cortex M3, without FPU , so every floating point operation needs to be emulated.

Even the FPU (in the F3/F4/F7 parts) does not support trigonometric functions (sinf(), cosf() ...).

Better use scaled math, and integer variables.

SProg
Associate III
Posted on June 19, 2016 at 17:17

Yeah i know F107 doesnt support FPU but 60-65usec is still too much.

AvaTar
Lead
Posted on June 19, 2016 at 18:12

Try measure the timing for sinf() calls, and for mult./div. operations.

You can also step through the disassembly code ...

I used a integer-based approach with a sin/cos table (also integer) to create a realtime modulation of two frequencies (output via DAC). That took about 10us per cycle on a F100 (24MHz).

Posted on June 19, 2016 at 19:37

There are likely a number of significant ways to optimize your code, Keil doesn't understand the algorithms, and especially where you have variables with global scope rather than constants. Multiplication is faster than division.

The F1 series also has no caching, prefetching, or optimization of the very slow Flash memory.

Consider also using a proper version of PI, and using methods where you are not constantly rehashing the same math.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
SProg
Associate III
Posted on June 19, 2016 at 19:53

I have used the table method with 8bit mCs on past.I would like this method for do it this time,but seems takes so much.

Ua = (FREF/50)*sinf((PI/3)-(THETA-SECTOR*(PI/3)));

Ub = (FREF/50)*sinf(THETA-SECTOR*(PI/3));

Those 2, takes about 45uSec to exetuced.

Yeah i am looking the ASM code and it generated this  for above code:

   107: Ua = (FREF/50)*sinf((PI/3)-(THETA-SECTOR*(PI/3))); 

0x080005F0 60E0      STR      r0,[r4,#0x0C]

0x080005F2 F001F98C  BL.W     __aeabi_i2d (0x0800190E)

0x080005F6 4632      MOV      r2,r6

0x080005F8 463B      MOV      r3,r7

0x080005FA F001F99F  BL.W     __aeabi_dmul (0x0800193C)

0x080005FE 462A      MOV      r2,r5

0x08000600 4643      MOV      r3,r8

0x08000602 F001FA99  BL.W     __aeabi_drsub (0x08001B38)

0x08000606 4632      MOV      r2,r6

0x08000608 463B      MOV      r3,r7

0x0800060A F001FA95  BL.W     __aeabi_drsub (0x08001B38)

0x0800060E F000FEE7  BL.W     __aeabi_d2f (0x080013E0)

0x08000612 F000FDFB  BL.W     sinf (0x0800120C)

0x08000616 F8DF828C  LDR.W    r8,[pc,#652]  ; @0x080008A6

0x0800061A 4605      MOV      r5,r0

0x0800061C 4641      MOV      r1,r8

0x0800061E 6A20      LDR      r0,[r4,#0x20]

0x08000620 F001FC20  BL.W     __aeabi_fdiv (0x08001E64)

0x08000624 4629      MOV      r1,r5

0x08000626 F001FD5B  BL.W     __aeabi_fmul (0x080020E0)

   108: Ub = (FREF/50)*sinf(THETA-SECTOR*(PI/3)); 

0x0800062A 6120      STR      r0,[r4,#0x10]

0x0800062C 68E0      LDR      r0,[r4,#0x0C]

0x0800062E F001F96E  BL.W     __aeabi_i2d (0x0800190E)

0x08000632 4632      MOV      r2,r6

0x08000634 463B      MOV      r3,r7

0x08000636 F001F981  BL.W     __aeabi_dmul (0x0800193C)

0x0800063A 4606      MOV      r6,r0

0x0800063C 460D      MOV      r5,r1

0x0800063E 6A60      LDR      r0,[r4,#0x24]

0x08000640 F001FB70  BL.W     __aeabi_f2d (0x08001D24)

0x08000644 4632      MOV      r2,r6

0x08000646 462B      MOV      r3,r5

0x08000648 F001FA82  BL.W     __aeabi_dsub (0x08001B50)

0x0800064C F000FEC8  BL.W     __aeabi_d2f (0x080013E0)

0x08000650 F000FDDC  BL.W     sinf (0x0800120C)

0x08000654 4605      MOV      r5,r0

0x08000656 4641      MOV      r1,r8

0x08000658 6A20      LDR      r0,[r4,#0x20]

0x0800065A F001FC03  BL.W     __aeabi_fdiv (0x08001E64)

0x0800065E 4629      MOV      r1,r5

0x08000660 F001FD3E  BL.W     __aeabi_fmul (0x080020E0)

0x08000664 6160      STR      r0,[r4,#0x14]

SProg
Associate III
Posted on June 19, 2016 at 20:03

If i use constants i see time being increased.

Could other compiler has much more optimized code;

Rosiney Silva
Associate II
Posted on June 19, 2016 at 22:19

Take a look at this book ''Math Toolkit for Real-Time Programming'' might be useful.

matic
Associate III
Posted on June 19, 2016 at 22:51

You have to be sure that all of your constants are flaots and not doubles. When you write:

MAXMODINDEX*(Ub + 0.5*Uc);

0.5 here is treated as a double format variable and then the whole calculation is calculated as double. Be sure that all sin() and cos() functions are actually sinf() and cosf() - these have float input parameters. Then be sure that all variables are defined as float, and be sure that you type casted all constants to float like:

MAXMODINDEX*(Ub + (float)0.5*Uc);

I used float calculations with Cortex-M4 with hardware FPU and also there, upper recommendations have much impact. If I write, let say, only one constant in the calculation without type casting it to float, the calculation time significantly increased (tested with ETM).

Actually, single precision FP calculation are not much slower than integer calculations, when hardware FPU is used and when calculation is correctly written. Of course, F1 parts doesn't have FPU and there it will be significantly slower, but with properly written SP expression it would be much faster than DP.

Posted on June 20, 2016 at 02:27

something like this should be faster

#define PI 3.141592654f
// ...
Ua = (FREF * (1.0f/0f))*sinf((PI/3.0f) - (THETA - (float)SECTOR * (PI/3.0f)));
Ub = (FREF * (1.0f/0f))*sinf(THETA - (float)SECTOR * (PI/3.0f));

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..