uint16_t Division compilerabhängig? HardFault bei bestimmtem Compiler

Gast #4655029
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
}
Gast #4655044
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.
Gast #4655076
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.
Gast #4655140
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.
Gast #4655160
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
Gast #4655209
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?
Gast #4655260
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.
#4655271
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.
Gast #4655535
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.
Angehängte Dateien:
Gast #4655538
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.
Gast #4655542
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?
Gast #4655546
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).
Gast #4655547
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.
Gast #4655553
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?
Gast #4655556
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?
Angehängte Dateien:
Gast #4655582
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 :-)
Gast #4655586
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?
Gast #4655612
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.
Gast #4655622
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)
Gast #4655644
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
Gast #4655645
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
Gast #4655650
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
Gast #4655654
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.
Gast #4656027
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...
Gast #4656387
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.
Gast #4657286
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.
Gast #4657524
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.
Gast #4657611
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren