-         

Ergebnis 1 bis 8 von 8

Thema: STM32 braucht zu lange für Multiplikation

  1. #1
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    08.09.2007
    Ort
    Berlin
    Alter
    24
    Beiträge
    1.544

    STM32 braucht zu lange für Multiplikation

    Anzeige

    Hi,

    ich habe hier ein STM32F4DISCOVERY Board, auf dem sitzt ein STM32F407VGT6 mit FPU.
    Da ich noch neu in der Welt der STM32 (oder allg. ARM) bin, sitzt der Fehler vermutlich vorm Bildschirm.
    Ich setze einen Pin low, führe 50 Multiplikationen eines float32 aus und setze anschließend den Pin high.
    Die Multiplikation passiert nicht in einer Schleife, sondern einfach 50x die gleiche Instruktion hintereinander. Das Oszi zeigt knapp 3µs an.
    Eigentlich sollte durch die FPU das ganze nur 50 Takte dauern, der STM32 läuft auf 168MHz (macht aber glaube ich 210MIPS durch Accelerator), also sollte es nur ca. 2.4e-7 Sekunden dauern.

    Hier mal der Code:
    Code:
    #include "stm32f4xx.h"
    #include "stm32f4xx_gpio.h"
    #include "stm32f4xx_rcc.h"
    #include "stm32f4xx_tim.h"
    #include "stm32f4xx_spi.h"
    #include "system_stm32f4xx.h"
    #include "arm_math.h"
    
    
    void GPIO_setup(void)
    {
        GPIO_InitTypeDef GPIO_InitStruct;
    
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14; // we want to configure all LED GPIO pins
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;         // we want the pins to be an output
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;     // this sets the GPIO modules clock speed
        GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;     // this sets the pin type to push / pull (as opposed to open drain)
        GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;     // this sets the pullup / pulldown resistors to be inactive
        GPIO_Init(GPIOD, &GPIO_InitStruct);
    }
    
    void InitTimeTimer(void)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
        TIM3->PSC = 41999;
        TIM3->ARR = 1;
        TIM3->DIER = TIM_DIER_UIE; // Enable update interrupt (timer level)
        TIM3->CR1 = TIM_CR1_CEN;   // Enable timer
    }
    
    
    volatile uint8_t TimerFlag = 0;
    volatile int32_t TimeElapsed = 0;
    
    
    int main(void)
    {
        SystemInit();
    
        GPIO_setup();
        InitTimeTimer();
    
        NVIC_EnableIRQ(TIM3_IRQn); // Enable interrupt from TIM3 (NVIC level)
    
    
        float float1 = 3.14f;
    
    
        while(1)
        {
            GPIOD->ODR &= ~GPIO_Pin_13;
    
    /*
            for(cnt = 0;cnt<1000;cnt+=1)
            {
                float1 *= 5.1f;
            }
    */
    
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
    
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
    
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
    
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
    
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
            float1 *= 5.1f;
    
            GPIOD->ODR |= GPIO_Pin_13;
    
        }
    }
    
    void TIM3_IRQHandler(void)
    {
        if(TIM3->SR & TIM_SR_UIF) // if UIF flag is set
        {
            TIM3->SR &= ~TIM_SR_UIF; // clear UIF flag
        }
    
        TimerFlag = 1;
        TimeElapsed += 1;
    }
    Programmiert wird mit EM:Blocks.

    Vielen Dank & Gruß
    Chris
    Geändert von Che Guevara (22.01.2015 um 00:24 Uhr) Grund: 2.4e-9 zu 2.4e-7 geändert

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.08.2008
    Ort
    DE
    Beiträge
    523
    1. Überprüft, ob der Prozessor wirklich mit 168MHz läuft?
    2. HardFPU auch in den Build Optionen eingestellt?
    3. Dissasembly überprüft, ob er dafür auch kompiliert?
    4. Ergebnis geprüft?
    5. Optimierung?

    mfg

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    08.09.2007
    Ort
    Berlin
    Alter
    24
    Beiträge
    1.544
    Hi,

    danke erstmal für die Antwort!
    1. Ja, ich hab mir den geviertelten Systemtakt ausgeben lassen, mein Oszi kann es leider nicht anzeigen, geht nur bis 25MHz, aber man sieht, dass es passt.
    2. __FPU_PRESENT & __FPU_USED sind beide definiert, das sollte also passen?!
    3. Nein, welche Datei meinst du genau?
    4. Nein.
    5. Hab nichts verändert, sind also alle aus.

    Hab gerade mal folgendes probiert:
    Code:
    #define CORE_SysTickEn()    (*((u32*)0xE0001000)) = 0x40000001
    #define CORE_SysTickDis()   (*((u32*)0xE0001000)) = 0x40000000
    #define CORE_GetSysTick()   (*((u32*)0xE0001004))
    
    uint32_t t1, t2, dt;
    float32_t float1 = 3.14f;
    
    
    ...
    ...
    ...
    
    
            CORE_SysTickEn();
            t1 = CORE_GetSysTick();
    
            float1 *= 5.1f;
    
            t2 = CORE_GetSysTick();
            CORE_SysTickDis();
    
            dt = (t2 - t1) - 9;
    Laut Debugger braucht die Multiplikation 13 Takte, was jetzt nicht mit meinem Ergebnis von vorhin zusammenpasst und außerdem immernoch zu lange ist (oder??).

    Gruß
    Chris

  4. #4
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.08.2008
    Ort
    DE
    Beiträge
    523
    3. Nein, welche Datei meinst du genau?
    Wenn du debuggst, kannst du dir den Assembler code anzeigen lassen. Denn Teil mit der Multiplikation mal posten.

    5. Hab nichts verändert, sind also alle aus.
    Ohne Optimierung benötigt eine Berechnung oft ein vielfaches als mit Optimierung.

    Und ich bezweifle, dass 50 Multiplikation auch nur 50 Takte insgesamt benötigen.

    mfg

  5. #5
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    08.09.2007
    Ort
    Berlin
    Alter
    24
    Beiträge
    1.544
    Sorry für die blöde Frage, aber wie lasse ich mir das Assembler file anzeigen? Hab da nirgends was gefunden.
    Wenn ich Breakpoints setze oder auch beim Debuggen einzelne Schritte ausführe (mit f10 / f11), wird mir die aktuelle Position im Programm nur im normalen Code angezeigt. Zu sehen, was da auf ASM Höhe passiert, wäre wirklich interessant!

    Laut dieser Tabelle ( http://infocenter.arm.com/help/index.../BEHJADED.html ) braucht eine FPU-Multiplikation nur 1 Takt.
    Aber klar du hast Recht, es dauert wohl schon länger wegen speichern etc...
    Mit Optimierung ist es übrigens tatsächlich um EINIGES schneller, meine Versuche decken sich annähernd mit denen: http://blog.stm32f4.eu/category/fpu/

    Das einzige, was ich noch nicht in den Griff bekommen habe, ist der CORE_SysTick.
    Sobald die Optimierungen eingeschaltet sind (egal welcher Level), funktioniert das nicht mehr:
    Code:
            CORE_SysTickEn();
            t1 = CORE_GetSysTick();
    
            float1 = float2 * float3;
    
            t2 = CORE_GetSysTick();
            CORE_SysTickDis();
    
            dt = (t2 - t1) - 9;
    Dabei stehen nur konstante Werte in t1 & t2 (beide als volatile, aber auch ohne bringt nichts).

    Gruß
    Chris

  6. #6
    Ich denke, der Hase liegt bei der fehlenden Aktivierung der FPU im Pfeffer. Leider verliert das Referenc Manual zum Thema kein einziges Wort, dafür muss man auf das Dokument PM0214 ausweichen. Ab Seite 236 geht das da dann um die Konfiguration der FPU. Auf Seite 241 wird einem dann mitgeteilt, dass die FPU per Default nicht aktiv ist. Da ich nicht genau weiß, was alles in den Headern steht, würde ich das mal als nächsten Anhaltspunkt wählen.
    Zu dem Teil mit dem Systick: Ich nehme an, die Makros sind nicht selbst gebaut? Ich würde da empfehlen, sich einmal das Referenc Manual zu gemüte zu führen und dann die Konfiguration für den SysTick daraus zusammen zu bauen.

    Gruß Jannis

  7. #7
    Erfahrener Benutzer Lebende Robotik Legende Avatar von PICture
    Registriert seit
    10.10.2005
    Ort
    Freyung bei Passau in Bayern
    Alter
    66
    Beiträge
    10.969
    Hallo!

    @ Che Guevara

    Zitat Zitat von Wsk8 Beitrag anzeigen
    Und ich bezweifle, dass 50 Multiplikation auch nur 50 Takte insgesamt benötigen.
    Ich auch, weil man die CPU Takte in einer Hochsprache nicht wie im ASM betrachten darf (das ist vom Compiler abhängig).

    Um ein Code in ASM zu haben, muss man das Teil des Programms in Hochsprache disassemblieren.
    MfG (Mit feinem Grübeln) Wir unterstützen dich bei deinen Projekten, aber wir entwickeln sie nicht für dich. (radbruch) "Irgendwas" geht "irgendwie" immer...(Rabenauge) Machs - und berichte.(oberallgeier) Man weißt wie, aber nie warum. Gut zu wissen, was man nicht weiß. Zuerst messen, danach fragen. Was heute geht, wurde gestern gebastelt. http://www.youtube.com/watch?v=qOAnVO3y2u8 Danke!

  8. #8
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.08.2008
    Ort
    DE
    Beiträge
    523
    Sorry für die blöde Frage, aber wie lasse ich mir das Assembler file anzeigen? Hab da nirgends was gefunden.
    Wenn ich Breakpoints setze oder auch beim Debuggen einzelne Schritte ausführe (mit f10 / f11), wird mir die aktuelle Position im Programm nur im normalen Code angezeigt. Zu sehen, was da auf ASM Höhe passiert, wäre wirklich interessant!
    Debug->Debugging Windows->Disassembly

    Das einzige, was ich noch nicht in den Griff bekommen habe, ist der CORE_SysTick.
    Sobald die Optimierungen eingeschaltet sind (egal welcher Level), funktioniert das nicht mehr:
    Den Systick zur Zeitmessung zu benutzen ist suboptimal. STM32s haben normal alle einen Cycle Counter impelementiert. Damit siehst du ganz genau wie viele Zyklen zur Berechnung benutzt werden. Aber bei einer einfachen Multiplikation kann man das am einfachsten eh am Disassembly auslesen.

    mfg

Ähnliche Themen

  1. Für lange Winterabende....
    Von oderlachs im Forum Suche bestimmtes Bauteil bzw. Empfehlung
    Antworten: 33
    Letzter Beitrag: 19.06.2016, 20:40
  2. [ERLEDIGT] I2C Master braucht sehr lange um ein Byte zu schreiben
    Von wolf112 im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 2
    Letzter Beitrag: 29.12.2011, 22:28
  3. Servo braucht zu lange
    Von RAM im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 5
    Letzter Beitrag: 11.11.2007, 18:18
  4. Wie lange braucht PWM zum wechseln des Tastverhältnisses?
    Von stefan_Z im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 0
    Letzter Beitrag: 22.09.2007, 15:11
  5. Wie lange braucht der RN-Control zum Einlesen eines A/D-Pin?
    Von ch4 im Forum Schaltungen und Boards der Projektseite Mikrocontroller-Elektronik.de
    Antworten: 2
    Letzter Beitrag: 19.12.2005, 20:40

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •