Forum: Mikrocontroller und Digitale Elektronik uint16_t Division compilerabhängig? HardFault bei bestimmtem Compiler


von ide (Gast)


Lesenswert?

Hallo,

habe ein seltsames Problem festgestellt, als ich versucht habe eine 
andere IDE zu verwenden. Ich weiß auch, dass man solche Divisionen auf 
Mikrocontrollern aus Zeitgründen vermeiden sollte, aber die Funktion 
wird nur einmal zu Beginn aufgerufen, von daher nicht zeitkritisch.

Unter KEIL µVision 5 funktioniert die Division
"wSlope = wCalibValue/wCalibCurrent;"
ohne Probleme. In der IAR Embedded Workbench IDE (7.70) geht der STM32F0 
aber nach dieser Zeile in den HardFaultHandler. Weiß jemand woran es 
liegen könnte?


Die Funktion macht eigentlich nichts anderes als Daten aus dem Flash 
lesen und dann aus ihnen eine Steigung bestimmen.
1
void calculateNominalCurrents(volatile uint16_t* CalibrationArray, uint8_t ch){
2
   uint16_t* flashPtr = (USIGN16*)CAL_FLASHPAGEBASEADDR;
3
   uint8_t i = 0;
4
   uint16_t wCalibCurrent, wCalibValue, wSlope;
5
    
6
7
   wCalibCurrent   = (USIGN16)(*(flashPtr + 8*(ch+1)+2));
8
   wCalibValue     = (USIGN16)(*(flashPtr + 8*(ch+1)+3));
9
   wSlope = wCalibValue/wCalibCurrent;
10
       ...
11
}

von Dr. Sommer (Gast)


Lesenswert?

Wenn wCalibCurrent = 0 ist, gibts eine Exception.

von ide (Gast)


Lesenswert?

Achja,  wCalibCurrent und wCalibValue sind nicht 0, wenns an die 
Division geht. Division durch 0 kann es also eigentlich nicht sein.

