Forum: Mikrocontroller und Digitale Elektronik STM32F405 int64_t lehren


von Detlef _. (detlef_a)


Angehängte Dateien:

Lesenswert?

Hallo Cortex Cracks,

ich betreibe einen STM32F405 unter C und GCC. Wenn ich int64_t benutze 
friert er irgendwo ein.

Ich nehme an, dass ich nicht die richtigen libraries zulinke. Ich habe 
mal das Makefile angehängt.

Jemand einen Rat?
Danke

Cheers
Detlef

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Detlef _. schrieb:
> Wenn ich int64_t benutze friert er irgendwo ein.

Und was sagt Dein Debugger dazu?

von Detlef _. (detlef_a)


Lesenswert?

Hab keinen Debugger. Ich debugge mit printf und das geht ja dann nich 
:-/

von Sebastian V. (sebi_s)


Lesenswert?

Stimmt das Alignment? Wenn du einfach irgendwelche char Pointer zu 
int64_t Pointern castest werden manchmal Instructions generiert die 
korrektes Alignment voraussetzen.

von Detlef _. (detlef_a)


Lesenswert?

Nee, mach ich nicht, ich setz die ganz normal auf

int64_t bla;

und will sie dann benutzen.

Cheers
Detlef

von M. K. (sylaina)


Lesenswert?

Detlef _. schrieb:
> Ich debugge mit printf und das geht ja dann nich

Machst du das etwa so:
1
...
2
int64_t myInt64;
3
...
4
printf("My int64 value is: %d", myInt64);
5
...

Bekommst du beim Kompilieren irgendwelche Warnings?

von Dr. Sommer (Gast)


Lesenswert?

Initialer Stack Pointer im Linker Script falsch. Der muss auf das erste 
Byte nach dem RAM zeigen, nicht das letzte Byte im RAM. Leider weiß 
ST nicht wie die eigenen Chips funktionieren und macht das in den 
Beispiel Skripten teilweise falsch.

von Sebastian V. (sebi_s)


Lesenswert?

Detlef _. schrieb:
> und will sie dann benutzen.

Und machst was genau? Zeig mal den relevanten Codeteil in dem du den 
int64_t benutzt.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Detlef _. schrieb:
> Hab keinen Debugger. Ich debugge mit printf und das geht ja dann nich
> :-/

Du debuggst nicht, Du testest.

Ist denn Dein Controller nicht zufälligerweise auf einer dieser 
"Discovery"-Platinen drauf? Die enthalten mit "ST-Link" die Hardware, 
die nötig ist, um via JTAG oder etwas artverwandtem Debuggen zu können.

von Nop (Gast)


Lesenswert?

Detlef _. schrieb:
> Ich nehme an, dass ich nicht die richtigen libraries zulinke.

Also auf meinem F405 geht das mit 64bit-Integern und GCC problemlos, und 
ich linke überhaupt keine Libraries zu. Folglich ist es irgendwas in 
Deinem Code oder Linkerscript, aber da Du die nicht hochgeladen hast, 
kann man da nichts weiter zu sagen.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Moegliche Ursachen:
- printf kann keine 64 bit
- Stack ist nicht 8 byte aligned

von Detlef _. (detlef_a)


Angehängte Dateien:

Lesenswert?

Hallo,

danke erstmal an alle.

Ich hab son Olimex board und flashe das Ding über den eingebauten 
bootloader und debugge (teste :/) über eine serielle Schnittstelle. Hab 
kein JTAG.

@Uwe: Das ist ne Idee. Laut angehängtem, benutzten default-Linkerscript 
liegt der Stack bei _estack-__Stack_Size = 0x20020000-1024 , das ist 8 
Byte aligned, oder?

@NOP: "ich linke überhaupt keine Libraries zu.". Der STM32F405 kann 
keine 64Bit ints' nativ rechnen, der braucht dafür ne Software lib, die 
muss irgendwo her kommen.

Mache kein printf auf die 64 Bit Variablen.
Er friert bei sowas ein:

int64_t bla;
bla = (3355*bla)>>24;

Denke immer noch, dass irgendwas mit der lib-Version zum tun hat oder 
diese 'thumb' Geschichte, ist mir auch nich so richtig klar, was man 
mischen darf und was nicht.

Danke für Eure Aufmerksamkeit.
Cheers
Detlef

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Detlef _. schrieb:
> Der STM32F405 kann keine 64Bit ints' nativ rechnen, der braucht dafür ne
> Software lib, die muss irgendwo her kommen.

Das ist dann die Runtimelibrary Deines C-Compilers.

von Detlef _. (detlef_a)


Lesenswert?

Rufus Τ. F. schrieb:
> Detlef _. schrieb:
>> Der STM32F405 kann keine 64Bit ints' nativ rechnen, der braucht dafür ne
>> Software lib, die muss irgendwo her kommen.
>
> Das ist dann die Runtimelibrary Deines C-Compilers.

