Skip to main content
phkloth
Associate II
August 16, 2022
Solved

Cycles or duration of float Multiplication on STM32F4

Hi all,

I have a question concerning the duration of float multiplication on the STM32F4. As far as I know, the chip has an FPU.

I run the following code snippet

float LagCompensator_process(LagCompensator_instance* S, float input)
{
 
	S->x2 = input;
 
	LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_8);
 
	S->y1 = S->p1 *	(-S->p2 * S->y1 +
					 S->p3 * S->x2 +
					 S->p4 * S->x1
					);
	LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_8);
	S->x1 = S->x2;
 
	return S->y1;
 
}

The duration between the Pin Set and Reset is about 170ns. The processor runs on 180MHz.

I find the 170ns for 4 Multiplications pretty long. However, it is with float variables. Can anybody comment on this? Do I have to activate the FPU somewhere in the Project?

In the project properties, you can find

0693W00000QNn4MQAT.pngThanks in advance for your help!

This topic has been closed for replies.
waclawek.jan
waclawek.janBest answer
Super User
August 16, 2022

There's no problem with pointers here. S is parameter so is in r0 at the function entry; note that the very first instruction uses it straighforwardly.

If S points to RAM instead of CCMRAM, there's a penalty - reading from RAM as reading from any resource through the S-port of processor involves automatically one extra waitstate. Try moving the target struct to CCMRAM.

> > the first operation (saving 3 in s->y1) takes about 40ns.

> 8002b58: 4a12 ldr r2, [pc, #72] ; (8002ba4 <LagCompensator_process+0x58>)

This is read from data bus of the FLASH. If this value hasn't been cached (see ART), and you run at 180MHz thus probably 5 FLASH waitstates, the load alone takes 6 cycles plus ld execution is one more cycle, so that's 7 cycles = 39ns.

Btw. note that the compiler did not care to use the float registers for this operation - and 0x4040'0000 is indeed 3.0f.

IMO the above sequence is as optimal as it gets. 170ns is around 30 cycles. There are 4 muls and 2 adds, plus 7 loads and two saves. Loads are naturally 2 cycle, with an additional waitstate because of loading through S-port it's 3 cycles per load, that's 4+2+3*7+2=29 cycles, plus some odd cycle because of the 6-cycle FLASH latency can't supply sustained stream of 32-bit instructions.

As I've said, you can try to move the data struct to CCMRAM. You can also try to run code from RAM, but you may be surprised to find that it's not straighforwardly better - read Technical Update 1, pp. 36-45.

JW

12 replies

waclawek.jan
Super User
August 17, 2022

The call (bl) itself won't take 72 cycles under no reasonable scenario, so it's probably something at the entry of called function, maybe stacking of registers. Duration of that then depends not only on number of registers to stack, but also on the type of memory where the stack is located. Again, stack should be in CCMRAM. But it may be something else, too.

Generally, steps to improve performance is loops unrolling and function inlining (either through what the compiler provides, or explicitly). Plus moving things around in various memories, as I've already told you above. Note, that compiler compiles things differently when circumstances change. For ultimate control resort to asm.

Performance doesn't come cheap.

JW

phkloth
phklothAuthor
Associate II
August 17, 2022

Ok. It is at least nice to know that you would expect faster runtimes normally. So I will play around a bit and try to increase the performance.

Thank you very much for your help Jan!