von ide (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Wenn wCalibCurrent = 0 ist, gibts eine Exception.

Mist, ich dachte ich wär noch schnell genug mit dem zweiten Post. Daran 
dachte ich auch, aber die Daten werden aus dem Flash geholt und sind 
nicht 0.

von (prx) A. K. (prx)


Lesenswert?

ide schrieb:
>    uint16_t* flashPtr = (USIGN16*)CAL_FLASHPAGEBASEADDR;
>    wCalibCurrent   = (USIGN16)(*(flashPtr + 8*(ch+1)+2));
>    wCalibValue     = (USIGN16)(*(flashPtr + 8*(ch+1)+3));

Du hast verifiziert, dass diese Rechnerei die richtige Adresse ergibt?

von Clemens L. (c_l)


Lesenswert?

Was sind denn die genauen Werte?

von ide (Gast)


Lesenswert?

A. K. schrieb:
> ide schrieb:
>>    uint16_t* flashPtr = (USIGN16*)CAL_FLASHPAGEBASEADDR;
>>    wCalibCurrent   = (USIGN16)(*(flashPtr + 8*(ch+1)+2));
>>    wCalibValue     = (USIGN16)(*(flashPtr + 8*(ch+1)+3));
>
> Du hast verifiziert, dass diese Rechnerei die richtige Adresse ergibt?

Ja, es funktioniert unter KEIL und auch unter IAR werden die Daten aus 
dem Flash gelesen. Habe einen Breakpoint in die Zeile mit der Division 
gesetzt und gesehen, dass die Werte zugewiesen waren.

von ide (Gast)


Lesenswert?

Clemens L. schrieb:
> Was sind denn die genauen Werte?

CalibValue ist 135, CalibCurrent ist 5 bei der ersten Rechnung und nach 
dieser gehts auch schon in den HardFault.

von (prx) A. K. (prx)


Lesenswert?

Wie sieht der Asm-Code der Division denn aus? Der CM0 hat keinen 
Divisionbefehl. Wenn du da die falsche Runtime-Lib erwischst, dann 
scheppert es.

von Hanswurst (Gast)


Lesenswert?

Wie genau ist denn der HardFault qualifiziert? Da gibt es ja einige 
Register die entsprechend gesetzt werden. Das steht aber genau im 
Manual, was da angezeigt wird und was man dazu tun muss.

von Horst (Gast)


Lesenswert?

Hmm, leider F0, dann kann man nicht so viel über den Grund des 
Hardfaults rausfinden leider.
Alignment Fehler sollte es bei soft division auch nicht sein..

Da bleibt wohl nur noch übrig den ASM-Code anzusehen.

von Hanswurst (Gast)


Lesenswert?

Mist! Kein CFSR und kein HFSR.

Aber es gibt wohl doch einige Tips, wie ich z.B. hier sehe: 
https://community.arm.com/thread/5414

von pxc (Gast)


Lesenswert?

Danke für die rege Beteiligung soweit. Ich werde den ASM-Code morgen mal 
nachliefern, von beiden KEIL und IAR, meine Assembler-Kenntnisse halten 
sich leider in Grenzen.

Hab beim Portieren schon interessante Sachen festgestellt, aber dass es 
selbst bei einer Division hakt hätte ich nicht erwartet.



Hanswurst schrieb:
> Mist! Kein CFSR und kein HFSR.
>
> Aber es gibt wohl doch einige Tips, wie ich z.B. hier sehe:
> https://community.arm.com/thread/5414

Ich werds mir morgen genauer ansehen, vor allem das mit dem Stack ist 
interessant. Habe da vielleicht schon einen kleinen Verdacht wegen der 
Stack-Größe. Nicht dass der IAR-Compiler die Division so umständlich 
baut, dass da irgendwas überläuft.

von ide (Gast)


Lesenswert?

Hoppla, Name gewechselt. Der Post oben ist von mir.

von Seastian (Gast)


Lesenswert?

Hallo,

wenn Du den Pointer hochzählst sollte das mit der "sizeof" des Datentyps 
sein.

Es kommt auch drauf an wie die Daten hintereinander liegen, ist eine 
32Bit Architektur aber Du hast ein Datum von 16Bit, ein 16Bit-Wert kann 
in einer Zelle liegen, aber auch 2 in einer SpeicherZelle?

Und man muss aufpassen wegen unaligned access: 
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/BABFAIGG.html

Wenn Du weißt woran es liegt, schreib mal, ich lerne auch gern immer was 
dazu.

Grüße

Sebastian

von zeigerarithmetik (Gast)


Lesenswert?

Seastian schrieb:
> wenn Du den Pointer hochzählst sollte das mit der "sizeof" des Datentyps
> sein.

wie meinst du das?

von Nop (Gast)


Lesenswert?

Da könnte sein.

wCalibCurrent   = (USIGN16)(*(flashPtr + 8*(ch+1)+2));
wCalibValue     = (USIGN16)(*(flashPtr + 8*(ch+1)+3));

Vielleicht verhakt er sich damit ja bei der Pointer-Arithmetik. Wenn 
dann wCalibValue nur in der Division gebraucht wird, eliminiert er 
vielleicht die lokale Variable und setzt in der Division direkt diese 
Pointer-Dereferenzierung.

Wenn's das ist, ersetz die Division da doch mal testweise durch eine 
Addition. Nur um zu schauen, ob es dann immer noch crasht.

Wie sind die Daten im Flash abgelegt, byteweise als 8-Bit-Werte? Oder 
sind das im Flash auch uint16_t?

von (prx) A. K. (prx)


Lesenswert?

Nop schrieb:
> vielleicht die lokale Variable und setzt in der Division direkt diese
> Pointer-Dereferenzierung.

Wie soll das funktionieren? Die Division ist sehr wahrscheinlich eine 
Funktion der Laufzeitbibliothek des Compilers.

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

A. K. schrieb:
> Wie soll das funktionieren?

Naja indem er direkt vor dem Aufruf der Divisionsfunktion erst das Laden 
macht, also die Zeile mit dem Laden nicht IN der Zeile ausführt. Der 
Effekt wäre, daß er scheinbar bei der Division abschmiert, in Wahrheit 
aber die Zeile davor mit dem Laden die Ursache ist. Ich hatte schon 
unterhaltsame Fehler, weil der Sourcelevel-Debugger da nicht immer 1:1 
mit dem Quellcode einhergeht.

Abhilfe schafft es natürlich, sich im Debugger neben dem Quellcode den 
Maschinencode anzuzeigen und anstatt per Singlestep durch den C-Code zu 
gehen, per Singlestep durch den Maschinencode zu gehen.

Oder eben die Division durch die Addition zu ersetzen. Wenn das Laden 
die Ursache ist, wird er da genauso abstürzen wie bei einer Division.

von (prx) A. K. (prx)


Lesenswert?

Nop schrieb:
> Naja indem er direkt vor dem Aufruf der Divisionsfunktion erst das Laden
> macht, also die Zeile mit dem Laden nicht IN der Zeile ausführt.

Deshalb auch die Frage nach dem Code, und ob die Adresse wirklich 
stimmt.

> Abhilfe schafft es natürlich, sich im Debugger neben dem Quellcode den
> Maschinencode anzuzeigen und anstatt per Singlestep durch den C-Code zu
> gehen, per Singlestep durch den Maschinencode zu gehen.

Richtig, das wäre der nahe liegende Ansatz.

von ide (Gast)


Angehängte Dateien:

Lesenswert?

Das ist jetzt die Disassembly vom IAR, ich habe den Breakpoint in der 
Zeile gesetzt, in der wohl die Funktion für die Division aufgerufen 
wird, danach zwei mal den Single Step gemacht und direkt im 
HardFaultHandler gelandet.

Die Daten im Flash habe ich auch mal hochgeladen. Für die erste Rechnung 
wird die 0x015F und die 0x0005 aus dem Flash geholt und diese sollen 
dann dividiert werden.

von ide (Gast)


Lesenswert?

Nop schrieb:
> Wenn's das ist, ersetz die Division da doch mal testweise durch eine
> Addition. Nur um zu schauen, ob es dann immer noch crasht.

Addition funktioniert und es kommt auch das erwartete Ergebnis dabei 
raus. Er scheint nur die Division nicht zu mögen.



@ Sebastian

Meinst du mit der Ausrichtung little und big Endian? Die Daten scheinen 
vor der Division zumindest richtig aligned in den Registern R0 und R1 zu 
stehen.

von Horst (Gast)


Lesenswert?

ide schrieb:
> Meinst du mit der Ausrichtung little und big Endian? Die Daten scheinen
> vor der Division zumindest richtig aligned in den Registern R0 und R1 zu
> stehen.

Nein, zum Beispiel hatte ich bei Verwendung der FPU mal das gleiche 
Problem, dass der immer im Hardfault gelandet ist. Und das lag daran, 
dass die Floats nicht an einer Adresse die durch 4 teilbar ist gestartet 
haben. Wüsste aber nicht, warum das hier bei einer 
Soft-Division-Funktion ein Problem sein sollte. Scheint außerdem ja auch 
zu laden in die Register.

Dein Stackpointer scheint mir aber an recht niedrieger Adresse zu sein. 
Kann es sein, dass bis dorthin noch Daten im RAM sind?

von Horst (Gast)


Lesenswert?

Im Zweifel schau dir also auch mal die unterschiedlichen Linkerfiles und 
Startup-Skripte an, wo hier das Stackend liegt und ob es dann richtig 
gesetzt wird (erster Eintrag in der Vector Table als Beginn des Stacks).

von Nop (Gast)


Lesenswert?

Bild 2 sagt es sehr deutlich: Da, wo wo _aeabi_idivmod sein sollte, ist 
kein Code im Flash, sondern alles ist 0xff. Das sind keine 
Instruktionen, und deswegen stürzt der Controller ab, wenn er dorthin 
springt.

Vermutlich ein Problem im Linker-Setup.

von Horst (Gast)


Lesenswert?

Nop schrieb:
> Bild 2 sagt es sehr deutlich: Da, wo wo _aeabi_idivmod sein
> sollte, ist kein Code im Flash, sondern alles ist 0xff. Das sind keine
> Instruktionen, und deswegen stürzt der Controller ab, wenn er dorthin
> springt.
>
> Vermutlich ein Problem im Linker-Setup.

In der Tat, völlig übersehen. Welcher Controller genau und welcher 
Debugger?

von ide (Gast)


Angehängte Dateien:

Lesenswert?

@ Horst und Nop

Ich habe das ganze mal in die main eingefügt und dort scheint die 
Division zu klappen.
1
int main(){
2
...
3
 USIGN16* flashPtr = (USIGN16*)CAL_FLASHPAGEBASEADDR;
4
 USIGN8 i = 0;
5
 USIGN16 wCalibCurrent, wCalibValue, wSlope;
6
         
7
 ch = 0;
8
 wCalibCurrent   = (USIGN16)(*(flashPtr + 8*(ch+1)+2));
9
 wCalibValue   =  (USIGN16)(*(flashPtr + 8*(ch+1)+3));
10
 wSlope = wCalibValue/wCalibCurrent;
11
12
...
13
}

Ich glaube in der Startup-Datei, die KEIL benutzt konnte man die 
Stack-Größe einstellen. Unter IAR finde ich es nicht. Weiß einer wo man 
sie einstellen kann?

von ide (Gast)


Lesenswert?

Horst schrieb:
> In der Tat, völlig übersehen. Welcher Controller genau und welcher
> Debugger?

STM32F0C8 und IAR Debugger. Die Division funktioniert in der main, in 
der Funktion nicht.

von (prx) A. K. (prx)


Lesenswert?

ide schrieb:
> Ich glaube in der Startup-Datei, die KEIL benutzt konnte man die
> Stack-Größe einstellen. Unter IAR finde ich es nicht. Weiß einer wo man
> sie einstellen kann?

Wenn kein Division-Code im Flash ist, dann ist der Stack erst einmal 
uninteressant.

von (prx) A. K. (prx)


Lesenswert?

ide schrieb:
> STM32F0C8

Unter dieser exakten Bezeichnung finde ich nichts. Google auch nicht.

von ide (Gast)


Lesenswert?

A. K. schrieb:
> Wenn kein Division-Code im Flash ist, dann ist der Stack erst einmal
> uninteressant.

Hatte den Code für die Division auch in der main stehen um zu testen ob 
sie überhaupt geht und es ging.

Hatte ihn dann drin gelassen und danach die eigentliche Funktion 
aufgerufen und jetzt gehts auch in der Funktion... Wie kann das sein? 
Sobald ich die paar Zeilen in der main auskommentiere geht es wieder 
nicht.

Danke für die Hilfe bisher :-)