Ja. Erwische ich da die richtige?

von Nop (Gast)


Lesenswert?

Detlef _. schrieb:
> bla = (3355*bla)>>24;

und damit kannste Dir einen signed int overflow einhandeln, was 
undefined behaviour ist. Wenn bla hinreichend groß ist, dann ist 
(3355*bla) ein Overflow.

Abhilfe: entweder, Du begrenzt mit einem Check vorher den Wertebereich 
von bla, oder wenn der Overflow erwünscht ist, geh auf uint64_t, denn 
bei unsigned ist der Overflow definiert.

Ansonsten, wie ich schon sagte, ich linke keine Library zu (auch nicht 
die Standardbibliothek), der GCC setzt die 64bit-Befehle trotzdem 
automatisch richtig um. Natürlich nicht in 64bit-Instruktionen, die es 
auf ARM32 ja nicht gibt, sondern zerlegt in 32bit-Instruktionen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Es könnte natürlich auch sein, daß die int64_t-Unterstützung mit 
Inline-Code oder "intrinsincs" implementiert ist, d.h. der Code kommt 
nicht aus einer Library, die zum Programm dazugelinkt wird, sondern wird 
bereits vom Compiler selbst eingesetzt.

Würdest Du einen Debugger verwenden, könntest Du darüber mehr 
Informationen selbst gewinnen.

von W.S. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Es könnte natürlich auch sein, daß die int64_t-Unterstützung...

Der TO sollte doch erstmal nachschauen, was sich hinter diesem int64_t 
tatsächlich verbirgt.

Wenn ich mich recht entsinne, dann konnte bereits der ARM7TDMI in der 
Lernbetty problemlos mit int64 umgehen - und zwar sowohl per Keil als 
auch per Gcc.

W.S.

von Nico W. (nico_w)


Lesenswert?

Mein Nucleo F411RE läuft auch mit u/int64_t ohne irgend eine lib mit 
gcc. Auch ohne mathlib.

von Jim M. (turboj)


Lesenswert?

Detlef _. schrieb:
> Hab keinen Debugger. Ich debugge mit printf und das geht ja dann nich

Dann gib doch mal nur die Addresse von der int64_t Variablen mit 
printf() aus. Wenn die nicht durch 4 teilbar ist, hast Du eine Ursache 
gefunden.

Hint: Hardfault Handler implementieren und ein Blink Code ausgeben 
lassen. Dann sieht man Software Probleme schneller.

Längerfristig will man sich aber einen Debugger zulegen. Die gibt es für 
ARM auch sehr preiswert.

von Detlef _. (detlef_a)


Lesenswert?

Jim M. schrieb:

> Dann gib doch mal nur die Addresse von der int64_t Variablen mit
> printf() aus. Wenn die nicht durch 4 teilbar ist, hast Du eine Ursache
> gefunden.

durch 8 teilbar, oder !?

> Längerfristig will man sich aber einen Debugger zulegen. Die gibt es für
> ARM auch sehr preiswert.

hm, hm. für solch einen komischen Fehler ist Kenntnis eines Debuggers 
gut.

Aber ansonsten debugge ich den Code lieber vorher auf einer 
komfortableren Plattform als auf nem uC und teste den vorher so, dass er 
auf Anhieb läuft. Das klappt auch oft, jetzt aber nicht.

Ausserdem habt ich meist fette Echtzeit, da hab ich schlechte 
Erfahrungen gemacht wenn mir der Debugger da reinfummelt. Liegt aber 
wahrscheinlich wie oft an meiner Unkenntnis.

Danke
Cheers
Detlef

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Detlef _. schrieb:
> durch 8 teilbar, oder !?

Nein, 4. Das ist ein 32-Bit-Prozessor.

von W.S. (Gast)


Lesenswert?

Jim M. schrieb:
> Längerfristig will man sich aber einen Debugger zulegen. Die gibt es für
> ARM auch sehr preiswert.

Und? Was hat man davon?
Es glauben gar viele Leute, daß ein Debugger das Allheilmittel sei. Ist 
er nicht. Die Fehler, die man mit ihm finden kann, sind zu 99% eigene 
Doofheit oder Unachtsamkeit. Die eigentlichen Sauereien, die einem 
gelegentlich das Leben schwer machen, findet man damit nimmer. Versuche 
doch mal, nen USB-Handler per Debugger zu debuggen... nur so, als 
Beispiel.

W.S.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Ach ja, gewiss, gewiss. Wer einen Debugger verwendet, ist zu 99% 
unachtsam und doof. Natürlich. Was sonst.

Geht's noch?

von Detlef _. (detlef_a)


Lesenswert?

Ich nochma, TO.

Habe Stück für Stück die Benutzung der int64_t reingenommen. Geht auch 
alles gut, bis ich eine int64_t Variable mit einer float Variable 
vergleiche:

int64_t out;
float maxx;
if(out > maxx) maxx = (float)out;

