2013-03-14 3 views
7

ZusammenfassungGCC 4.7.2 Optimierungsprobleme

Ich ST USB OTG-Bibliothek zu einer benutzerdefinierten STM32F4 Board mit der neuesten Version von Sourcery Codebench Lite Werkzeugkette (GCC Arm-keine-EABI 4.7.2) zu portieren.

Wenn ich den Code mit -O0 kompiliere, läuft das Programm gut. Wenn ich mit -O1 oder -O2 kompiliere, schlägt es fehl. Wenn ich sage scheitern, hört es einfach auf. Kein harter Fehler, nichts (Naja, offensichtlich gibt es etwas, was es tut, aber ich habe keinen Emulator zum Debuggen und finde es heraus, es tut mir leid. Mein Fehler-Handler wird nicht aufgerufen).

Einzelheiten

Ich versuche, einen Aufruf an die folgende Funktion zu machen ...

void USBD_Init(USB_OTG_CORE_HANDLE *pdev, 
      USB_OTG_CORE_ID_TypeDef coreID, 
      USBD_DEVICE *pDevice,     
      USBD_Class_cb_TypeDef *class_cb, 
      USBD_Usr_cb_TypeDef *usr_cb); 

... aber es scheint nicht in die Funktion Körper zu machen. (Ist dies ein Symptom der „Stack-Smashing“?)

Die an diese Funktion übergeben Strukturen haben die folgenden Definitionen:

typedef struct USB_OTG_handle 
{ 
    USB_OTG_CORE_CFGS cfg; 
    USB_OTG_CORE_REGS regs; 
    DCD_DEV  dev; 
} 
USB_OTG_CORE_HANDLE , *PUSB_OTG_CORE_HANDLE; 

typedef enum 
{ 
    USB_OTG_HS_CORE_ID = 0, 
    USB_OTG_FS_CORE_ID = 1 
}USB_OTG_CORE_ID_TypeDef; 

typedef struct _Device_TypeDef 
{ 
    uint8_t *(*GetDeviceDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetLangIDStrDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetManufacturerStrDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetProductStrDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetSerialStrDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetConfigurationStrDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetInterfaceStrDescriptor)(uint8_t speed , uint16_t *length); 
} USBD_DEVICE, *pUSBD_DEVICE; 

typedef struct _Device_cb 
{ 
    uint8_t (*Init)   (void *pdev , uint8_t cfgidx); 
    uint8_t (*DeInit)  (void *pdev , uint8_t cfgidx); 
/* Control Endpoints*/ 
    uint8_t (*Setup)  (void *pdev , USB_SETUP_REQ *req); 
    uint8_t (*EP0_TxSent) (void *pdev);  
    uint8_t (*EP0_RxReady) (void *pdev); 
    /* Class Specific Endpoints*/ 
    uint8_t (*DataIn)  (void *pdev , uint8_t epnum); 
    uint8_t (*DataOut)  (void *pdev , uint8_t epnum); 
    uint8_t (*SOF)   (void *pdev); 
    uint8_t (*IsoINIncomplete) (void *pdev); 
    uint8_t (*IsoOUTIncomplete) (void *pdev); 
    uint8_t *(*GetConfigDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetUsrStrDescriptor)(uint8_t speed ,uint8_t index, uint16_t *length); 

} USBD_Class_cb_TypeDef; 

typedef struct _USBD_USR_PROP 
{ 
    void (*Init)(void); 
    void (*DeviceReset)(uint8_t speed); 
    void (*DeviceConfigured)(void); 
    void (*DeviceSuspended)(void); 
    void (*DeviceResumed)(void); 

    void (*DeviceConnected)(void); 
    void (*DeviceDisconnected)(void);  

} 
USBD_Usr_cb_TypeDef; 

Ich habe versucht, enthalten alle Quellcode relevant für dieses Problem. Wenn Sie den gesamten Quellcode sehen möchten, können Sie ihn hier herunterladen: http://www.st.com/st-web-ui/static/active/en/st_prod_software_internet/resource/technical/software/firmware/stm32_f105-07_f2_f4_usb-host-device_lib.zip

Lösungen Versuchte

ich mit #pragma GCC optimize ("O0") versucht zu spielen, __attribute__((optimize("O0"))) und Erklärung der Vereinbarkeit bestimmter Definitionen als volatile, aber nichts funktionierte. Ich würde lieber den Code ändern, um ihn trotzdem gut mit dem Optimierer zu spielen.

