Forum: Mikrocontroller und Digitale Elektronik Floating Pointing Unit STM32F4


von Moritz M. (avrprogger)


Lesenswert?

Hallo,

ich programmiere jetzt seit einiger Zeit die STM32 Controller mit dem 
Atollic TrueStudio. Ich frage mich jetzt nur ob die FPU der STM32F4 
Controller wirklich gestartet wird. Ausgewählt habe ich im 
Projekt-Erstellen Dialog vom Atollic TrueStdio "Floating Pointing : Mix 
HW/SW implementation". Im Startup-Code steht auch
1
/*FPU settings*/
2
 ldr     r0, =0xE000ED88           /* Enable CP10,CP11 */
3
 ldr     r1,[r0]
4
 orr     r1,r1,#(0xF << 20)
5
 str     r1,[r0]


Hat jemand eine Idee wie ich rausfinden kann ob die FPU läuft?

Moritz

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Moritz M. schrieb:
> Hat jemand eine Idee wie ich rausfinden kann ob die FPU läuft?

Wieso sollte sie nicht laufen, nachdem Du CP10/11 aktiviert hast? Um das 
zu prüfen lässt Du einfach einen FPU Befehl ausführen und schaust, ob er 
das gewünschte Ergebnis liefert.

--
Marcus

von Moritz M. (avrprogger)


Lesenswert?

Hallo,

okay vielen Dank! Wie würde den so ein FPU Befehl aussehen? ich dache 
wenn ich mit Gleitkomma rechne würde die FPU das automatisch erledigen?

Moritz

von STM32 (Gast)


Lesenswert?

>Wie würde den so ein FPU Befehl aussehen? ich dache

-> Cortex reference manuals.

>wenn ich mit Gleitkomma rechne würde die FPU das automatisch erledigen?

Wenn Du die richtigen Compileroptionen anwendest oder in Assembler
programmierst und den Rat von Marcus oben befolgst, sollte
das auch passieren.

von Roland H. (batchman)


Lesenswert?

Moritz M. schrieb:
> ich dache
> wenn ich mit Gleitkomma rechne würde die FPU das automatisch erledigen?

Wenn man dem Compiler mitteilt, dass man das möchte, dann ja:
1
  COMMON_FLAGS += -mfloat-abi=hard
2
  COMMON_FLAGS += -mfpu=fpv4-sp-d16

für AS, CC, LD.

Dann wird aus
1
  const float f2 = f * 2.29f;

so etwas:
1
 8001488:  edd4 7a00   vldr  s15, [r4]
2
 800148c:  ee27 7a88   vmul.f32  s14, s15, s16

ohne FPU sieht es es so aus:
1
 8001ba4:  4925        ldr  r1, [pc, #148]  ; (8001c3c <main+0x120>)
2
 8001ba6:  6820        ldr  r0, [r4, #0]
3
 8001ba8:  f7fe ec68   blx  800047c <__aeabi_fmul>
4
 8001bac:  4607        mov  r7, r0

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Gut dass es diesen Thread gibt ;-)
Nicht alle haben bisher die FPU richtig benutzt, bzw. wissen wie es 
richtig geht (incl. mich).

Zum ersten, wenn man die Compileroptionen (siehe oben) setzt und man hat 
nicht diese 4 Assember Befehle für das Aktivieren der FPU drin und man 
nutzt float Zahlen, dann gibt es einen Absturz mit 
"Hard-Fault-Exception()" Interrupt.

Somit muss immer beides gemacht werden.

Verwirrender weise zeigt das Listing von GCC den Assembler Befehl 
"fmuls" hingegen im Disassembler Fenster beim Debuggen "vmul.f32" an.

Nun zu meinen kleinen Tests:
1
  float f = 1.01f;
2
  CORE_SysTickEn();
3
  vu32 it = CORE_GetSysTick();
4
  float f2 = f * 2.29f;
5
  vu32 it2 = CORE_GetSysTick() - it;

Das Ergebnis ist bei der GCC und der FPU Variante immer gleich. Nur der 
Windows Taschenrechner zeit eine andere Zahl.

Die Taktberechnung verbraucht 6 Takte, die habe ich von der 
Float-Zählung abgezogen:
GCC:   41
FPU:   5

Dann habe ich die Zeile geändert:
1
float f2 = f / 2.29f;
GCC:   155
FPU:   21

Ist doch ein deutlicher Unterschied.

Testboard: STM32F4-Discovery
Compiler: arm-none-eabi-gcc.exe (Sourcery CodeBench Lite 2011.09-69) 
4.6.1
Optimierungsstufe: -O0

Defines für den Systic:
1
// Sys-Tick Counter - Messen der Anzahl der Befehle des Prozessors:
2
#define CORE_SysTickEn()    (*((u32*)0xE0001000)) = 0x40000001
3
#define CORE_SysTickDis()   (*((u32*)0xE0001000)) = 0x40000000
4
#define CORE_GetSysTick()   (*((u32*)0xE0001004))

von Roland H. (batchman)


Lesenswert?

Markus Müller schrieb:
> Somit muss immer beides gemacht werden.

Ich dachte, das sei nach den beiden ersten Postings klar ;-)