Für das Ding linkt er 700Byte mehr ein und 'friert ein' bei der 
Ausführung. Eigentlich sollte ich jetzt dem Fehler auf den Grund gehen, 
aber Zeit und Lust fehlen. Rest geht erstma bei mir und gut, die Abfrage 
hab ich mit int32_t gelöst, an der Stelle passte das noch.

Die gewonnene Zeit nutze ich lieber, um meinen Olimex USB JTAG Adapter 
zum Fliegen zu bringen ;-/

Danke allen Beteiligten.

Cheers
Detlef

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> Versuche doch mal, nen USB-Handler per Debugger zu debuggen... nur so,
> als Beispiel.

Ich habe letzte Woche den USB Code von NXP für LPC debuggt und nur dank 
Debugger festgestellt dass an einer Stelle ein unaligned memory Zugriff 
war der den Cortex M0 abstürzen lässt. Ich bin gespannt wie man das in 
den Tausenden LoC ohne Debugger (schnell) hätte finden können.

von 53453453454353 (Gast)


Lesenswert?

dieses?

https://www.olimex.com/Products/ARM/ST/STM32-405STK/


besorg dir ein Nucleo board ...
der ST Link V2-1 da drauf kann alle ST flashen.
Ich breche die gern ab und verwende die weiter ^^

Aber dann kannst du zB mit OpenSTM IDE auch ganz fix debuggen und 
spielen.

von W.S. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Ach ja, gewiss, gewiss. Wer einen Debugger verwendet, ist zu 99%
> unachtsam und doof. Natürlich. Was sonst.
>
> Geht's noch?

Ich habe den Eindruck, daß du dich getroffen fühlst. OK, ist ne 
Bestätigung für mich.

Aber denk mal nach, wofür DU normalerweise einen Debugger auf nem 
Mikrocontroller verwendest. Zum Flashen? Oder wirklich zum Debuggen - 
und wenn, was hast du denn debuggt mit welchem Ergebnis?

Also komm mal runter von deiner Palme und bleibe vernünftig. Das, was 
man per Debugger herausbekommen kann, ist wirklich zu 99% nur 
Unachtsamkeiten und sich zu doof angestellt haben. Letzteres besteht 
regelmäßig darin, daß man haben will, was man meint und nicht, was der 
Compiler davon hält. Nettes Beispiel sind konstante arrays von 
konstanten Zeigern auf konstante arrays im Flash. Irgendwo ein const 
fehlplaziert oder vergessen und ätsch.

Aber warum der Systemtakt nicht so kommt, wie man es beim Aufsetzen der 
PLL sich gedacht hat oder warum anschließend die CPU sang- und klanglos 
verreckt ist (und auch kein Debugger-Frontend mehr läuft) oder warum man 
beim USB vom Host gnadenlos kaltgestellt wird, das findet man per 
Debugger eher NICHT. Ich bin nach wie vor davon überzeugt, daß der 
Debugger entweder nur zum Flaschen benutzt wird oder sein Nutzen 
deutlich überschätzt wird.

Und, sag mal wie du das nennen würdest, wenn jemand seinen Fehler, den 
er beim Schreiben seiner Quelle gemacht hat, nicht durch kritisches 
Draufgucken aud seine Quelle finden kann und stattdessen meint, daß der 
Debugger es an seiner Stelle schon finden wird.

Hier hat jemand geschrieben, "Ich habe letzte Woche den USB Code von NXP 
für LPC debuggt und nur dank Debugger festgestellt dass.." - ich glaube 
dem Jungen kein einziges Wort. Kein Einziges!

W.S.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

W.S. schrieb:
> Und, sag mal wie du das nennen würdest, wenn jemand seinen Fehler, den
> er beim Schreiben seiner Quelle gemacht hat, nicht durch kritisches
> Draufgucken aud seine Quelle finden kann und stattdessen meint, daß der
> Debugger es an seiner Stelle schon finden wird.

Das klingt ziemlich überheblich und vor allem ... erfahrungsarm.

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> Aber denk mal nach, wofür DU normalerweise einen Debugger auf nem
> Mikrocontroller verwendest.

Es gibt Leute, die schreiben komplexere Dinge als LED-Blinker. Dafür ist 
ein Debugger enorm hilfreich. Bei großen Projekten mit komplexen 
Programmstrukturen helfen Watchpoints und Step-by-Step eine Menge. Nur 
weil du damit nicht umgehen kannst heißt das nicht dass man das nicht 
braucht. Nicht umsonst sind Debugger seit Jahrzehnten(!) integraler 
Bestandteil aller Entwicklungs-Toolchains (außer Arduino)...