von ide (Gast)


Lesenswert?

A. K. schrieb:
> Unter dieser exakten Bezeichnung finde ich nichts. Google auch nicht.

Sorry, meinte STM32F030C8. Ob die Division in der aufgerufenen Funktion 
klappt ist abhängig ob in der main ein paar Zeilen mehr oder weniger 
stehen. Ist das ein Linker-Problem? Wenn ja, was kann man da tun?

von (prx) A. K. (prx)


Lesenswert?

Das ist nicht zufällig eine IAR Kickstart Version, die beim Cortex M0 
nur 16KB Code unterstützt?

: Bearbeitet durch User
von ide (Gast)


Lesenswert?

A. K. schrieb:
> Das ist nicht zufällig eine IAR Kickstart Version, die beim Cortex
> M0
> nur 16KB Code unterstützt?

Es ist eine Testversion, die allerdings eine Zeitbeschränkung und keine 
Code-Beschränkung hat. Die Code-Größe insgesamt ist schon über 35K und 
die Division in der Funktion funktioniert ja auch mit ein paar Zeilen 
mehr in der main und nicht weniger.

von Karl (Gast)


Lesenswert?

- Map-File oder Symboltabelle anschauen
- Speicher an den entsprechenden Stellen wo die Funktion stehen sollte 
im Binary prüfen (wird es falsch erzeugt oder falsch programmiert?)
- Wenn man sich den 2. Screenshot ansieht, sind noch deutlich mehr 
Funktionen von der FF-Eritis betroffen. Herausfinden, wo das anfängt 
(und ob das wieder aufhört).
- Prüfen, ob an den entsprechenden Addressen irgendetwas im 
Linker-Skript passiert oder gar der Flash aus ist?
- Sind das irgendwelche verkrüppelte Demo-Versionen? (Wer hat schon Keil 
und IAR gleichzeitig im Zugriff?)
- Falls alles bezahlt -> Support des Herstellers. (Habe auch schon 
komische Sachen bei einem TriCore mit dem TASKING Compiler erlebt. Der 
ist bei einer bestimmten Kombination selbst in den Tod gesprungen)
- Alle Warnungen des Linkers anschalten und dem nachgehen

