6 votos

STM32F4: Flotante punto instrucciones demasiado lentas

Estoy trabajando en una aplicación de audio en el Núcleo F411RE y me he dado cuenta de que mi tratamiento fue demasiado lento, haciendo que la aplicación omitir algunas muestras.

Buscando a mi desmontaje pensé que dado el número de instrucciones y el 100 MHz de reloj de CPU (que me he fijado en STM32CubeMx), que debería ser mucho más rápido.

He comprobado SYSCLK valor y es de 100Mhz como se esperaba. Para estar 100% seguro de que poner 1000 "nop" en mi bucle principal y mide 10 µs, lo que corresponde a un 100 MHz de reloj.

He medido exactamente el tiempo tomado por mi de procesamiento y toma de 14,5 µs es decir 1450 ciclos de reloj. Creo que es demasiado, teniendo en cuenta que el proceso es bastante simple :

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

donde la fase y phaseInc son de precisión simple carrozas, y el valor es un int16_t, sine[] es una tabla de consulta que contiene 1024 int16_t.

No debería ser más que un deseo de 500 ciclos, derecho? Me miré en el desmontaje, se hace uso de la las instrucciones de punto flotante... Por ejemplo, el último de la línea de desmontaje es : vfma.f32 => 3 ciclos vcvt.s32.f32 => 1 ciclo vstr => 2 ciclos ldrh.w => 2 ciclos

(ciclos de tiempo de acuerdo a este ), con Lo que un total de 8 instrucción de esa línea, que es el "más grande". Yo realmente no se por qué es tan lento... tal vez porque estoy usando estructuras o algo?

Si alguien tiene alguna idea, me encantaría escucharlo.

EDIT : acabo de medir el tiempo, línea por línea, usted puede ver en el código anterior. Parece que la mayor parte del tiempo consumming línea es la tabla de la línea, lo que significa que es tiempo de acceso a memoria que es crítico? ¿cómo podría mejorar?

EDIT2: desmontaje, según lo solicitado por BruceAbott (lo siento, es un poco desordenado, probablemente debido a la forma en que fue optimizado por el compilador):

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>

16voto

Joe Kearney Puntos 425

En su desmontaje vemos llamadas a 64 bits (doble precisión) funciones matemáticas:-

08001956:   bl 0x80004bc <__extendsfdf2>
...
0800195e:   bl 0x8000564 <__muldf3>
08001962:   bl 0x8000988 <__fixdfsi>

La STM32F4 solo soporta 32 bits de punto flotante en el hardware, por lo que estas funciones deben ser realizadas en el software y tomará muchos ciclos para ejecutar. Para asegurarse de que todos los cálculos se hacen en 32 bits, se debe definir todos sus números de punto flotante (incluyendo constantes) como tipo float.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X