Forum: Mikrocontroller und Digitale Elektronik FPU Anwendung Cortex-M4


von Simsonite (Gast)


Lesenswert?

Ahoi Community,

ich verwende der zeit das TM4C123GXL Launchpad von TI. Der darauf 
verbaute Controller ist mit einem Cortex M4 Prozessor ausgestattet. 
Zusätzlich verfügt der µC über eine FPU. Ich habe bisher nur mit dem 
ATmega8 gearbeitet und die bisherigen Programme für den TM4C123 habe ich 
alle mit integer Berechnung durchgeführt.

1) Kann mir jemand verraten ob meine float Berechnungen bei Aktivierung 
der FPU automatisch über die FPU mit den integrierten Funktionen (VADD, 
VDIV, VSQRT...) berechnet werden oder muss ich diese erst als Funktionen 
in Assembler Code anlegen

Beispiel: Wurzelberechnung
CalcSqrt
     VSQRT.F32 S0,S0  ; sqrt(input)
     BX  LR

Beispiel: Multiplikation
CalcMultiply
     VMUL.F32 S0,S0,S1  ; multiply(input1, input2)
     BX  LR

2) Wird die Instruktion VSQRT.F32... bzw. VMUL.F32 automatisch 
ausgeführt wenn ich die in math.h enthaltene Funktion sin(float x) bzw. 
A * B verwende?

Hier ein Link zum M4 Instruction Set: 
http://users.ece.utexas.edu/~valvano/EE345L/Labs/Fall2011/CortexM_InstructionSet.pdf

von Christian D. (burning_legend)


Lesenswert?

Du kannst deinem Compiler mitteilen, dass er die Floating Point 
berechnungen in Hardware machen soll, der linked dann automatisch die 
richtige Library. In GCC (afaik auch im TI Compiler) geht das mittels
1
-mfloat-abi=hard

Eventuell gibt es im Eclipse basierten CCS auch eine Einstellung bei den 
Architektur-Optionen.

Eventuell kann es auch notwendig sein
-march armv7e-m -mfpu=fpv4-sp-d16
zu spezifizieren.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dreckpfuhler:
1
-mfloat-abi=hard

von Simsonite (Gast)


Lesenswert?

Vielen Dank für die schnelle Antwort. Ein paar Fragen habe ich noch.

1) Im Datenblatt des TM4C123 wird ie FPU mittels:

; CPACR is located at address 0xE000ED88
LDR.W R0, =0xE000ED88
; Read CPACR
LDR R1, [R0]
; Set bits 20-23 to enable CP10 and CP11 coprocessors
ORR R1, R1, #(0xF << 20)
; Write back the modified value to the CPACR
STR R1, [R0]; wait for store to complete
DSB
;reset pipeline now the FPU is enabled
ISB

aktiviert. Erzeugt dieser Code das selbe Ergebnis oder wird die FPU 
dadurch tatsächlich "nur" aktiviert?

2) Ich verwende als IDE KeilµV. Habe dazu noch eine fred gefunden:
http://www.keil.com/support/docs/3716.htm
Wenn ich das richtig verstehe muss kann ich die Nutzung der FPU über die 
IDE einstellen : off, single precision, (double precision -> nicht bei 
M4)

3) Ist die tatsächliche Berechnung mittels assembler C=CalcMultiply(A,B) 
mit

CalcMultiply
     VMUL.F32 S0,S0,S1  ; multiply(input1, input2)
     BX  LR

schneller als die C Instruktion C=A*B wenn die FPU verwendet wird?

von klausr (Gast)


Lesenswert?

Simsonite schrieb:
> Erzeugt dieser Code das selbe Ergebnis oder wird die FPU
> dadurch tatsächlich "nur" aktiviert?

Die FPU wird aktiviert. Das ist notwendig, dass sonst beim Aufruf eines 
FPU-Befehles die CPU abstürzt.

Aber noch was: Falls du den gcc Compiler benutzt und möchtest, dass z.B. 
auch sqrtf Befehle direkt in einen FPU Code übersetzt werden, muss du 
folgendes beachten. Nehmen wir mal diesen Code an:
1
#include <math.h>
2
3
extern float d2(float a,float b,float c,float d,float e,float f,float g);
4
5
float test(float a)
6
{
7
  float b,c,d,e,f,g;
8
9
  b = a + 0.2f;
10
  c = b / 12.345f;
11
  d = c * 0.123f;
12
  e = fabs(d);
13
  f = sqrtf(e);
14
  g = sinf(f);
15
16
  return(d2(a,b,c,d,e,f,g));
17
}

Nach einem Aufruf mit:
arm-none-eabi-gcc floattext.c -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 
-mfloat-abi=hard -mthumb -Os -S
bekommst du das folgende Ergebnis:
1
        ...
2
test:
3
        @ args = 0, pretend = 0, frame = 0
4
        @ frame_needed = 0, uses_anonymous_args = 0
5
        push    {r3, lr}
6
        fstmfdd sp!, {d8, d9, d10}
7
        flds    s18, .L2
8
        fcpys   s20, s0
9
        flds    s17, .L2+4
10
        fadds   s18, s0, s18
11
        flds    s16, .L2+8
12
        fdivs   s17, s18, s17
13
        fmuls   s16, s17, s16
14
        fabss   s19, s16
15
        fcpys   s0, s19
16
        bl      sqrtf
17
        fcpys   s21, s0
18
        bl      sinf
19
        ...