- arm-none-eabi-gcc nehmen (SCNR)

von Sebastian (Gast)


Lesenswert?

Hallo,

Horst hat es gesagt, hatte Probleme dass die Adresse nicht durch 4 
teilbar war,.. "unaligned access".


Du wirst dasselbe Problem haben wenn Du die Werte nur "umspeicherst", 
probier mal, lass mal division,.. alles weg, oder mach eine 
Addition,.... wird auch crashen.

Grüße

Sebastian

von Horst (Gast)


Lesenswert?

Karl schrieb:
> - arm-none-eabi-gcc nehmen (SCNR)

FullACK ;)

Das Linkerscript fehlt noch wegen Stackgröße.

Iar debugger heißt die Software? Also ich will nur ausschließen, dass es 
kein JLink ist. Hatte da auch in der STM32F0 Serie, dass das Flash nicht 
richtig beschrieben wurde.
Also im Zweifel nochmal schauen ob im Binary auch alles FF ist oder ob 
es beim Schreiben irgendwie verloren gegangen ist

von Karl (Gast)


Lesenswert?

Sebastian schrieb:
> Du wirst dasselbe Problem haben wenn Du die Werte nur "umspeicherst",
> probier mal, lass mal division,.. alles weg, oder mach eine
> Addition,.... wird auch crashen.