Markus Müller schrieb:
> Defines für den Systic:// Sys-Tick Counter - Messen der Anzahl der Befehle des 
Prozessors:
> #define CORE_SysTickEn()    (*((u32*)0xE0001000)) = 0x40000001
> #define CORE_SysTickDis()   (*((u32*)0xE0001000)) = 0x40000000
> #define CORE_GetSysTick()   (*((u32*)0xE0001004))

Ist das der Cortex-SysTick?
Wo hast Du denn diese Adressen/Register gefunden?

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Das ist der Befehls-Counter mit dem man exakt messen kann wie viele 
Clock-Takte der CPU für die Bearbeitung vergehen.

Die Register stehen im "Cortex-M3 Technical Referenz Manual" unter "Data 
Watchpoint and Trace registers" der Firma ARM. Such einfach nach 
"E0001000".

Das geht somit auch beim LPC17xx und anderen Prozis mit einem 
Cortex-M3/M4 drin.

Dieser Befehl ist wichtig, wenn man Zeitkritische Anwendungen hat und 
man kann somit exakt feststellen wie viele µS eine Routine benötigt. Ich 
musste mal AD-Interrupts recht komplex berechnen, da war es natürlich 
wichtig, dass die Routine weniger Zeit braucht, als wie der Interrupt 
erneut aufgerufen wird und die App genügend Reserve hat.
Beim ARM7 musste man dafür noch extra einen Timer 
konfigurieren/missbrauchen.

von Roland H. (batchman)


Lesenswert?

Markus Müller schrieb:
> Die Register stehen im "Cortex-M3 Technical Referenz Manual" unter "Data
> Watchpoint and Trace registers" der Firma ARM. Such einfach nach
> "E0001000".

Aha. Mich hat die Angabe "SysTick" verwirrt. Denn damit assoziiere ich 
den Cortex SysTick Timer, dessen Register an einer anderen, aber 
ähnlichen Adresse liegen.

Zu "E0001000" findet sich leider auch nix in core_cm4.h

Sehr interessant - wieder etwas gelernt.

von Vollprofi (Gast)


Lesenswert?

Roland H. schrieb:
> Zu "E0001000" findet sich leider auch nix in core_cm4.h
>
> Sehr interessant - wieder etwas gelernt.

Das ist der optimistische Standpunkt :-)
Man könnte auch sagen, die Datenblätter sind zu bescheiden. Die 
Stückelinformationen von STM gehen mir machmal auf den Geist!

von Roland H. (batchman)


Lesenswert?

Vollprofi schrieb:
> Die
> Stückelinformationen von STM gehen mir machmal auf den Geist!

Das trifft den Falschen.

core_cm4.h wird von ARM bereitgestellt. Das hat mit STM nix zu tun.

von Moritz M. (avrprogger)


Lesenswert?

Hallo,

wer weiß den wo man die Compiler-Optionen im Atollic TrueStudio einfügen 
muss? (Arbeite noch nicht solange mit Atollic TrueStudio)

Ausserdem fügt Atollic TrueStudio auch den Code
1
/*FPU settings*/
2
 ldr     r0, =0xE000ED88           /* Enable CP10,CP11 */
3
 ldr     r1,[r0]
4
 orr     r1,r1,#(0xF << 20)
5
 str     r1,[r0]

ein, wenn man "Floating Pointing: Software implementation" auswählt.

Moritz

von Uwe (Gast)


