Hallo zusammen
Ich habe hier eine Applikation in welcher ein STM32F103 als USB-Device
(HID) an einem PC hängt. Dieses Device emuliert einen Touchscreen.
Code gibts hier:
https://github.com/chandong83/stm32_i2c_to_usb_hid_multitouch
Nun ist es so, dass bei intensiver nutzung des Touchscreens und damit
hohem Datenaufkommen, nach kurzer Zeit (2-8 Sekunden) ein HardFault
eintritt.
Dieser Fault habe ich nun mit dem FaultAnalyzer (Kauf von Atoolic durch
ST sein Dank ist dieser ja nun kostenfrei nutzbar) im STM32CubeIDE
analyziert.
Es handelt sich um einen PRECISERR, sowie Bus, Memory management or
usage fault. (FORCED BIT gesetzt)
BFAR: 0x3002bd9f
sp (MSP): 0x20004E90
lr: 0x80061C3
pc: 0x8005272
xpsr: 0x61000024
Nun erinnere ich mich, dass das Bit2 beim lr angibt, ob der MainStack
oder ProcessStack gültig war.
1
The current link register LR contains the EXC_RETURN value for the exception being serviced and this value indicates which stack holds the preserved register values from the application context. If bit 2 of the EXC_RETURN is zero then the main stack (MSP is saved) was used, else the process stack was used.
In meinem Fall ist Bit2 von LR jedoch 1. Somit war der ProcessStack
gültig.
Doch wo finde ich diesen?
Vielen Dank für eure Unterstützung.
Asynchronous bus faults are described as imprecise bus faults and can happen when there is write buffering in the processor design. As a result, the processor pipeline proceeds to the subsequent instruction execution before the bus error response is observed. When an asynchronous bus fault is triggered, the BusFault exception is pended. If another higher priority interrupt event arrived at the same time, the higher priority interrupt handler is executed first, and then the BusFault exception takes place. If the BusFault handler is not enabled, the HardFault exception is pended instead. A HardFault caused by an asynchronous BusFault never escalates into lockup. Asynchronous faults are often unrecoverable, as you do not know which code caused the error.
Klingt jedoch so, als könnte die ursache ein zu hoch priorisierter
interrupt sein?
Holger schrieb:> Ich vermute einen Bufferoverflow irgendwo. Aber wie könnte man so einen> finden?
Muss nicht bufferoverflow sein.
At To, hast du dieses Dokument angeschaut:
http://www.keil.com/appnotes/files/apnt209.pdf
Dort wird beschrieben, wie man rausfinden kann, welcher code genau einen
Fault verursacht.
Gruß
Danke für deinen Link.
Ja, genau dieses Dokument habe ich einen Beitrag weiter oben verlinkt :)
Bisher habe ich damit aber noch keine weiterführenden Informationen
gefunden. Aber ich sehe dort, dass die den Stack entsprechend
analysieren.
Nach weiteren Versuchen habe ich nun einen PRECISERR erhalten.
Die Busfaultaddresse ist: 0x3002a59e
Doch laut ReferenceManual befindet sich an dieser Adresse überhaupt
keine Peripherie
(RM0008, Seite 50 ff.)
Hey Holger,
ich nutze zwar AtmelStudio, aber vllt. bringt dich das ein wenig weiter.
Bei meinem letzten HardFault bin ich wie folgt an das Problem
herangegangen:
Ich habe mir für alle möglichen "Systemfehler" leere Interrupt-Handler
angelegt - kann natürlich sein, dass diese bei STM Projekten bereits
existieren.
1
voidNMI_Handler(void)
2
{
3
while(1){
4
}
5
}
6
7
voidHardFault_Handler(void)
8
{
9
while(1){
10
}
11
}
12
13
voidMemManage_Handler(void)
14
...
15
voidBusFault_Handler(void)
16
17
...usw.
Den µC habe ich dann im Debug-Mode laufen lassen (JTAG), bis der Fehler
aufgetretten ist.
Zu beachten ist, dass du es aber als Release (mit optimierung) laufen
lässt aber im Projekt den Debug Level (-g3) z.b. aktivierst.
Da der Fehler evtl. gar nicht auftritt, wenn die Optimierung im Debug
Fall deaktiviert ist (Bufferoverflow, Anordnung der Variablen).
Als der µC dann hängen geblieben ist, konnte ich im Fenster
"Aufrufliste" sehen, an welcher Stelle er in den HardFault gesprungen
ist.
Dies ergab erst mal kein Sinn, aber wenn du nun noch die *.map Datei zur
hilfe nimmst, kannst du sehen welche Variablen vor oder nach der liegen,
wo er in HardFault gesprungen ist.
Bei mir war es ein Bufferoverflow (mittels Pointer) der mir danach ein
Funktionszeiger auf 0x00 gesetzt hat - tja, don't try to call a NULL
function pointer :-D
Aber somit war der Fehler gefunden.
Ich habe es auch erst mit den Bits in den Registern versucht, aber das
ist oft nur ein Hinweis.
Edit:
Sorry, hatte die letzten 2 beiträge nicht mitbekommen ;)
Was hatte der PC als Wert?
PRECISERR: Precise data bus errorWhen the processor sets this bit is 1,
it writes the faulting address to the BFAR.
0: No precise data bus error
1: A data bus error has occurred, and the PC value stacked for the
exception return points to the instruction that caused the fault.
Kannst du sehen welchen Wert dev_state hat?
Es ist ja "nur" ein Vergleich, aber wenn pdev auf einen falschen
Speicherbereich zeigen würde, dann könnte der Vergleich nicht
durchgeführt werden. Z.B. auf einen Speicherbereich der gar nicht
existiert.
Das habe ich mir auch gedacht. Ich glaube aber, dass ich dev-state mit
dem Debugger nicht mehr analysieren kann.
Ich könnte jedoch den Wert von DevState zuvor in einer Variable
speichern...
Nur so eine Idee:
wenn ein Fehler nach gewisser Laufzeit auftritt, mache ich als ersten
den Stack-Bereich grösser. Wenn es dann länger dauert, oder gar nicht
passiert, wird es daran gelegen haben.
Tritt der Fehler auch auf, wenn du das Touch nicht nutzt?
In der Datei "usbd_core.c" werden diverse USB Aktionen behandelt.
Was ist wenn der Host dein Device vom Bus schmeißt oder etwas anderes
provoziert (bedingt durch intensive Nutzung).
Dann könnte ja pdev evtl. gar nicht initialisert sein:
Dann funktioniert es auch nicht mit dem Vergleich.
Dies ist auch nur so eine Idee, hab die HAL nicht aufm Rechner, deshalb
gestaltet es sich recht schwer, die ganzen Zuordnungen zu finden :-)
Adam P. schrieb:> Wäre halt interessant zu wissen wohin pdev zeigt.
Definitiv. Da arbeite ich noch dran eine Lösung zu finden, um den Wert
anzuzeigen.
pegel schrieb:> Nur so eine Idee:> wenn ein Fehler nach gewisser Laufzeit auftritt, mache ich als ersten> den Stack-Bereich grösser. Wenn es dann länger dauert, oder gar nicht> passiert, wird es daran gelegen haben.
Es ist nicht die reine "Zeit" welche hier entscheidend ist. Es scheint
mir, als ob die Anzahl an übertragenen USB-Paketen entscheidend sind.
Denn ich muss den Touch mit fünf Fingern (Multitouch) verwenden und
"herumspielen" damit dann nach ca. 3-5 Sekunden ein Fault eintritt.
Benutze ich den Touch nicht und lasse ihn herumliegen, funktioniert er
auch noch nach einigen Minuten... Wenn ich dann nur wenige Eingaben
mache, gibt es auch keine Probleme. Nur bei "intensiver" Nutzung.
Dann setzt ein Break Point und schaust welche Adresse er im normal
Betrieb hat...dann lässt es weiter laufen bis der Fehler auftritt.
Und schaust was my_pdev sagt...solltest du da so nicht herankommen, dann
schau im *.map File wo dein my_pdev im RAM liegt und schau was da drin
steht.
Oder?
Danke für deinen Vorschlag.
Habe dies nun so umgesetzt. Nach dem Hardfault kann ich über die
Expressions nicht mehr auf die Variable zugreifen. Da kommt:
1
Multiple errors reported.
2
3
1) Unable to create variable object
4
5
2) Failed to execute MI command:
6
-data-evaluate-expression pdev
7
Error message from debugger back end:
8
No symbol "pdev" in current context.
9
10
3) Failed to execute MI command:
11
-var-create - * pdev
12
Error message from debugger back end:
13
-var-create: unable to create variable object
14
15
4) Failed to execute MI command:
16
-var-create - * pdev
17
Error message from debugger back end:
18
-var-create: unable to create variable object
hab mal ein paar screenshorts gemacht.
Frage zu addrC.jpg. Soll ich im Speicher an Adresse 0x20000444
nachschauen? Wenn ja, dann ist addrA.jpg das passende Bild dazu.
addrD.jpg zeigt den Inhalt des speichers im korrekten Zustand. Bei
addrA.jpg ist der Inhalt beim fault zu sehen.
Ok. Hab vorhin übersehen, dass ich anstatt my_pdev nur pdev gewatcht
habe.
Nun habe ich my_pdev überwacht und, siehe da, der wert ist nun 0x2ec0030
im fault fall. und nicht mehr 0x20000444
Holger schrieb:> Bleibt die Frage, woher der falsche Pointer kommt.
Wahrscheinlich ein buffer overflow eines Buffers, der physikalisch vor
Deinem Pointer liegt. Guck da mal ins Mapfile rein, welche Variablen
davor liegen.
Hast Du Breakpoints mit write-watch? Wenn ja, dann setz mal einen
ebensolchen auf Deinen Pointer und guck, wo der überschrieben wird.
Der Fehler kann nur provoziert werden, wenn mind. 4 Finger auf dem Touch
bewegt werden. Und auch nur bei schnellen Bewegungen.
Hab inzwischen das I2C von Software zu HW gewechselt. Ohne veränderungen
auf das Fehlerbild.
Nop schrieb:> Hast Du Breakpoints mit write-watch? Wenn ja, dann setz mal einen
Ich glaube der STM32 hat sowas (tolles) leider nicht.
Nun habe ich einen neuen witzigen Fehler.
1
if(pdev->dev_state==USBD_STATE_CONFIGURED)
2
{
3
if(hhid->state==HID_IDLE)
4
{
5
hhid->state=HID_BUSY;
6
USBD_LL_Transmit(pdev,
7
HID_EPIN_ADDR,
8
report,
9
len);
10
}
pdev->dev_state ist nun = 5.
Ich glaube ich sehe langsam das Fehler bild.
Nun gab es keinen HardFault. Warum? Weil bei einem Wert von 5 keine
Daten mehr gesendet werden, da USBD_STATE_CONFIGURED = 3 ist.
Interessanterweise ist jedoch 5 kein gültiger Wert für dev_state. Also
wurde wieder irgendwo ein Speicherbereich überschrieben.
Könnte ich nun einen Write-Watch auf diese Adresse legen? Vorausgesetzt,
der STM hätte sowas?
Holger schrieb:> Hab inzwischen das I2C von Software zu HW gewechselt. Ohne veränderungen> auf das Fehlerbild.
Methodisch vorgehen wie angeregt magst Du also nicht. Naja, dann bleibt
halt nur Rumprobieren.
Holger schrieb:> Könnte ich nun einen Write-Watch auf diese Adresse legen? Vorausgesetzt,> der STM hätte sowas?
Ah hat sich überschnitten. Das müßte im Debugger gehen, bei den
Breakpoints. Ansonsten halt noch die Empfehlung mit dem Mapfile zur
EIngrenzung der möglichen Buffer.
Holger schrieb:> Leider finde ich bei Atollic nirgends eine entsprechende Möglichkeit für> einen write-watch...
Wenn man nach stm32 atollic breakpoint write googelt, scheint sich das
"Watchpoint" zu nennen - vielleicht hilft das weiter?
https://www.youtube.com/watch?v=Z3lQ2mFa1xI
Es empfielt sich wegen sowas immer etwas Software für die Faulthandler
einzubauen: Beitrag "ARM Cortex-M3/4/7 Faulthandler"
Ansonsten hast du noch nicht geschrieben was zum touchen genutzt wird
und wo das reinschreibt.
Das wird ja irgendwo nen Bufefr haben der speichert was eingegeben
wurde.
Den auch mal im mapfile suchen ob der vor den Variablen des USB Stack
liegt und dann mit Trace printfs (vllt sogar in schnell über SWO) gucken
wie groß der wird.