Forum: Mikrocontroller und Digitale Elektronik STM32F3 FPU Aktivieren/Benutzen in STM32CubeIDE


von Alex -. (alex796)


Angehängte Dateien:

Lesenswert?

Hi

Ich bin neu in Microcontroller und verwende den STM32F303CCT6 mit 
STM32CubeIDE. Mittels Ref Manual gehe ich verschiedene Kapitel (ADC, 
Timer etc.) durch mit kleinen Beispielprojekten.

In Bezug auf ADC möchte ich gerne die interne Temperature sowie die 
Referenzspannung mittels SWV und printf ausgeben, welche 
Gleitkommazahlen sind:
1
  temperature = (V25-ADC_data[0]*3.3/4095)/(AVG_SLOPE)*1000+25;
2
  voltage = ADC_data[1]*3.3/4095;
3
  printf("Temperature is: %.2f\n", temperature);
4
  printf("Voltage is: %.2f\n", voltage);

Der genannte MCU besitzt eine FPU. Meine Fragen:

1. Wie aktiviere und benutze ich die FPU?

In den Einstellungen kann ich zwischen Hardware, Software und Mix HW/SW 
wählen.

2. Sind das die einzigen Einstellungen, auf die ich achten muss?

3. Kann ich dann einfach mit float rechnen, ohne in der Performance 
Abstriche zu machen?

Compiler-output sagt, u.a:
> -mfpu=fpv4-sp-d16 -mfloat-abi=hard

von Stefan F. (Gast)


Lesenswert?

Die Einstellungen für den Compiler hast du gefunden. Damit sagst du dem 
Compiler, dass er die FPU nutzen soll. Du musst die FPU aber vor der 
Nutzung noch einschalten, mit

> SCB->CPACR = 0x00F00000;

Leider kann ich dir diese "magische" Zahl nicht erklären. Ich habe dazu 
keine Doku gefunden.

Wenn du die FPU innerhalb von Interrupt-Handlern verwendest, musst du 
der CPU außerdem sagen, dass sie ggf. deren Register auf dem Stack 
sichern soll:

> SET_BIT(FPU->FPCCR, FPU_FPCCR_LSPEN_Msk + FPU_FPCCR_ASPEN_Msk);

Siehe http://stefanfrings.de/stm32/stm32f3.html

> Kann ich dann einfach mit float rechnen, ohne in der
> Performance Abstriche zu machen?

Ja, soweit die FPU es halt her gibt. Float Operationen sind auch mit FPU 
nicht immer so schnell wie Integer Operationen. Ich würde sie daher nach 
wie vor sparsam einsetzen.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Stefan ⛄ F. schrieb:
> Leider kann ich dir diese "magische" Zahl nicht erklären. Ich habe dazu
> keine Doku gefunden.

Einfach mal CPACR bei der Suchmaschine des geringsten Misstrauens 
eingeben?
-> Vollzugriff auf Koprozessor 10 und 11 (warum auch immer die FPU auf 2 
Koprozessoren aufgeteilt ist)
Im CMSIS finden sich auch die passenden Bitdefines.

von Alex -. (alex796)


Angehängte Dateien:

Lesenswert?

Hi Stefan

Stefan ⛄ F. schrieb:
>> SCB->CPACR = 0x00F00000;

Ich habe diesen Link gefunden:
https://www.keil.com/support/docs/3716.htm

In der SystemInit Funktion:
1
#if (__FPU_USED == 1)                   // Keil
2
  /* enable FPU if available and used */
3
  SCB->CPACR |= ((3UL << 10*2) |             /* set CP10 Full Access               */
4
                 (3UL << 11*2)  );           /* set CP11 Full Access               */
5
#endif

Habe bei mir einen Breakpoint gesetzt, und siehe da, die Bits werden bei 
mir gesetzt.

Mir gefällt deine Webseite bezüglich STM32, Stefan. :)

Gruß,

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Mw E. schrieb:
> Im CMSIS finden sich auch die passenden Bitdefines.

Wo denn? Ich kann sie nicht finden.

von Stefan F. (Gast)


Lesenswert?