Frage

Wie kann ich diesen Code ändern, um es mit den GCC-Optimierer spielen schön zu machen?

+2

Es ist wahrscheinlich der Fall, dass beim Aktivieren von Optimierungen UB in Ihrem Code angezeigt wird. Das heißt, Ihr Code ist wahrscheinlich falsch, auch wenn Optimierungen deaktiviert sind. Sie sehen nur keine Symptome. – ildjarn

+11

Das ist eine 3,7 MB Zip-Datei, ich weiß nicht, dass irgendjemand das für Sie kostenlos debuggen würde. Der angegebene Code ist nur einige Deklarationen und sagt uns nichts. Sie sollten Ihren Code auf das absolut mögliche Minimum reduzieren und versuchen, das zu debuggen. Haben Sie auch alle Warnungen eingeschaltet und auf sie geachtet? – nos

+1

Warum kein Emulator? Vielleicht möchten Sie 15 US-Dollar in eine STM32F4DISCOVERY-Karte investieren, die über einen integrierten JTAG verfügt. Ich habe keine verwendet, und ich weiß nicht, ob die Sourcery CodeBench Lite Toolchain damit problemlos funktionieren wird, aber Sie sollten in der Lage sein, die ST USB OTG Bibliothek zu bekommen, die mit einer Toolchain gebaut wurde und läuft (wenn nicht die Sourcery Toolchain) und sehen Sie, ob Sie Probleme mit Ihrem Code haben. –

Antwort

1

Mit dem Code, den Sie angezeigt haben, scheint nichts falsch zu sein, daher wird diese Antwort allgemeiner gefasst sein.

Was sind typische Fehler mit "nah an der Hardware" -Code, die richtig nicht optimiert funktioniert und mit höheren Optimierungsstufen versagt?

Denken Sie über die Unterschiede zwischen -O0 und -O1/-O2 nach: Optimierungsstrategien sind - unter anderem - Loop Enrolling (scheint nicht gefährlich zu sein), versuchen, Werte in Registern so lange wie möglich zu halten, Eliminierung von toten Codes und Instruktionen.

Die verbesserte Registerverwendung führt normalerweise zu Problemen mit höheren Optimierungsstufen, wenn Hardwareregister, die sich jederzeit ändern können, nicht ordnungsgemäß volatile deklariert werden (siehe obigen Kommentar von PokyBrain). Der optimierte Code wird so lange wie möglich versuchen, Werte in Registern zu speichern, was dazu führt, dass Ihr Programm Änderungen auf der Hardware-Seite nicht bemerkt. Stellen Sie sicher, Hardware erklären Register volatile richtig

Beseitigung von totem Code zu Problemen führen wahrscheinlich, wenn Sie ein Hardware-Register lesen, müssen unabhängig von der Hardware an den Compiler nicht bekannt Effekt zu erzeugen und mit der nichts tun Wert, den Sie gerade gelesen haben.Diese Hardware-Zugriffe werden möglicherweise wegoptimiert, wenn Sie die für den Lesezugriff verwendete Variable void nicht korrekt deklarieren (der Compiler sollte jedoch eine Warnung ausgeben). Stellen Sie sicher, Dummy zu werfen liest (void)

Anweisung Nachbestellung: wenn Sie verschiedene Hardware-Register in einer bestimmten Reihenfolge zugreifen müssen, um die gewünschten Ergebnisse zu erzielen und wenn Sie das tun, sonst durch Zeiger nicht in irgendeiner Weise mit, der Compiler ist frei, die resultierenden Anweisungen neu zu ordnen, wie es für richtig hält (selbst wenn Hardware-Register sind korrekt deklariert volatile). Sie müssen Speicherbarrieren in Ihren Code streuen, um die erforderliche Zugriffsfolge zu erzwingen (__asm__ __volatile__(::: "memory");). Stellen Sie sicher, dass Speichersperren bei Bedarf hinzugefügt werden.

Obwohl unwahrscheinlich, könnte es immer noch der Fall sein, dass Sie einen Compiler-Fehler gefunden haben. Optimierung ist keine leichte Aufgabe, besonders wenn sie der Hardware nahe kommt. Es könnte einen Blick in die gcc-Fehlerdatenbank wert sein.

Wenn das alles nicht hilft, können Sie manchmal einfach nicht vermeiden, in den generierten Assembler-Code zu graben, um sicherzustellen, dass er das tut, was er tun soll.