Ich arbeite an einer Audioanwendung auf dem Nucleo F411RE und habe festgestellt, dass meine Verarbeitung zu langsam war, wodurch die Anwendung einige Samples übersprang.
Wenn ich mir meine Demontage anschaue, dachte ich, dass es angesichts der Anzahl der Anweisungen und des 100-MHz-CPU-Takts (den ich in STM32CubeMx eingestellt habe) viel schneller sein sollte.
Ich habe den SYSCLK-Wert überprüft und er ist wie erwartet 100 MHz. Um 100% sicher zu sein, habe ich 1000 "nop" in meine Hauptschleife gelegt und 10 µs gemessen, was einem 100-MHz-Takt entspricht.
Ich habe genau die Zeit gemessen, die meine Verarbeitung benötigt, und sie dauert 14,5 µs, dh 1450 Taktzyklen. Ich denke, es ist viel zu viel, wenn man bedenkt, dass die Verarbeitung ziemlich einfach ist:
for(i=0; i<12; i++)
{
el1.mode[i].phase += el1.osc[i].phaseInc; // 16 µs
if(el1.osc[i].phase >= 1.0) // 20 µs (for the whole "if"
el1.osc[i].phase -= 1.0;
el1.osc[i].value = sine[ (int16_t)(el1.osc[i].phase * RES) ]; // 96 µs
el1.val += el1.osc[i].value * el1.osc[i].amp; // 28 µs
} // that's a total of 1.63 µs for the whole loop
wobei phase und phaseInc Floats mit einfacher Genauigkeit sind und value ein int16_t ist, ist sine[] eine Nachschlagetabelle, die 1024 int16_t enthält.
Es sollten nicht mehr als 500 Zyklen sein, oder? Ich habe mir die Disassemblierung angesehen, sie verwendet die Gleitkommaanweisungen ... Zum Beispiel lautet die Disassemblierung der letzten Zeile: vfma.f32 => 3 Zyklen vcvt.s32.f32 => 1 Zyklus vstr => 2 Zyklen ldrh.w = > 2 Zyklen
(zykliert das Timing entsprechend ) Das sind also insgesamt 8 Anweisungen für diese Zeile, die die "größte" ist . Ich verstehe nicht wirklich, warum es so langsam ist ... Vielleicht, weil ich Strukturen verwende oder so?
Wenn jemand eine Idee hat, würde ich mich freuen, sie zu hören.
EDIT : Ich habe gerade die Zeit Zeile für Zeile gemessen, Sie können es im obigen Code sehen. Es scheint, als wäre die Nachschlagetabellenzeile die zeitaufwändigste Zeile, was bedeuten würde, dass die Speicherzugriffszeit kritisch ist? wie könnte ich das verbessern?
EDIT2: Demontage, wie von BruceAbott angefordert (sorry, es ist ein bisschen chaotisch, wahrscheinlich wegen der Art und Weise, wie es vom Compiler optimiert wurde):
membrane1.mode[i].phase += membrane1.mode[i].phaseInc;
0800192e: vldr s14, [r5, #12]
08001932: vldr s15, [r5, #8]
08001936: vadd.f32 s15, s15, s14
0800193a: adds r5, #24
179 if(membrane1.mode[i].phase >= 1.0)
0800193c: vcmpe.f32 s15, s16
08001940: vmrs APSR_nzcv, fpscr
180 membrane1.mode[i].phase -= 1.0;
08001944: itt ge
08001946: vmovge.f32 s14, #112 ; 0x70
0800194a: vsubge.f32 s15, s15, s14
0800194e: vstr s15, [r5, #-16]
182 membrane1.mode[i].value = sine[(int16_t)(membrane1.mode[i].phase * RES)];
08001952: ldr.w r0, [r5, #-16]
08001956: bl 0x80004bc <__extendsfdf2>
0800195a: ldr r3, [pc, #112] ; (0x80019cc <main+428>)
0800195c: movs r2, #0
0800195e: bl 0x8000564 <__muldf3>
08001962: bl 0x8000988 <__fixdfsi>
08001966: ldr r3, [pc, #104] ; (0x80019d0 <main+432>)
184 membrane1.val += membrane1.mode[i].value * membrane1.mode[i].amp;
08001968: vldr s13, [r5, #-4]
182 membrane1.mode[i].value = sine[(int16_t)(membrane1.mode[i].phase * RES)];
0800196c: sxth r0, r0
0800196e: ldrh.w r3, [r3, r0, lsl #1]
08001972: strh.w r3, [r5, #-8]
184 membrane1.val += membrane1.mode[i].value * membrane1.mode[i].amp;
08001976: sxth r3, r3
08001978: vmov s15, r3
0800197c: sxth r3, r4
0800197e: vcvt.f32.s32 s14, s15
08001982: vmov s15, r3
08001986: vcvt.f32.s32 s15, s15
174 for(i=0; i<12; i++) // VADD.F32 : 1 cycle
0800198a: cmp r5, r6
184 membrane1.val += membrane1.mode[i].value * membrane1.mode[i].amp;
0800198c: vfma.f32 s15, s14, s13
08001990: vcvt.s32.f32 s15, s15
08001994: vstr s15, [sp, #4]
08001998: ldrh.w r4, [sp, #4]
0800199c: bne.n 0x800192e <main+270>
In Ihrer Disassemblierung sehen wir Aufrufe von mathematischen 64-Bit-Funktionen (doppelte Genauigkeit): -
08001956: bl 0x80004bc <__extendsfdf2>
...
0800195e: bl 0x8000564 <__muldf3>
08001962: bl 0x8000988 <__fixdfsi>
Der STM32F4 unterstützt nur 32-Bit-Gleitkomma in der Hardware, daher müssen diese Funktionen in der Software ausgeführt werden und benötigen viele Zyklen zur Ausführung. Um sicherzustellen, dass alle Berechnungen in 32 Bit durchgeführt werden, sollten Sie alle Ihre Fließkommazahlen (einschließlich Konstanten) als Typ definieren float
.
Jonathan Wheeler
Marko Buršič
Florent
Florent
Bence Kaulics
Florent
leicht angeknabbert
if
Aussage. Wenn das kurz ist, versuchen Sie es in der Sinus-Nachschlagetabelle zu platzieren. Bald...Florent
Bruce Abbott
Florent
Rohr
Florent
Florent
membrane1.mode[i].value = sine[membrane1.mode[i].phase];
längste Zeitdauer (0,96 µs). gibt es eine möglichkeit das zu optimieren?Florent
Oldtimer
Florent
Oldtimer
Oldtimer
Michael
Florent
Oldtimer