Hat er doch schon probiert. Auslesen aus dem Falsh klappt, aber da wo 
die divisions-Routine im Flash sein sollte steht halt nur 0xFF

von Karl (Gast)


Lesenswert?

Horst schrieb:
> Also ich will nur ausschließen, dass es
> kein JLink ist. Hatte da auch in der STM32F0 Serie, dass das Flash nicht
> richtig beschrieben wurde.

Vom J-Link hört man immer wieder solche Sachen. Scheint ziemlich 
ausgefuchst zu sein mit viel Caching auf dem Debugger und ständigem neu 
flashen für unendliche Breakpoints.

von ide (Gast)


Lesenswert?

Das Problem hat sich erübrigt, nachdem ich weiter oben im Code ein 
FLASH_Lock() hinzugefügt habe. Anschließend trat es nicht mehr auf.

von Dr. Sommer (Gast)


Lesenswert?

ide schrieb:
> Das Problem hat sich erübrigt, nachdem ich weiter oben im Code ein
> FLASH_Lock()

Das klingt, als hättest du im Code "wilde" Flash-Schreibzugriffe, die 
deinen Divisionscode löschen würden, die du jetzt blockiert hast. Da 
würde ich ja lieber versuchen diese Zugriffe ausfindig zu machen anstatt 
das Symptom zu beheben...

von ide (Gast)


Lesenswert?

Dr. Sommer schrieb:
> ide schrieb:
>> Das Problem hat sich erübrigt, nachdem ich weiter oben im Code ein
>> FLASH_Lock()
>
> Das klingt, als hättest du im Code "wilde" Flash-Schreibzugriffe, die
> deinen Divisionscode löschen würden, die du jetzt blockiert hast. Da
> würde ich ja lieber versuchen diese Zugriffe ausfindig zu machen anstatt
> das Symptom zu beheben...

Das könnte natürlich sein. Danke für den Tipp. Werde morgen mal den Code 
nach Schreibzugriffen absuchen.

Und danke an alle, die geholfen haben dem Fehler auf die schlichte zu 
kommen.

von karl (Gast)


Lesenswert?

Und? Was gefunden?

von Etzala reichts (Gast)


Lesenswert?

Ja :-)

Das Problem war ein #define EEPROM_EMULATION_START_ADDRESS 0x8007000, 
das voll in den Code-Bereich zeigte, nachdem sich der Code die letzten 
Tage um mehr als 10KB vergrößert hat.

Der neue Inhalt an der Stelle hat den Zustandsautomat der 
EEPROM-Emulation ziemlich irritiert, worauf dieser sich mit dem Löschen 
seiner zugewiesenen Pages bedankte, um für sich einen definierten 
Zustand wieder herzurichten. Zufälligerweise Stand dort meine Division.

Hab das ganze jetzt ganz nach hinten auf Page 62 & 63 verfrachtet und 
jetzt ist alles gut.

von ide (Gast)


Lesenswert?

Herrgott, dass sich jeder Browser den Namen merken muss, den man 
irgendwann eingetippert hat.

von karl (Gast)


Lesenswert?

Willst noch was für die zukunft lernen oder Bist happy?

von ide (Gast)


Lesenswert?

Jetzt gehts bestimmt um die Division an sich, oder die wilde 
Flashaddressierung, oder den "Bezeichnungsmix" unint und USIGN (der 
wurde schon bereinigt) :-)

Schieß los, wenn du willst. Ich hab für Dinge die man besser machen 
könnte immer ein offenes Ohr.

von karl (Gast)


Lesenswert?

Mit so einem kleinkram halte ich mich nicht auf. Typedefs soll doch 
jeder machen Wie er will. Macht jeder sowieso so.

Worauf ich hinauswollte:es gibt ein Programm das sich sozusagen 
hauptberuflich mit der Vergabe von speicheradressen beschäftigt. Es ist 
der linker. Wenn du die Inhalte eines  speichersegments beeinflussen 
willst sollte das dem compiler und linker auch bekannt sein. Also 
definiere eine entsprechende output section und übergib dem Compiler die 
entsprechenden Adressen über Symbole aus dem linker. Dann gibt es 
zumindest eine halbwegs aussagekräftige Fehlermeldung.

von ide (Gast)


Lesenswert?

Werde ich mir mal anschauen. Assembler, Linker usw. sind leider noch 
Neuland für mich.

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.