Wie du siehst, werden durchweg FPU Befehle benutzt, aber nicht bei 
sqrtf. sinf gibts nicht als FPU Befehle beim Cortex-M4. Dass bei sqrtf 
die Lib-Funktion aufgerufen wird, liegt daran, dass bei Fehlern nach 
IEEE ein Flag gesetzt werden muss. Kann man darauf verzichten, kann man 
die Option -ffast-math verwenden. Siehe: 
https://answers.launchpad.net/gcc-arm-embedded/+question/246145

Übrigens ist eine Optimierunsstufe notwendig, damit statt der 
Lib-Funktion sqrtf der direkte FPU-Befehl benutzt wird!

arm-none-eabi-gcc floattext.c -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 
-mfloat-abi=hard -mthumb -ffast-math -Os -S

führt zu:
1
test:
2
        ...
3
        push    {r3, lr}
4
        fstmfdd sp!, {d8, d9, d10}
5
        flds    s18, .L2
6
        fcpys   s21, s0
7
        flds    s17, .L2+4
8
        fadds   s18, s0, s18
9
        flds    s16, .L2+8
10
        fmuls   s17, s18, s17
11
        fmuls   s16, s17, s16
12
        fabss   s20, s16
13
        fsqrts  s19, s20
14
        fcpys   s0, s19
15
        bl      sinf
16
        ...

Übrigens nicht verwundern, dass die FPU Befehle mit f... beginnen, das 
ist eine Eigenart des gcc für ARM. Der Assemblers der GNU-Binutils für 
ARM übersetzt das richtig. Nach dem assemblieren und anschließenden 
disassemblieren schauen sie so aus:
1
00000000 <test>:
2
   0:   b508            push    {r3, lr}
3
   2:   ed2d 8b06       vpush   {d8-d10}
4
   6:   ed9f 9a15       vldr    s18, [pc, #84]  ; 5c <test+0x5c>
5
   a:   eddf 8a15       vldr    s17, [pc, #84]  ; 60 <test+0x60>
6
   e:   ed9f 8a15       vldr    s16, [pc, #84]  ; 64 <test+0x64>
7
  12:   ee30 9a09       vadd.f32        s18, s0, s18
8
  16:   eef0 aa40       vmov.f32        s21, s0
9
  1a:   ee69 8a28       vmul.f32        s17, s18, s17
10
  1e:   ee28 8a88       vmul.f32        s16, s17, s16
11
  22:   eeb0 aac8       vabs.f32        s20, s16
12
  26:   eef1 9aca       vsqrt.f32       s19, s20
13
  2a:   eeb0 0a69       vmov.f32        s0, s19
14
  2e:   f7ff fffe       bl      0 <sinf>

Der Assembler kann übrigens beide Notierungen:

Aus
1
        fadds    s18, s0, s18
2
        vadd.f32 s18, s0, s18

macht er beide Male:
1
  12:   ee30 9a09       vadd.f32        s18, s0, s18
2
  16:   ee30 9a09       vadd.f32        s18, s0, s18

von klausr (Gast)


Lesenswert?

Kurzes Update: Die f... Befehle lagen wohl am alten gcc. Die Beispiele 
oben waren mit dem 4.9.1 gcc gemacht. Mit dem neuen gcc (gcc version 
5.2.1 20151202 (release) [ARM/embedded-5-branch Revision 231848] (GNU 
Tools for ARM Embedded Processors)) generiert er jetzt direkt v....f32 
Befehle.
1
test:
2
        @ args = 0, pretend = 0, frame = 0
3
        @ frame_needed = 0, uses_anonymous_args = 0
4
        push    {r3, lr}
5
        vpush.64        {d8, d9, d10}
6
        vldr.32 s16, .L2
7
        vldr.32 s17, .L2+4
8
        vldr.32 s18, .L2+8
9
        vadd.f32        s16, s0, s16
10
        vmov.f32        s19, s0
11
        vmul.f32        s17, s16, s17
12
        vmul.f32        s18, s17, s18
13
        vabs.f32        s20, s18
14
        vsqrt.f32       s21, s20
15
        vmov.f32        s0, s21
16
        bl      sinf

von Simsonite (Gast)


Lesenswert?

Vielen Dank!

Schön langsam kommt Licht ins Dunkel. Kann mir noch jemand sagen ob man 
die Einstellungen

arm-none-eabi-gcc floattext.c -mcpu=cortex-m4 -mfpu=fpv4-sp-d16
-mfloat-abi=hard -mthumb -ffast-math -Os -S

direkt in der IDE vornehmen kann, oder muss ich diese in ein bestimmtes 
File schreiben?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Simsonite schrieb:
> Kann mir noch jemand sagen

Zur Not nochmal einen Thread explizit dafür öffnen, der die benutzte
IDE im Subject benennt.  Kann gut sein, dass die, die sich damit
auskennen nicht die sind, die diesen Thread hier lesen.

von Simsonite (Gast)


Lesenswert?

Vielen Dank für die Hilfe. Ich werde diesbezüglich einen neuen thread 
erstellen.

von W.S. (Gast)


Lesenswert?

Simsonite schrieb:
> Beispiel: Multiplikation
> CalcMultiply
>      VMUL.F32 S0,S0,S1  ; multiply(input1, input2)
>      BX  LR

Wenn du Float-Operationen in Assembler schreibst, dann wird der 
Controller auch die FPU-Einheit benutzen.

ABER:
Wenn du nicht vorher die FPU freigibst, dann kriegst du entwede garnix 
oder nen Hardfault. Geht etwa so:
  SCB_CPACR = 3<<20;


Ansonsten mußt du die Float-verwendung auch dem Compiler sagen:
--cpu=Cortex-M4.fp.sp
--thumb
-c

Und auch dem Linker:
--cpu=Cortex-M4.fp.sp
...usw.

W.S.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.