Lesenswert?

Benutzt du denn die Vollversion von Atollic TrueStudio.
Die frühen Demoversionen konnten kein Hardware Fließkomma und die 
aktuellen können zwar Fließkomma aber haben eine Größenbeschränkung.

von Uwe (Gast)


Lesenswert?


von friedrich (Gast)


Lesenswert?

Soviel ich weiß kann die code sourcery lite von 2011 die du verwendest 
noch keine native FPU Unterstützung des Cortex M4. Dagegen soll die von 
ARM (https://launchpad.net/gcc-arm-embedded/4.6) herausgegebene 
Toolchain dies können (habe ich nicht verifiziert). Ich habe diese 
anstatt der code sourcery lite installiert und die geht stattdessen 
einwandfrei.

Grüße

von friedrich (Gast)


Lesenswert?

Zitat aus lauchpad.net:

Features:
* All GCC 4.6 features, plus latest mainline features
  * Cortex-M0/M1/M3 support
  * Cortex-M4 with hard float multilib support

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Ich nutze Codesourcery Lite und wie man oben sieht (Taktmessung) klappt 
das auch mit den FPU Befehlen.
Beitrag "Re: Floating Pointing Unit STM32F4"

von ReinerL (Gast)


Lesenswert?

Markus Müller schrieb:
> Ich nutze Codesourcery Lite und wie man oben sieht (Taktmessung) klappt
> das auch mit den FPU Befehlen.

Das kann ich auch bestätigen, solange keine Funktionen aus der Mathlib 
verwendet werden.
Bei der Version von Launchpad ist eine Multilib dabei, da klappt es auch 
mit mathematischen Funktionen und der FPU. Das hab ich getestet.

von Moritz M. (avrprogger)


Lesenswert?

Hallo,

ich benutze eine Demo Version von TrueStudio allerdings gibt es da noch 
keine Code-Begrenzung.

wo muss mann die Optionen nun hinzufügen?

Moritz

von Moritz M. (avrprogger)


Lesenswert?

Hallo,

okay ich hab jetzt die CooCox CoIDE. Wo fügt ihr die FPU Init Befehle 
ein?

(startup_stm32f4xx.c ?)

Ich finde es übrigens super dass das gleich in das STM32-Tutorial 
eingefügt wurde! :)