Alex -. schrieb:
> Ich habe diesen Link gefunden:
> https://www.keil.com/support/docs/3716.htm

Siehst du, wenn man die richtigen Stichworte kennt, findet man auch was. 
Passe aber auf, das Dokument bezieht sich auf den Cortex M7, der STM32F3 
hat einen Cortex M4.

von Alex -. (alex796)


Lesenswert?

Stefan ⛄ F. schrieb:
> Alex -. schrieb:
>> Ich habe diesen Link gefunden:
>> https://www.keil.com/support/docs/3716.htm
>
> Siehst du, wenn man die richtigen Stichworte kennt, findet man auch was.
> Passe aber auf, das Dokument bezieht sich auf den Cortex M7, der STM32F3
> hat einen Cortex M4.

Jap, das stimmt. Weshalb ich selbst in meiner SystemInit geschaut habe.

Zu deiner anderen Frage, wo man CPACR findet. Ist das nicht im Struct 
SBC_Type in der core_cm4.h zu finden?
1
typedef struct
2
{
3
...
4
  __IOM uint32_t CPACR;                  /*!< Offset: 0x088 (R/W)  Coprocessor Access Control Register */
5
} SCB_Type;

Und dann weiter unten:
1
#define SCB                 ((SCB_Type       *)     SCB_BASE      )   /*!< SCB configuration struct */

von Stefan F. (Gast)


Lesenswert?

Alex -. schrieb:
> Zu deiner anderen Frage, wo man CPACR findet. Ist das nicht im Struct
> SBC_Type in der core_cm4.h zu finden?

Das CPACR Register habe ich gefunden, aber keine Bit-Definitionen. 
Offenbar verwendet sogar Keil deswegen ebenfalls "magische" Zahlen.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Das ist jetzt durchaus interessant, dass in dem Header die Bitdefs 
fehlen.
Bis DFSR gibts die nur.
Da hat wohl ein Erstellscript bei ST oder ARM gezickt.

Ich hab aber mal mit grep geguckt wo meine Definition herkommt:
Aus einem Header vom Micrium OS.