W.S. schrieb:
> Also komm mal runter von deiner Palme und bleibe vernünftig. Das, was
> man per Debugger herausbekommen kann, ist wirklich zu 99% nur
> Unachtsamkeiten und sich zu doof angestellt haben.
Selbst wenn es so wäre - ist doch gut, das damit schnell & einfach zu 
finden. Manche Leute wollen einfach ihre Arbeit machen anstelle sich 
durch Männlichkeit ( http://xkcd.com/378/ ) zu profilieren.

W.S. schrieb:
> Irgendwo ein const
> fehlplaziert oder vergessen und ätsch.
Das findet ja der Compiler, da sollte man sich mal die 
Compiler-Warnungen anschauen.

W.S. schrieb:
> das findet man per
> Debugger eher NICHT.
Debugger sind auch sehr hilfreich um Peripherie-Register anzuschauen und 
herauszufinden, warum die Peripherie nicht tut was man möchte. 
Dokumentationsfehler sind ja nun keine Seltenheit.

W.S. schrieb:
> Und, sag mal wie du das nennen würdest, wenn jemand seinen Fehler, den
> er beim Schreiben seiner Quelle gemacht hat, nicht durch kritisches
> Draufgucken aud seine Quelle finden kann
Es gibt so etwas das nennt sich "Betriebsblind". Bei Millionen Zeilen 
Code wird es irgendwann schwierig den Fehler durch Hinschauen zu finden, 
wenn das Problem durch komplizierte Wechselwirkung der einzelnen 
Komponenten zustande kommt.

W.S. schrieb:
> Hier hat jemand geschrieben, "Ich habe letzte Woche den USB Code von NXP
> für LPC debuggt und nur dank Debugger festgestellt dass.." - ich glaube
> dem Jungen kein einziges Wort. Kein Einziges!
Hahaha, du bist echt der Beste! Wenn dir was nicht passt steckst du den 
Kopf in den Sand? Aber bitte:
https://github.com/una1veritas/ARMWork/blob/master/LPCLibrary/LPC11Uxx_USBDriver/usbhw.c#L803 
Dies ist der Code von NXP. Die offizielle Quelle des Codes kannst du 
selber ausfindig machen, in diesem GitHub-Repo ist es am einfachsten 
öffentlich einsehbar.
Der Trick mit *((__packed uint32_t *)dataptr)  funktioniert vielleicht 
mit dem ARMCC, aber nicht mit dem GCC (der ignoriert das einfach). 
Sobald dataptr also unaligned ist gibt es beim Cortex-M0 einen Crash. 
Wenn du mir das nicht glaubst, probier's aus. Und dann bin ich gespannt, 
wie man einen solchen Crash ohne Debugger finden soll. Mit Debugger 
ging's recht schnell (Backtrace, Assemblercode, Register anschauen).

von Dr. Sommer (Gast)


Lesenswert?

Mir fällt gerade ein dass ich auch mal per Debugger einen Buffer 
Overflow in ST's USB Code gefunden habe. Ich hatte das Phänomen dass 
virtuelle Funktionsaufrufe plötzlich nicht mehr funktionierten. Da habe 
ich einen Watchpoint auf den vtable Pointer gesetzt und sofort die 
fragliche Stelle im ST Code gefunden. Das ist aber jetzt so lange her 
dass ich die genaue Stelle nicht mehr weiß (aber hier im Forum wird ja 
oft von den vielen Bugs im ST USB Code geredet). Wie man das in 
sinnvoller Zeit ohne Debugger finden soll wüsste ich jetzt auch nicht.

von Operator S. (smkr)


Lesenswert?

Rufus Τ. F. schrieb:
> vor allem ... erfahrungsarm.

Wer nur vom Tisch springt, findet einen Fallschirm unnütze Ballast.

von Nico W. (nico_w)


Lesenswert?

Ich habe vor einiger Zeit auch mal eine eigene Lib geschrieben um den 
ADC per DMA auszulesen. Ich habe ca. 4 Monate rumgetestet und es lief 
nicht.

Ich bin zwar noch Rookie, aber dann habe ich mich mit dem 
Hardwaredebugger eingelesen. 2 Tage gebraucht bis ich das alles 
verstanden hatte und der Debugger lief. 2 Stunden später lief der 
DMA-ADC ohne Probleme.

von Steffen R. (steffen_rose)


Lesenswert?

Dr. Sommer schrieb:
> Initialer Stack Pointer im Linker Script falsch. Der muss auf das erste
> Byte nach dem RAM zeigen, nicht das letzte Byte im RAM. Leider weiß
> ST nicht wie die eigenen Chips funktionieren und macht das in den
> Beispiel Skripten teilweise falsch.

Gilt das nur für den F4 oder die gesamte STM32 Familie?
Gilt dies generell für alle Cortex-M auch anderer Hersteller?

von Nop (Gast)


Lesenswert?

Steffen R. schrieb:
> Gilt das nur für den F4 oder die gesamte STM32 Familie?
> Gilt dies generell für alle Cortex-M auch anderer Hersteller?

Gilt für alle Cortex, weil das ein "fully descendent stack" ist. Der SP 
wird also VOR dem Push dekrementiert.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Der muss auf das erste Byte nach dem RAM zeigen, nicht das letzte Byte
> im RAM.

Das in Kombination mit

> Der SP wird also VOR dem Push dekrementiert.


bedeutet also nur, daß ein Byte (oder vermutlich 4 Byte, da der Stack 
sicherlich auch besser mit Alignment angesprochen wird) "vergeudet" 
wird, der effektive Stack also um dieses eine Element kleiner ist als 
vermutet.

Welche Programmfehler sollten dadurch entstehen? Ein Programmdesign, das 
den Stack bis aufs letzte Byte ausquetscht halte ich für eher 
fragwürdig.

von Dr. Sommer (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Welche Programmfehler sollten dadurch entstehen?
Auf ungerade Adressen kann man nur ineffizient zugreifen. Zudem 
scheitern Zugriffe mit Datentypen die größer als 4 Byte sind (double, 
(u)int64_t) bei solchen Adressen, da die ldrd/strd Instruktionen nur 
4-Byte-Aligned Adressen unterstützten.
Allerdings lese ich gerade dass der SP immer Zwangs-Aligned ist: 
Beitrag "Re: [ARM] Nützliches newlib-nano float printf" Daran liegt es also 
wohl doch nicht...

von Nop (Gast)


Lesenswert?

W.S. schrieb:
> wenn jemand seinen Fehler, den
> er beim Schreiben seiner Quelle gemacht hat, nicht durch kritisches
> Draufgucken aud seine Quelle finden kann

Das kann man grundsätzlich immer. Die Frage ist nur, wieviel Zeit das 
braucht. Denn man hätte es ja auch einfach gleich richtig schreiben 
können, so daß Debugging generell überflüssig ist. Theoretisch. 
Dummerweise wird man aber oftmals beim Drübergucken genau denselben 
Denkfehler machen wie auch schon beim Codieren.

Noch schöner wird es, wenn man anders als offensichtlich W.S. nicht den 
Luxus hat, stets nur from scratch selbstgeschriebene Programme vor sich 
zu haben, sondern man es mit zigtausend Zeilen fremden Codes zu tun hat 
und der ursprüngliche Programmierer nicht mehr erreichbar ist.

Das können dann durchaus auch unterhaltsame indirekte Fehler sein - etwa 
ein obendrein auch noch sehr seltener und schwer reproduzierbarer 
Absturz nicht an der Stelle, wo der Fehler liegt, sondern an völlig 
anderer Stelle, wo der ursächliche Fehler sich erst auswirkt. Sowas wie 
sehr seltenes, irrtümliches Überschreiben eines Pointers, der viel 
später und ganz woanders erst dereferenziert wird.

Klar kann man dann erstmal wochenlang nur Quelltext lesen und überlegen, 
ob in einer der hunderten Funktionen womöglich ein Fehler stecken 
könnte. Blöd nur, wenn ein Fehler schlichtweg da ist und man nicht 
wochenlang auf einen Fix warten kann.

Mitm Debugger habe ich in der genannten Lage von "da ist möglicherweise 
ein Problem" bis zu "Problem behoben" zwei Tage gebraucht. Ich will 
nicht wissen, wie lange ich ohne Debugger gebraucht hätte.

von Nop (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> bedeutet also nur, daß ein Byte (oder vermutlich 4 Byte, da der Stack
> sicherlich auch besser mit Alignment angesprochen wird)

Mit dem Auto-Alignment werden es 4 Bytes sein, die vergeudet werden. 
Schlimmer ist aber, daß er zu Beginn dann eher nicht mehr 8-Byte-aligned 
ist, was er für Datentypen wie double aber zu sein hat.

Es sei denn, man hat seinen Stack echt schräg dimensioniert, nämlich um 
genau diese 4 Bytes oberhalb des nächstniederen 8-alignments.

von W.S. (Gast)


Lesenswert?

Nop schrieb:
> Noch schöner wird es, wenn man anders als offensichtlich W.S. nicht den
> Luxus hat, stets nur from scratch selbstgeschriebene Programme vor sich
> zu haben, sondern man es mit zigtausend Zeilen fremden Codes zu tun hat
> und der ursprüngliche Programmierer nicht mehr erreichbar ist.

Eins rauf! Du bist in diesem Thread wohl der Einzige, der ein wirklich 
überzeugendes Argument gebracht hat.

Nicht mal Rufus hat es fertig gebracht, auf ne sachliche Frage eine 
sachliche Antwort zu geben.

W.S.

von W.S. (Gast)


Lesenswert?

Nochwas:

Nop schrieb:
> Das kann man grundsätzlich immer. Die Frage ist nur, wieviel Zeit das
> braucht. Denn man hätte es ja auch einfach gleich richtig schreiben
> können

Ja, eigentlich ein fettes JA... ABER: Die meisten C-Programmierer (auch 
hier in diesem Forum) haben eine unendliche Abscheu davor, einen 
biederen und in den Statements simpel gehaltenen Code zu schreiben. Das 
ist ihnen zu poplig und so werden oft genug Formulierungen geschrieben 
(einschließlich unangenehm vieler Casts), die fehlerträchtig sind und 
eben beim Durchgehen der Quellen einem partout nicht auffallen.

Eben genau deshalb predige ich hier, daß man lieber die Dinge simpel 
schreiben soll und das Optimieren dem Compiler überlassen soll. Ist aber 
in den Wind gesprochen, und so wachsen die Leute immer wieder nach, die 
sich selbst ein Bein stellen. Die brauchen den Debugger dann dafür, 
herauszukriegen, was ihre Formulierung in der Quelle tatsächlich 
bewirkt.

Kleines Beispiel am Rande: Ich hatte neulich in einer Quelle von der 
"blackmagic"-Jtag/Swd-Probe eine void function gefunden, die einen Wert 
zurückliefert. Was mich dabei gewundert hat war, daß der Gcc offenbar 
sowas hat durchgehen lassen. Bei meinem Versuch, den Kram per Keil zu 
übersetzen, hab ich natürlich ne fette Ohrfeige vom Compiler abgekriegt 
- welch Wunder..

W.S.

von m.n. (Gast)


Lesenswert?

W.S. schrieb:
> Was mich dabei gewundert hat war, daß der Gcc offenbar
> sowas hat durchgehen lassen. Bei meinem Versuch, den Kram per Keil zu
> übersetzen, hab ich natürlich ne fette Ohrfeige vom Compiler abgekriegt
> - welch Wunder..

Wie, Du benutzt einen Compiler? Das hätte ich jetzt nicht gedacht!

von Nop (Gast)


Lesenswert?

W.S. schrieb:

> Eins rauf! Du bist in diesem Thread wohl der Einzige, der ein wirklich
> überzeugendes Argument gebracht hat.

thx ;-)

Wobei ich Debugger aber auch nur in solchen Extremfällen brauche. Im 
Normalfall habe ich ja ohnehin einen vernünftigen Hardfault-Handler, der 
nach Art eines Bluescreens die abstürzende Programm-Adresse aus dem 
Exception-Stack fummelt und loggt, und da sehe ich dann über das Mapfile 
schnell, in welcher Funktion das Problem liegt (weswegen ich für die 
Testbuilds inlining deaktiviere). Ging nur nicht im genannten Beispiel.

> Ja, eigentlich ein fettes JA... ABER: Die meisten C-Programmierer (auch
> hier in diesem Forum) haben eine unendliche Abscheu davor, einen
> biederen und in den Statements simpel gehaltenen Code zu schreiben.

Ich mach's da eher umgedreht - erstmal KISS und gucken, daß es überhaupt 
wie gewollt läuft. Dann schauen, ob weitere Optimierung sinnvoll ist. 
Wenn ja, dann erstmal auf algorithmischer Ebene verbessern anstatt mit 
Programmiertricks. Bevor ich einen Bubblesort optimier-verpfriemele, 
nehme ich gleich einen Shellsort.

Was dann noch übrig bleibt, das kann dann schon tricky werden. Mit 
Pointergecaste, ggf. manuellen alignment-checks und mehrfachem 
Loop-Unrolling, was der Compiler so schlichtweg nicht kann. Ich hab mit 
solchen Tricks mal bei einem embedded Ethernettreiber den Durchsatz um 
den Faktor 3 erhöhen können, das war ordentlich.

Die einzelnen Statements halte ich dabei aber auch simpel, statt mit 
kryptischer C-Syntax möglichst viel in eine Zeile zu klatschen. 
Fragezeichenoperator mit gleichzeitigen Seiteneffekten in einer 
Indexierung kann ich, mache ich aber nicht. Der Compiler optimiert 
beides ohnehin gleichermaßen gut.

Da ich meinen Quelltext viel häufiger lese als schreibe, würde ich mir 
ja mit sowas nur selbst ein Bein stellen. Meine Fehler finde ich 
normalerweise nicht erst beim Testen, sondern schon vorher beim Review.

Meiner Meinung nach zeichnet sich ein Profi nicht dadurch aus, daß er 
kryptischen Code schreiben kann, sondern daß er komplizierte Sachen mit 
übersichtlichem Code ausdrücken kann. Überhaupt, an jeder Stelle, wo ich 
beim Codieren nachdenken mußte, schreibe ich auch einen Kommentar, WAS 
ich mir gedacht habe - denn offensichtlich war das ja nicht 
offensichtlich.

> (einschließlich unangenehm vieler Casts)

Und dann auch noch oftmals verkehrte Casts. Da wird dann zum 
Alignment-Check wahlweise ganz ohne Cast direkt auf Pointern mit 
Bitmasken rumgemacht (unzulässig), oder wenn gecastet wird, dann nach 
irgendeinem unsigned int (oder noch schlimmer, nur int) anstatt nach 
uintptr_t.

> Eben genau deshalb predige ich hier, daß man lieber die Dinge simpel
> schreiben soll und das Optimieren dem Compiler überlassen soll.

Auf dem Level, wo er das kann ja. Geht aber nicht immer. Das o.g. 
Beispiel des Ethernettreibers hat der Compiler nicht so optimieren 
können.

> Kleines Beispiel am Rande: Ich hatte neulich in einer Quelle von der
> "blackmagic"-Jtag/Swd-Probe eine void function gefunden, die einen Wert
> zurückliefert. Was mich dabei gewundert hat war, daß der Gcc offenbar
> sowas hat durchgehen lassen.

Vermutlich ohne -Wall compiliert. Mit -Wall gibt das eine Warnung auch 
bei GCC; hab's gerade getestet. Allerdings gibt's ja auch Spezis, deren 
Code so schlecht ist, daß sie die Warnungen abschalten, um "Ruhe" zu 
haben. Bei mir ist Grundforderung, daß der Code mit -Wall ohne Warnungen 
compilieren muß - denn meistens verbirgt sich dahinter irgendwas 
Unerwünschtes.

Zusätzlich lasse ich dann auch noch CppCheck auf meinen Code los. Die 
eine oder andere Warnung bleibt, das ist aber dann im Einzelfall 
technisch notwendig und gehört auch in die Projekt-Dokumentation.

von Nop (Gast)


Lesenswert?

Ach ja, und sogar ich habe an C Sachen zu meckern:

- Das keyword "inline" ist Schrott. Es ist nur ein Vorschlag an den 
Compiler, mehr nicht. Bin ich auf dem Basar oder wie, daß ich mit meinem 
Compiler verhandele?!

- Will ich ernsthaft "inline", dann geht das über Funktionsattribute, 
die aber compiler-spezifische Erweiterungen sind. Muß man sich also 
einmal irgendwo als Makro definieren, damit man Portabilität wahrt.

- Manchmal will ich dem Compiler strikt verbieten, trotz allgemein 
erlaubtem Inlining eine bestimmte Funktion zu inlinen. Beispielsweise, 
wenn sie einen hohen Stackverbrauch hat. Die Inline-Logik jedenfalls 
beim GCC ist da ziemlich kaputt, weswegen ich ihm das explizit verbieten 
muß. Dafür gibt es nichtmal ein Surrogat eines keyword, aber immerhin 
Attribute - compilerspezifisch.

- Es gibt zwar goto, und es gibt Pointer-Arithmetik, aber beides 
zusammen gibt's nur als compilerspezifische Erweiterung, nämlich das 
computed goto. Das hätte man auch in den Sprachstandard aufnehmen 
können. Kann durchaus nützlich sein.

von Bernd K. (prof7bit)


Lesenswert?

W.S. schrieb:
> Jim M. schrieb:
>> Längerfristig will man sich aber einen Debugger zulegen. Die gibt es für
>> ARM auch sehr preiswert.
>
> Und? Was hat man davon?
> Es glauben gar viele Leute, daß ein Debugger das Allheilmittel sei. Ist
> er nicht. Die Fehler, die man mit ihm finden kann, sind zu 99% eigene
> Doofheit oder Unachtsamkeit.

Alter Schwede, der W.S. ist heute wieder mal voll in seinem Element

> Die eigentlichen Sauereien, die einem
> gelegentlich das Leben schwer machen, findet man damit nimmer. Versuche
> doch mal, nen USB-Handler per Debugger zu debuggen... nur so, als
> Beispiel.

Hab schon lang nicht mehr so einen Nonsens der mit so einer Vehemenz 
vorgetragen wurde gelesen. Das bringen in dieser ausgeprägten Form nur 
wenige in diesem Forum zustande.

von Detlef _. (detlef_a)


Lesenswert?

Hallo,

ich bins nochmal, der TO.
Ich hab noch ne Frage zu 64Bit und STM32.

Plus und mal mit 64Bit geht wunderbar, jetzt möchte ich zwei int64_t 
dividieren, dann kommen vom Linker Beschwerden:

"main.out uses VFP register arguments, libgcc.a(bpabi.o) does not"
"failed to merge target specific data of file libgcc.a(bpabi.o)"

Das ganze für eine Anzahl .o Files, unter anderem _divdi3.o und 
_udivdi3.o

Dann noch hinten was:

"DISCARD has both ordered ['.ARM.exidx' in libgcc.a(_divdi3.o)] and 
unordered ........"

Ich nehme an, dass ich die nativen 64Bit Operationen Plus und Mal nehmen 
kann, dass der linker aber für emulierte Operationen wie dividieren die 
falsche lib vorgesetzt kriegt. (Das würde wahrscheinlich auch das 
Problem lösen, weswegen ich diesen thread geöffnet habe und das ich nur 
umschifft aber nicht gelöst habe)

Wie bringe ich dem linker denn die richtige lib nahe?

THX
Cheers
Detlef

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Deine FPU Optionen in der Nutzerfiles sind unterschiedlich von den 
Optionen in den Bibliotheken. Uebersetzte die Nutzfile mit den FPU 
Optionen der Bibliothek!

von Detlef _A (Gast)


Lesenswert?

So sehen die Compile- und Linkflags aus:

# Flags
CFLAGS = -Wall -fno-common -c -g -mcpu=cortex-m4 -mthumb
CFLAGS += -mfloat-abi=hard
CFLAGS += -mfpu=fpv4-sp-d16
CFLAGS += -fno-math-errno
CFLAGS += -ffast-math
CFLAGS += -g $(OPTIMIZATION) $(INCLUDES) -DTRACE_LEVEL=$(TRACE_LEVEL)
ASFLAGS = -g -mapcs-32
LDFLAGS = -g -v -nostartfiles -mfloat-abi=hard -mfpu=fpv4-sp-d16
LDFLAGS+= -mcpu=cortex-m4 -mthumb
LDFLAGS+= -fno-math-errno
LDFLAGS+= -ffast-math -specs=nosys.specs

Wie findet der gcc denn dann die Bibliothken oder was muss ich hier 
ändern damit das zu den Bibliotheken passt?

THX
Cheers
Detlef

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Hoppla, was hat float und int64_t miteinander zu tun?
Brauchst Du an anderer Stelle die Floating point unit? Wenn nicht, 
verwende
CFLAGS += -mfloat-abi=soft. Anderenfalls brauchst Du ein libgcc was mit 
mfloat-abi=hard kompiliert ist.

von Felix F. (wiesel8)


Lesenswert?

Wie Uwe schon geschrieben hat, mischt du hard-float und soft-float. Das 
geht nicht! Entweder nur hard oder nur soft!
1
-mfloat-abi=soft
2
-mfloat-abi=hard

mfg

von Bernd K. (prof7bit)


Lesenswert?

Also bei mir erzeugt mein Makefile (ebenfalls handgeklöppelt) folgende 
Compiler- und Linkeraufrufe und hard-float funktioniert:

Vielleicht kannst Du Dir da die passenden Flags und Optionen 
rausklauben. Auch die Reihenfolge der Optionen und Argumente ist 
stellenweise relevant.

[CC] src/main.c:
arm-none-eabi-gcc -MMD -c -o build/src/main.o -Isrc/STM32F401XE 
-ffunction-sections -mlittle-endian -mthumb -mcpu=cortex-m4 
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu11 -ggdb -Os -flto -Wall 
-Wextra -Wstrict-prototypes -Werror -Wno-error=unused-function 
-Wno-error=unused-variable -Wfatal-errors -Warray-bounds 
-Wno-unused-parameter src/main.c

[LD] build/hello_world.elf:
arm-none-eabi-gcc -o build/hello_world.elf 
build/src/STM32F401XE/gcc_startup_system.o build/src/main.o 
-ffunction-sections -mlittle-endian -mthumb -mcpu=cortex-m4 
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu11 -ggdb -Os -flto 
--specs=nano.specs  --specs=nosys.specs  -nostartfiles -Wl,--gc-sections 
-Tsrc/STM32F401XE/gcc_linker.ld -lm -Wl,-Map=build/hello_world.map


Ich verwende den offiziellen gcc von Arm auf Launchpad.

von Detlef _. (detlef_a)


Lesenswert?

Hallo,

habs gefunden.

>>>>
Brauchst Du an anderer Stelle die Floating point unit?

Ja, brauche ich und da hatte ich vor einiger Zeit mit dieser -lm Option 
rumgebastelt, die muss nämlich komischerweise ganz hinten stehen beim 
Linkerkommando.

Das sah dann bei mir so aus:
$(LD) $(LDFLAGS) -T$(LINKER_SCRIPT) -o $(OUTPUT).out $(C_OBJECTS) 
$(ASM_OBJECTS) libgcc.a -lm

Er linkte mir dann eine lokale Version von libgcc mit ein, die die 
Probleme machte.

So gehts':
$(LD) $(LDFLAGS) -T$(LINKER_SCRIPT) -o $(OUTPUT).out $(C_OBJECTS) 
$(ASM_OBJECTS) -lm

Der es wissen will, ein sehr interessanter Hintergrund:

Ich möchte die Abweichung d zweier Zähler (int32_t)a und b in ppb 'parts 
per billion' berechnen d=1e9*(a-b)/a. a und b werden sehr gross, 1e8 
Grössenordnung. Für diese Rechnung reicht die Stellenanzahl von 32 Bit 
floats (ca. 6 Stellen) nicht mehr aus. Wenn a und b langsam in gleichem 
Abstand hochlaufen sollte sich das Ergebnis langsam und stetig ändern. 
Bei float32-Rechnung springt es hin und her, bei 64 Bit Rechnung ist 
alles gut.

Danke für die Hilfe.
Cheers
Detlef

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.