Moritz

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Aktivierung ist in den STMicro Beispielen für STM32F4 aus der 
StdPeriphLib (das ist nicht das Codepacket zum STM32F4 Discovery-Board) 
in system_STM32F4.c/SystemInit() untergebracht. Sieht so aus:
1
void SystemInit(void)
2
{
3
  /* FPU settings ------------------------------------------------------------*/
4
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
5
  SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
6
#endif
7
  ...

__FPU_PRESENT und __FPU_USED werden in STM32F4xx.h bzw. core_cm4.h 
definiert, in letzterer durch Auswertung von vordefinierten Macros in 
Abhängigkeit von den Compileroptionen.

Man kann relativ leicht die StdPeriphLib aktualisieren, muss dann nur 
auf die HSE-Frequenz und die PLL Einstellung in SystemInit achten.

von Florian A. (florian_a)


Lesenswert?

Hallo!

Wenn ich das Beispiel von Markus Müller auf meinem STM32F4Discovery 
probiere komme ich auch auf die 21 Takte bei der Division, nur bei der 
Multiplikation auf 12 Takte anstatt wie bei ihm 5 Takte.

Was könnt der Grund hierfür sein?
In CP10 steht 0b11 und in CP11 auch 0b11!

Der Disassembly Code für die Multiplikation:
float f2 = f * 2.29f;
    ED977A03    vldr s14, [r7, #12]
    EDDF7A0B    vldr s15, 0x080003F0 <__text_start__+0x5C>
    EE677A27    vmul.f32 s15, s14, s15
    EDC77A02    vstr s15, [r7, #8]

Danke für eure Hilfe!!

von hans (Gast)


Lesenswert?

Hi, hab ne Zwischenfrage zu "__FPU_PRESENT und __FPU_USED werden in 
STM32F4xx.h bzw. core_cm4.h definiert"

In der STM32F4xx.h steht
#define __FPU_PRESENT             1       /*!< FPU present

Dennoch erhalte ich beim bauen folgende Fehlermeldung:
Libraries\CMSIS\Include/core_cm4.h:131:8: warning: #warning "Compiler 
generates FPU instructions for a device without an FPU (check 
__FPU_PRESENT)"

Ich habe als Flag -D"ARM_MATH_CM4" eingetragen, damit der Kompiler die 
Mathe-Funktionen lädt. Hab ich etwas vergessen?

von Markus G. (grabner)


Lesenswert?

Ich hatte ein ähnliches Problem und habe in diesem Thread einige 
Antworten auf meine Fragen gefunden. Ich möchte hier noch ergänzen, was 
zu tun ist, damit auch die Quadratwurzel von der FPU berechnet wird. Als 
Entwicklungsumgebung verwende ich eclipse unter Linux (siehe 
http://www.mikrocontroller.net/articles/STM32F4-Discovery).

*) Die von Roland H. oben genannten Compiler-Optionen lassen sich in 
eclipse bequem unter "Project->Properties->C/C++ Build->Settings->Tool 
Settings->Target Processor" einstellen.

*) Im release-Modus wird standardmäßig mit der Option "-Os" kompiliert, 
die für minimale Größe des generierten Codes sorgt. Dabei wird offenbar 
der Aufruf einer Bibliotheksfunktion bevorzugt. Um das zu ändern, muss 
die Laufzeit optimiert werden, z.B. mit der Option "-O3". Das geht im 
gleichen Dialog-Fenster unter "...->Tool Settings->ARM Linux GCC C 
Compiler->Optimization->Optimization level".

*) Die C-Funktion sqrt() berechnet die Quadratwurzel in "double 
precision", wandelt also das Argument in double um, berechnet die 
Wurzel, und wandelt das Ergebnis zurück in float um (alles auf der CPU). 
Um die Berechnung auf der FPU zu erzwingen, ist die Funktion sqrtf() zu 
verwenden. Im Disassembler kann man dann verifizieren, dass tatsächlich 
der Befehl "vsqrt.f32" ausgeführt wird.

Schöne Grüße,
Markus

von Armin J. (arminj)


Lesenswert?

Erstmal vielen Dank, das ist schon sehr sehr hilfreich, was hier 
gepostet ist!
Aber eine Ergänzung hat mir noch gefehlt.

Bei mir gab es mit dem Flag beim Linken
1
-mfloat-abi=hard
jede Menge Errors der Art:
1
hw_config.o uses VFP register arguments, TouchScreenApps.elf does not

Das liegt daran, dass die libgcc nicht für hardfloat übersetzt ist.

Macht aber nichts, denn mit
1
-mfloat-abi=softfp
funktioniert es und der Copiler erzeugt schöne Floatingpoint Befehle,
wie man im *.lst File
1
arm-none-eabi-objdump -h -S TouchScreenApps.elf > TouchScreenApps.lst
nachsehen kann.

Beste Grüße
Armin

von Detlef _. (detlef_a)


Lesenswert?

Hallo,

ich belebe den fred nochmal, weil ich ein ähnliches Problem habe:

Ich betreibe ein Olimex board mit einem STM32F405 unter C mit gcc und 
Eclipse, ich lade das Programm über JTAG.

Geht alles wunderbar, solange ich kein float benutze.
Falls ich das tue, übersetzt und linkt er problemlos, der 'launcher' 
meckert aber mir unverständliches.

In stm32f4xx.h finde ich:
#if !defined  (__FPU_PRESENT)
  #define __FPU_PRESENT             1       /*!< FPU present 
*/
#endif /* __FPU_PRESENT */

scheint ok.

Wenn ich sowas in die main.c einbaue meckert der Compiler, beide Werte 
sind also 1
#if (__FPU_PRESENT == 1)&& (__FPU_USED == 1)
hhhhhhh
#endif


Im Makefile steht:
CFLAGS += -mfloat-abi=hard
CFLAGS += -mfpu=fpv4-sp-d16

Im Makefile nur angegeben:
CFLAGS += -mfloat-abi=hard
geht auch nicht.

CFLAGS += -mfloat-abi=softfp
geht auch nicht

Irgendwo ist noch ein Schalterchen, das ich nicht kenne. Könnt Ihr mir 
den verraten?

Bin ARM Anfänger, weiß ich.

THX
Cheers
Detlef

Noch was: Wieso kennt er 'cos' nicht wenn ich math.h include?
Noch noch was: Wie kann ich das Listingfile des Assemblers behalten, 
meine Konfiguration schmeist das weg?

: Bearbeitet durch User
von cd334 (Gast)


Lesenswert?

Detlef _a was ist deine compiler Version?

von Detlef _. (detlef_a)


Lesenswert?

4.8.4

von cd334 (Gast)


Lesenswert?

Und welche variant? arm-gcc oder Sourcery CodeBench Lite, oder anderes?

von Detlef _. (detlef_a)


Lesenswert?

arm-gcc

von cd334 (Gast)


Lesenswert?

Dann musst du die FPU unit einschalten:
Das ist ein Code von FreeRTOS ARM-CM4F gcc port:
1
/* This is a naked function. */
2
static void vPortEnableVFP( void )
3
{
4
  __asm volatile
5
  (
6
    "  ldr.w r0, =0xE000ED88    \n" /* The FPU enable bits are in the CPACR. */
7
    "  ldr r1, [r0]        \n"
8
    "                \n"
9
    "  orr r1, r1, #( 0xf << 20 )  \n" /* Enable CP10 and CP11 coprocessors, then save back. */
10
    "  str r1, [r0]        \n"
11
    "  bx r14            "
12
  );
13
}

von Detlef _. (detlef_a)


Lesenswert?

Die FPU units sind eingeschaltet, das wird bei SystemInit gemacht, die 
Defines sind beide 1:

  /* FPU settings 
------------------------------------------------------------*/
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 
Full Access */
  #endif


Was kanns denn sonst noch sein?

Cheers
Detlef

von Detlef _. (detlef_a)


Lesenswert?

Ich habe nochmal tiefer gegraben, meine Konfiguration machte laut 
Assemblerlisting Soft-floatingpoint.

Wenn ich das -mfpu=fpv4-sp-d16 Flag rausgenommen habe, also so
#CFLAGS += -mfpu=fpv4-sp-d16

hat er Hard-floatingpoint kompiliert aber ist trotzdem irgendwo 
abgeschmiert, wenn ich floating-point benutzt habe.

Ich kann kein float aufm CortexM4, wieso könnt Ihr das?

Cheers
Detlef

von SuseLunix (Gast)


Lesenswert?

Du nimmst schon "float", kein "double" oder?

von Detlef _. (detlef_a)


Lesenswert?

SuseLunix schrieb:
> Du nimmst schon "float", kein "double" oder?

Das war es!

Ich habe mir für die Tests das Ergebnis von 0.7*(n++) ausgeben lassen.
Das in 0.7f*(n++) geändert beendet alle Probleme (naja, erstmal).

Danke!!!

Cheers
Detlef

von SuseLunix (Gast)


Lesenswert?

gut. Hab die FPU selbst noch nicht benutzt, will das aber in den 
nächsten Tagen tun und hab mich gestern Abend etwas eingelesen. Und da 
bin ich über ein Dokument/Webseite gestolpert wo stand, dass es bei 
double eine Hardware exception gäbe.

Die FPU ist halt für float (32Bit) gemacht. Double sollte eigentlich 
über Bibliotheksfunktionen laufen.

Aber wie gesagt, ich stehe auch gerade am Anfang bzw. bald vor den 
gleichen Problemen.

von SuseLunix (Gast)


Lesenswert?

Grad gefunden:
http://visualgdb.com/tutorials/arm/stm32/fpu/
Abschnitt 9.

Ist also wohl eine Compilergeschichte.

von Detlef _. (detlef_a)


Lesenswert?

Hallo,

nochwas zum CortexM4:

sinf ist laut math.h die float Variante vom Sinus.

Der Linker findet aber die lib wohl nicht: undefined reference.
Was für ne lib muss ich denn dazu noch einbinden?

gute Nacht
Detlef

von Detlef _. (detlef_a)


Lesenswert?

Hallo,

Du kopierst die libm.a in den Projektordner wo sich auch schon die 
libgcc.a befindet. libm.a gibts gibts in mindestens drei 
Geschmacksrichtungen: hard/soft float, thumb. Die richtige nehmen. Dann 
libm.a in die Linker commandline, wo auch schon libgcc.a vorhanden ist.

Cheers
Detlef

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.