: Bearbeitet durch User
von test (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Leider kann ich dir diese "magische" Zahl nicht erklären. Ich habe dazu
> keine Doku gefunden.



Im "Programming manual" (nicht Reference manual) stehen auch sämtliche 
Bitdefinitionen dazu. Auch mit Beispiel, wie man das in ASM aktiviert.

von Planloser (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Alex -. schrieb:
>> Zu deiner anderen Frage, wo man CPACR findet. Ist das nicht im Struct
>> SBC_Type in der core_cm4.h zu finden?
>
> Das CPACR Register habe ich gefunden, aber keine Bit-Definitionen.
> Offenbar verwendet sogar Keil deswegen ebenfalls "magische" Zahlen.


Ein typischer Stefan F.

Im von Dir sonst angepriesenen "Joseph Yiu, The Definitive Guide to ARM® 
CORTEX®-M3 and CORTEX®-M4 Processors" in der dritten Edition von 2014 
wird das doch im Kapitel
"13.2.3 CPACR register"
schön erklärt.
Insbesondere auch, dass man nicht zwangsläufig CP11 setzen muss.

Table 13.3. CP10 and CP11 Settings
Bits  CP10 and CP11 Setting
00  Access denied. Any attempted access generate a Usage fault (type 
NOCP – No Co-processor)
01  Privileged Access only. Unprivileged access generate a Usage fault
10  Reserved – result unpredictable
11  Full access

Vorschlag: Lies die von Dir angepriesene Literatur!

von Stefan F. (Gast)


Lesenswert?

Planloser schrieb:
> Ein typischer Stefan F.

Du mich auch.

> Vorschlag: Lies die von Dir angepriesene Literatur!

Glaube mir, das habe ich gemacht. Deswegen habe ich aber nicht das ganze 
Buch auswendig im Kopf.

Deine Erklärung ist hilfreich, dein persönliche Angriff ist aber ohne 
Würde. Du solltest wenigstens deinen richtigen Account verwenden, wenn 
du dreist wirst.

von Stefan F. (Gast)


Lesenswert?

test schrieb:
> Im "Programming manual" (nicht Reference manual) stehen auch sämtliche
> Bitdefinitionen dazu. Auch mit Beispiel, wie man das in ASM aktiviert.

Da steht nur CP10 und CP11 ohne weitere Erklärung, was das sein soll.

von Bauform B. (bauformb)


Lesenswert?

Stefan ⛄ F. schrieb:
> Das CPACR Register habe ich gefunden, aber keine Bit-Definitionen.
> Offenbar verwendet sogar Keil deswegen ebenfalls "magische" Zahlen.

Für die STM32 ist ja erstmal das Cortex-M4 programming manual PM0214 
zuständig. Da steht 1:1 das gleiche drin wie im Cortex-M4 Devices™ 
Generic User Guide oder im ARM v7-M Architecture® Reference Manual. Das 
letztere ist etwas ausführlicher, aber offiziell haben die vier Werte in 
den Koprozessor-Bitfeldern also keinen Namen.

Jetzt müsste ST für ihre Header Files Namen erfinden. Ich glaube nicht, 
dass uns das viel hilft. Deshalb schreibt man ja auch seine eigenen 
Header aus dem Manual ab ;)

Planloser schrieb:
> Insbesondere auch, dass man nicht zwangsläufig CP11 setzen muss.

bist du sicher? Der M4-Pseudo-Code zum Thema sieht so aus:
1
The CheckVFPEnabled() pseudocode procedure takes appropriate
2
action if software uses a floating-point instruction when the
3
Floating-point extension is not enabled:
4
// CheckVFPEnabled()
5
// =================
6
CheckVFPEnabled() // Check Coprocessor Access Control Register
7
                  // for permission to use CP10/11.
8
   if CPACR.cp10 != CPACR.cp11 then UNPREDICTABLE;
9
   case CPACR.cp10 of
10
      when 00
11
         UFSR.NOCP = 1;
12
         ExceptionTaken(UsageFault);
13
      when 01
14
         if !CurrentModeIsPrivileged()
15
            UFSR.NOCP = 1;
16
            ExceptionTaken(UsageFault);
17
      when 10
18
         UNPREDICTABLE;
19
//    when ‘11’  // access permitted by CPACR
20
   return;

Alex -. schrieb:
> 3. Kann ich dann einfach mit float rechnen, ohne in der Performance
> Abstriche zu machen?

Die FPU ist nur 32 Bit breit, also musst du float statt double benutzen, 
double wird per Software gerechnet. Das ist dann etwas langsamer und 
braucht eine lib, die man eigentlich nicht haben will. Die Gemeinheit 
dabei ist, dass C per Default immer double benutzt. Auch wenn dein 
"voltage" float ist, würde C mit double rechnen und bei der Zuweisung 
nach float konvertieren.

Schuld ist die Konstante "3.3". Genau genommen müsste man 3.3f 
schreiben, aber zum Glück kennt der GCC die Option 
"-fsingle-precision-constant". Das gilt dann für alle Konstanten mit 
Punkt oder E.

Richtig unangenehm wird es, wenn man float in lesbarer Form ausgeben 
will. Man kann der printf() Familie kein float übergeben, es wird immer 
zu double konvertiert. Schuld sind die default argument promotions 
kombiniert mit stdarg.h.

Meistens will man auf einem uC auch kein vollständiges printf() haben, 
eine reine Integer-Version ist doch merklich kleiner. Dafür habe ich 
verschiedene Funktionen, die z.B. Spannung oder Temperatur als float 
bekommen, passend umrechnen und ein Integer-printf() für die eigentliche 
Ausgabe benutzen. Bei der Gelegenheit kann man auch den Wertebereich 
prüfen und ggf. sowas wie ">99.9" statt 1.234E23 ausgeben.

Planloser schrieb:
> Insbesondere auch, dass man nicht zwangsläufig CP11 setzen muss.

von Stefan F. (Gast)


Lesenswert?

In meinem YIU Buch steht, dass CP10 und CP11 immer gleich eingestellt 
sein müssen.

von Alex -. (alex796)


Lesenswert?

Hi all,
vielen Dank für eure Antworten. Ich glaube, ich habe die FPU aktiviert 
(ohne etwas explizit dafür gemacht zu haben :) ).

@Stefan:

Um nochmal auf deinen Beitrag von vorhin zurückzukommen, weil der mir 
ein wenig Kopfzerbrechen bereitet hat:
Stefan ⛄ F. schrieb:
> Wenn du die FPU innerhalb von Interrupt-Handlern verwendest, musst du
> der CPU außerdem sagen, dass sie ggf. deren Register auf dem Stack
> sichern soll:
>
>> SET_BIT(FPU->FPCCR, FPU_FPCCR_LSPEN_Msk + FPU_FPCCR_ASPEN_Msk);

Ich weiß nicht, ob du das bereits weißt, oder ich deinen Beitrag (deine 
Seite) vielleicht einfach nur missverstanden habe.
Ich habe aber gerade Dokument PM0214 von ST angesehen, Kapitel 4.6.2 
(FPCCR).
Reset value is 0xC0000000 = 0b 1100 0000 0000 0000 0000 0000 0000 0000

Die obersten zwei Bits sind ASPEN und LSPEN, und sind nach Reset bereits 
gesetzt.

Lazy stacking ist also bereits von Reset an aktiviert.

von Stefan F. (Gast)


Lesenswert?

Alex -. schrieb:
> Lazy stacking ist also bereits von Reset an aktiviert.

Das habe ich nicht bemerkt. Danke für den Hinweis, ich habe den Text 
entsprechend aktualisiert.

von pegel (Gast)


Lesenswert?

Kann es sein, dass die aktuelle CubeIDE das jetzt von allein richtig 
macht?
Ohne etwas einzustellen wird die FPU benutzt.
1
int main(void)
2
{
3
 8000598:  b580        push  {r7, lr}
4
 800059a:  b084        sub  sp, #16
5
 800059c:  af00        add  r7, sp, #0
6
  volatile float f1,f2,f3;
7
  f1=1.1; f2=2.2;
8
 800059e:  4b0e        ldr  r3, [pc, #56]  ; (80005d8 <main+0x40>)
9
 80005a0:  60fb        str  r3, [r7, #12]
10
 80005a2:  4b0e        ldr  r3, [pc, #56]  ; (80005dc <main+0x44>)
11
 80005a4:  60bb        str  r3, [r7, #8]
12
  f3=f1+f2;
13
 80005a6:  ed97 7a03   vldr  s14, [r7, #12]
14
 80005aa:  edd7 7a02   vldr  s15, [r7, #8]
15
 80005ae:  ee77 7a27   vadd.f32  s15, s14, s15
16
 80005b2:  edc7 7a01   vstr  s15, [r7, #4]
17
  f3=f3*f3;
18
 80005b6:  ed97 7a01   vldr  s14, [r7, #4]
19
 80005ba:  edd7 7a01   vldr  s15, [r7, #4]
20
 80005be:  ee67 7a27   vmul.f32  s15, s14, s15
21
 80005c2:  edc7 7a01   vstr  s15, [r7, #4]
22
  /* USER CODE END 1 */

Bei einem älteren Projekt war __FPU_USED nicht gesetzt und somit in 
SystemInit die FPU nicht aktiviert.

von pegel (Gast)


Lesenswert?

War in allen Fällen ein Nucleo-L476.

von M. Н. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
>> SCB->CPACR = 0x00F00000;
>
> Leider kann ich dir diese "magische" Zahl nicht erklären. Ich habe dazu
> keine Doku gefunden.

Die Doku findet man bei ARM im Prozessorhandbuch. Das ist quasi die 
"goldene Referenz". Kann das Handbuch allgemein sehr empfehlen. Da haben 
sich bei mir schon häufiger Dinge geklärt, die ST und Konsorten in ihren 
Manuals teils unzulänglich oder ganz falsch beschrieben hatten.

https://developer.arm.com/documentation/100166/0001/Floating-Point-Unit/FPU-programmers-model/Enabling-the-FPU

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.