Hallo,
manchmal erwischt man ihn ja und kann ihn einkreisen, so auch hier.
Bloss wieso ... ewig Theater mit den Optimierungstsufen des GCC. Aber
die schaffen locker mal 20% weniger Code.
Wieso zur Hölle crashed dieser Code, wenn ich die Optimierung, die auf
-OS steht zulasse? Ich traue mich bald keine Vars mehr ohne volatile zu
definieren. Vorher war da eine Laufvariable i, die nur als volatile
akzeptiert wurde. Ohne das auch im Handler drin.
1
/* Sendet einen Datensatz über das Schieberegister */
Christian J. schrieb:> manchmal erwischt man ihn ja und kann ihn einkreisen, so auch hier.> Bloss wieso ... ewig Theater mit den Optimierungstsufen des GCC. Aber> die schaffen locker mal 20% weniger Code.
Ist schon komisch, dass hier so mancher immer zuerst seine Fehler beim
gcc sucht. Wenn es mit -Os abschmiert liegt es zu 99,99% nicht am gcc,
sondern am Verfasser des Codes. Ob du zum Rest gehörst kann man dir so
nicht sagen, da wir den Rest des Programms und wie das aufgerufen wird
nicht kennen. Schon mal drüber nachgedacht was passiert wenn deine
tls_74HCT595_SendData mit nrBytes = 0 aufgerufen wird?
Christian J. schrieb:> Wieso zur Hölle crashed dieser Code, wenn ich die Optimierung, die auf> -OS steht zulasse?
Welchen Wert hat "data" und "nrBytes"? Passt "nrBytes" zu "data"?
Bist du sicher dass du tls_Set74HCT595(*(data++)) und nicht
tls_Set74HCT595(*data++) meinst? Im ersten Fall wird data erst
inkrementiert und dann dereferenziert, d.h. du überspringst immer das
erste Byte, und hast evtl. einen Überlauf am Ende der Schleife.
Wer bei heuten Speicherpreisen und großen Monitoren noch eine Grütze
wie:
> tls_Set74HCT595(*(data++));
schreibt, hats nicht besser verdient.
Schreibt eure Anweisungslisten ordentlich aus, dann merkt ihr auch was
fehlt.
In den STM32 "Debug" Registern steht nach eine Fault doch auch recht
genau drin, was ihn ausgelöst hat. Du must nur einen vernünftigen
Fault-Handler haben, der dir diese Register ausliest und dumped.
Wieso nutzen so wenige diese super Diagnose -Möglichkeit? In den meisten
Fällen hilft das.
Roland E. schrieb:> Wer bei heuten Speicherpreisen und großen Monitoren noch eine Grütze> wie:>>> tls_Set74HCT595(*(data++));>> schreibt, hats nicht besser verdient.
Sonst tickt es aber noch richtig bei dir, oder? Das was Du schreibst
finde ich ziemlichen Müll. sorry, wenn ich mich nur mal deinem Ton
anpasse. Meine Monitorgröße hat wohl kaum was mit dem Code zu tun.
Korrektur: Opt. steht auf -O1, nicht auf Os. mit -Os läuft es.
a) NrBytes kann niemals 0 sein, daher muss ich auch nicht drauf achten,
dass es 0xff wird. Dennoch NrBytes-- ist besser.
b) Debuggen mit eingeschalteter Optimierung ist nicht/kaum möglich.
Hier läuft es beim Debug mit eingeschalteter Optimierung durch, beim
Release aber kommt der Fehler. Das ist häufig so, auch das Timing ist
anders im Debug Lauf.
c) "Im ersten Fall wird data erst inkrementiert und dann dereferenziert"
Stimmt nicht! Inkrement erst nachdem der Ausdruck verlassen wurde. Keine
Ahnung von C aber Ratschläge geben?
Ich habe es durch probieren heraus gefunden wo die Ursache liegt. Sie
liegt im Aufrufer
tls_74HCT595_SendData((uint8_t*)&Work, sizeof(Work));
Tauscht man das gegen
tls_74HCT595_SendData((uint8_t*)&Time, sizeof(Time));
aus, läuft sie einwandfrei durch, auch auf dem Logic Analyzer.
Der Unterschied zwischen Work und Time liegt nur darin, dass Work im
sog. Backup RAM liegt und Time im CCRAM.
Die Ursache für den Fehler kann ich vorerst nicht bestimmen. Daher
schalte ich die Optimierung für dieses Modul aus.
PS: In den Code Richtlinien meiner Firma für Massenprodukte (bis SIL 3!)
ist Optimierung grundsätzlich auszuschalten, auch beim Keil der
verwendet wird. Das wird seinen Grund haben.
Christian J. schrieb:> dass Work im sog. Backup RAM liegt und Time im CCRAM
Dann schau doch mal, ob das Backup RAM Interface korrekt eingeschaltet
ist und der Zugriff somit überhaupt möglich ist.
Im Release Modus mit Optimierungen kannst du immer noch den Assembler
Code Schritt für Schritt debuggen und somit die fehlerhafte Anweisung
finden. Die ist dann vermutlich eine load oder store Anweisung mit einer
ungültigen Adresse. Auch hilfreich sind die Daten, die der Core beim
Absturz auf den Stack schiebt (siehe ARMv7M Architecture Reference
Manual), da kann man genau schauen bei welcher Anweisung es abgestürzt
ist und warum.
Dr. Sommer schrieb:> Dann schau doch mal, ob das Backup RAM Interface korrekt eingeschaltet> ist und der Zugriff somit überhaupt möglich ist.
:-)
Wollte ich grad schreiben. Ja, ist es. Im Dump Fenster einwandfrei zu
sehen. Auch die Variablen lassen sich dort auslesen. Schaltet man es ab,
liest er übrigens nur Müll, springt aber nicht in den Handler.
1
/BackupRamaktivieren
2
voidInit_BackupRam()
3
{
4
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);// Power für RTC/Backup RAM
5
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM,ENABLE);// Backup RAM mit Clock versorgen
Christian J. schrieb:> Das wird seinen Grund haben.
Ja, vermutlich dass die Leute ungültigen C Code schreiben, der bei
Verwendung von Compiler Optimierungen kaputt geht, was dann natürlich
immer auf den Compiler geschoben wird. Ich bin schon auf diverse Fehler
im GCC gestoßen, aber noch auf keinen einzigen, wo der Optimizer
falschen Assembler Code aus korrektem(!) C/C++ Code erzeugt hätte. Wenn
man die Compiler Optimierungen nicht verwenden darf und man somit von
Hand optimieren muss wird der Code na super unlesbar und so macht man
erst recht Fehler...
Dr. Sommer schrieb:> Ja, vermutlich dass die Leute ungültigen C Code schreiben, der bei> Verwendung von Compiler Optimierungen kaputt geht, was dann natürlich> immer auf den Compiler geschoben wird.
Ich wäre vorsichtig mit solchen Behauptungen. Ich arbeite nicht in einer
Klitsche sondern einem deutschen Weltkonzern mit einem "B" vorne und mit
hohen Qualitätsstandards. Und im Gespräch mit jemandem aus der Firmware
Ecke wurde mir das gesagt. MISRA + Optimierung alle aus und noch vieles
mehr.
Dr. Sommer schrieb:> Sicher, dass es der Backup RAM und nicht die Backup Register sind? Auf> die kann man nämlich nur 32Bit- Word - weise zugreifen.
Ähm... also das ist mir jetzt neu. Ich habe jede Menge Vars da drin in
allen Größen. Nicht in den RTC Registern, glaube das sind 20 oder so. Im
4K RAM Und die Linker Anweisung sieht so aus:
/* Backup RAM section */
/* _sibkram = LOADADDR(.bkram); */
.bkram (NOLOAD):
{
. = ALIGN(4);
*(.bkram)
*(.bkram*)
. = ALIGN(4);
} >BKRAM
Christian J. schrieb:> Der Unterschied zwischen Work und Time liegt nur darin, dass Work im> sog. Backup RAM liegt und Time im CCRAM.
Da kann es Probleme geben wenn der Code zu schnell wird da das Backup
Ram Pheripherie ist und entsprechend langsamer getaktet wird.
Christian J. schrieb:> Stimmt nicht! Inkrement erst nachdem der Ausdruck verlassen wurde. Keine> Ahnung von C aber Ratschläge geben?
Ah, hast dich also tatsächlich an Rolands Ton angepasst. Schade drum,
schönen Tag noch. Scheinst ja selber gut mit allem klar zu kommen.
Sicher, dass der Fehler überhaupt in tls_74HCT595_SendData ist und nicht
in tls_Set74HCT595 oder der aufrufenden Funktion ? Der Compiler könnte
diese zusammen optimiert haben sodass der Debugger die falsche Source
Code Zeile anzeigt.
Außerdem schließe ich mich meinen Vorrednern an, der Code ist schwer
lesbar. Was ist aus dem klassischen
1
for(size_ti=0;i<nrBytes;++i){
2
tls_Set74HCT595(data[i]);
3
}
geworden? Bei einer einfachen Struktur erkennt man sofort ob sie korrekt
ist, und der Compiler kennt solche 0815 Konstrukte und kann sie
optimieren.
Dieter Graef schrieb:> Da kann es Probleme geben wenn der Code zu schnell wird da das Backup> Ram Pheripherie ist und entsprechend langsamer getaktet wird.
Das ist mal ne Ansage !!!!
Kann man da Waitstates einfügen oder sowas? Genau den Effekt kenne ich
vom Debuggen ja, wo alles läuft und beim Release nicht mehr.
Irgendjemand in einem Forum erwähnte das auch mal aber wo weiss ich
nicht mehr. Das ist bei Geschichten mit dem SRAM auch so, daher wird
dringend abgeraten in einer AppNote von ST aus dem ext. SRAM Code
auszuführen.
Christian J. schrieb:> Ich wäre vorsichtig mit solchen Behauptungen.
Sie treffen aber fast immer zu.
Selbstverständlich ist auch ein Compiler nicht frei von Fehlern, gar
keine Frage. Aber auch ich kann bestätigen, dass ich in praktisch
allen Fällen, wo ich wieder so einen "nicht nachvollziehbaren" Fehler
suchen durfte, nachher wieder beim Programmierer gelandet bin und der
Compiler in Ordnung war.
Und leider Gottes in sehr vielen Fällen tatsächlich ein Problem mit dem
Optimierer auftauchte, weil sich der Programmierer auf etwas verlassen
hat, was ihm garnicht garantiert wurde. Und sei es ein blödes volatile
oder ein Füllbyte in einer Struktur.
> Ich arbeite nicht in einer> Klitsche sondern einem deutschen Weltkonzern mit einem "B" vorne und mit> hohen Qualitätsstandards.
Jaja.
Roland E. schrieb:> Wer bei heuten Speicherpreisen und großen Monitoren noch eine Grütze> wie:>>> tls_Set74HCT595(*(data++));>> schreibt, hats nicht besser verdient.>> Schreibt eure Anweisungslisten ordentlich aus, dann merkt ihr auch was> fehlt.
Wir schreiben keine Anweisungslisten, das tun die Stümper bei Step7 und
Siemens.
Aber klär uns doch auf: Was fehlt denn? Die Zeile da ist ein simples und
gängiges Idiom. Ich würde sogar noch auf die inneren Klammern
verzichten.
Off by one? schrieb:> Bist du sicher dass du tls_Set74HCT595(*(data++)) und nicht> tls_Set74HCT595(*data++) meinst?
Beide Varianten sind gleichwertig. Die Klammerung erzeugt keinen
Sequenzpunkt und hat damit keinen Einfluss darauf, wann inkrementiert
wird. Außerdem bindet das Postinkrement stärker, d.h. die innere Klammer
kann entfallen.
Dr. Sommer schrieb:> Was ist aus dem klassischenfor (size_t i = 0; i < nrBytes; ++i) {> tls_Set74HCT595 (data [i]);> }geworden? Bei einer einfachen Struktur erkennt man sofort ob sie> korrekt> ist, und der Compiler kennt solche 0815 Konstrukte und kann sie> optimieren.
Und warum benutzt du dann Prä-Inkrement und nicht "i++"?
Jaja :-)
Dr. Sommer schrieb:> Sicher, dass der Fehler überhaupt in tls_74HCT595_SendData ist und nicht> in tls_Set74HCT595 oder der aufrufenden Funktion ?
Das weiss ich nicht und ohne Debugger ist es auch schwer zu finden. Ich
habe einige Stunden aufgewandt um alle Möglichkeiten abzudecken, die mir
einfielen. Mit foo und bar und den Ausdruck aufgeweitet. Die gleiche
Chose habe ich bei einer I2C Routine nahe an der Hardware gehabt, wo
letzlich auch nur half, die von der Opt auszunehmen.
Diese Sxhreibweise ist aus einem Optimierungsfimmelt entstanden. So kuzr
wie möglich, nimm die Parameter als Variablen, zaehle Schleifen von oben
nach 0 runter, weil auf 0 prüfen kürzer ist usw.
Ich werde dein Konstrukt mal eben testen.
Nase schrieb:> Außerdem bindet das Postinkrement stärker, d.h. die innere Klammer> kann entfallen.
Ja ... aber sicher ist sicher :-) Auch immer brav Klammern um alle
Define Ausdrücke, man weiss ja nie....
Christian J. schrieb:> Das ist mal ne Ansage !!!!
Aber leider falsch. Zugriff auf den Backup RAM geht bei vollem Takt.
>> Kann man da Waitstates einfügen oder sowas?
Nein.
Nase schrieb:> Und warum benutzt du dann Prä-Inkrement und nicht "i++"?
Weil ++i eine einfachere Anweisung als i++ ist (letztere erzeugt eine
temporäre Kopie zum Zurückgeben), und es sinnvoll ist standardmäßig
immer das einfachere zu verwenden. Bei simplen Integern ist es natürlich
völlig egal, aber wenn man dann doch mal mit Iteratoren o.ä. hantiert
ist es praktisch wenn man sich das gleich richtig angewöhnt hat. Okay,
das ist nur bei C++ relevant.
Mache mal ein noinline Attribut an tls_74HCT595_SendData und an
tls_Set74HCT595. Hoffentlich stürzt es dann immer noch ab und du kannst
besser sehen wo der Fehler lag.
Aber wie gesagt: Die am meisten erfolgversprechende Vorgehensweise ist
es, den Assembler-Code Schritt für Schritt durchzusteppen. So findet man
früher oder später die exakte Stelle des Absturzes.
Dr. Sommer schrieb:> lesbar. Was ist aus dem klassischenfor (size_t i = 0; i < nrBytes; ++i)> {> tls_Set74HCT595 (data [i]);> }
Läuft! Warum weiss ich nicht. data[i] ist doch richtig? data[0] = data?
Ich verwende sowas nie, nur Zeiger.
Dr. Sommer schrieb:> Aber wie gesagt: Die am meisten erfolgversprechende Vorgehensweise ist> es, den Assembler-Code Schritt für Schritt durchzusteppen. So findet man> früher oder später die exakte Stelle des Absturzes.
Das habe ich schon :-) Im Debug Fenster für Asm Code, mixed Code. Da
sieht man nüscht.... läuft... step by step.....
Christian J. schrieb:> // do> // tls_Set74HCT595(*(data++));> // while (nrBytes-- > 0);
Na so ist das doch auf jeden Fall falsch oder? Wenn nrBytes = 1 ist, ist
der Rückgabewert von nrBytes-- auch 1, und somit wird der
Schleifenkörper zweimal durchlaufen. Das hast du nun von deinem
verdrehten Code :P
Christian J. schrieb:> Ich verwende sowas nie, nur Zeiger.
Um es besonders kompliziert zu machen? Array-Zugriffe sind doch
einfacher...
Christian J. schrieb:> for (uint16_t i = 0;i < nrBytes; i++)> tls_Set74HCT595(data[i]);
Warum uint16_t ?? Für nur halb genutzte 32bit-Prozessor-Register gibts
kein Geld zurück. Es wird aber ggf. langsamer mit uint16_t, weil der
Compiler den 16bit-Überlauf auf dem 32bit-Prozessor "emulieren" muss.
Nimm size_t, dann ists auch portabel...
Dr. Sommer schrieb:> Na so ist das doch auf jeden Fall falsch oder? Wenn nrBytes = 1 ist, ist> der Rückgabewert von nrBytes-- auch 1, und somit wird der> Schleifenkörper zweimal durchlaufen. Das hast du nun von deinem> verdrehten Code :P
Jo, --NrBytes war richtiger :-) Aber nach der Aussage oben eben doch
falscher, weil 0 nicht abgedeckt wird.
Deine Kiste sieht in Asm so aus, sie läuft ja ....
Weshalb schaust du nicht in die Diagnoseregister im Hard Fault Handler
anstatt "blind" rumzustochern? Das kannst du immer noch machen, falls
diese Register nichts hergeben.
Ahhhhh......ohhhhh..... jaaaaaa :-)
/* Sendet einen Datensatz über das Schieberegister */
void tls_74HCT595_SendData(const uint8_t *data,size_t nrBytes)
{
for (size_t i = 0;i < nrBytes; i++)
tls_Set74HCT595(data[i]);
}
Das Problem beschränkt sich also auf die Adressierung von Data.
900ss D. schrieb:> Weshalb schaust du nicht in die Diagnoseregister im Hard Fault Handler> anstatt "blind" rumzustochern?
Bin zu blöd dafür. Ich weiss nicht wie ich die Auslese.....
Christian J. schrieb:> Bin zu blöd dafür.
Glaub ich nicht, du nimmst dir nicht die Zeit. Die ist aber sinnvoller
investiert. Das kannst du dann immer wieder benutzen.
Ich bin mir ziemlich sicher, dass du einen Seiteneffekt hast, den du
durch Codeumschreiben kaschiert.
Christian J. schrieb:> Da> sieht man nüscht.... läuft... step by step.....
Das ldrb ... ,#1 ist doch schon höchst verdächtig. Da wird niemals
data[0] ausgelesen. Der Rest vom Code ist auch irgendwie komisch, steige
gerade nicht 100% dahinter warum das keine Endlosschleife ist.
Christian J. schrieb:> for (size_t i = 0;i < nrBytes; i++)> tls_Set74HCT595(*data++);
Meine Augen. Wer würde so etwas verbrechen :'( * und ++ haben ja die
gleiche Priorität... Was ist mit *(data++) ? Aber data[i] ist natürlich
am Einfachsten und Besten (und funktioniert...).
Christian J. schrieb:> Bin zu blöd dafür. Ich weiss nicht wie ich die Auslese.....
Lies im ARMv7M Architecture Reference Manual wie die heißen, wie ihre
Adressen sind, und gibt die Adressen im Memory Fenster der IDE ein.
900ss D. schrieb:> Glaub ich nicht, du nimmst dir nicht die Zeit. Die ist aber sinnvoller> investiert. Das kannst du dann immer wieder benutzen.>> Ich bin mir ziemlich sicher, dass du einen Seiteneffekt hast, den du> durch Codeumschreiben kaschiert.
Dazu muss man wohl asm in C einbinden denke ich und das sieht furchtbar
kryptisch aus .... zudem ich nicht weiss, wie man lokale Variablen mit
Registerinhalten füttert, da Locals ja auf dem Stack liegen und deren
Adresse mir nicht bekannt ist.
Christian J. schrieb:> Deine Kiste sieht in Asm so aus, sie läuft ja ....
Deine do..while Konstrukte sind ohne Optimizer naturgemäss effizienter
als ein äquivalentes for(;;). Compiler sind nicht dafür eingerichtet,
ohne Optimizer viel zu optimieren. ;-)
Dr. Sommer schrieb:> Lies im ARMv7M Architecture Reference Manual wie die heißen, wie ihre> Adressen sind, und gibt die Adressen im Memory Fenster der IDE ein.
Beim Debuggen läuft es .... und im Release habe ich kein Memory Fenster
:-(
Und das *data++ wurde grad oben als gleichwertig bezeichnet was ich auch
bezweifle, *(data++) muss das heissen. Sonst würde ich ja seit 10 Jahren
etwas falsch machen.
Christian J. schrieb:> Dazu muss man wohl asm in C einbinden denke ich
Nein. Du musst nur im Debugger die Adresse auslesen, wie z.B. 0xE000ED28
für das CFSR.
> zudem ich nicht weiss, wie man lokale Variablen mit> Registerinhalten füttert, da Locals ja auf dem Stack liegen und deren> Adresse mir nicht bekannt ist.
Nein, locals liegen meistens eben nicht auf dem Stack, sondern in
Registern.
Christian J. schrieb:> Beim Debuggen läuft es .... und im Release habe ich kein Memory Fenster> :-(
Dann verwende eine vernünftige IDE, bei der man das Memory Fenster auch
im Release Modus einblenden kann, wie z.B. eclipse. Oder einfach nur gdb
auf der Konsole benutzen. Wenn es schon daran scheitert, oh man.
> Und das *data++ wurde grad oben als gleichwertig bezeichnet was ich auch> bezweifle, *(data++) muss das heissen.
Laut http://en.cppreference.com/w/cpp/language/operator_precedence haben
* und ++ die gleiche Priorität, somit müsste *data++ undefiniert sein.
> Sonst würde ich ja seit 10 Jahren etwas falsch machen.
Nicht ausgeschlossen, schließlich verwendest du ja scheinbar seit 10
Jahren keine Arrays und nur eklige Pointer-Arithmetik...
A. K. schrieb:> Deine do..while Konstrukte sind ohne Optimizer naturgemäss effizienter> als ein äquivalentes for(;;). Compiler sind nicht dafür eingerichtet,> ohne Optimizer viel zu optimieren. ;-)
Ohne siehts so aus, wie aus dem Baukasten...
Christian J. schrieb:> Und das *data++ wurde grad oben als gleichwertig bezeichnet was ich auch> bezweifle, *(data++) muss das heissen.
Heisst du mit zweitem Vornamen Thomas?
*p++ und *(p++) sind exakt gleichwertig. Seit es C gibt. Dieser Ausdruck
war von Anfang an eine Art Markenzeichen von C, um Guten wie im
Schlechten.
> Sonst würde ich ja seit 10 Jahren etwas falsch machen.
Und? ;-)
Dr. Sommer schrieb:> Nicht ausgeschlossen, schließlich verwendest du ja scheinbar seit 10> Jahren keine Arrays und nur eklige Pointer-Arithmetik...
Ja. auch **data und so eklige Sachen :-) Je mehr * desto mehr Ehr. * ist
Elite, [] ist Lamer :-)
Christian J. schrieb:> Ja. auch **data und so eklige Sachen :-) Je mehr * desto mehr Ehr. * ist> Elite, [] ist Lamer :-)
Ja dann fühle ich mich geehrt dass die Elite sich hier von den Lamern
beraten lässt...
A. K. schrieb:> Da steht aber auch, dass sie rechtsassoziativ sind. Und das ++ steht nun> einmal rechts, das * aber links.
Oh, überlesen. Okay, dann hast du recht und sie sind gleichwertig.
Christian J. schrieb:> Steht oben, im Bildchen....
Bitte beide Varianten. Und wenns geht nicht zum selber suchen, sondern
einfach beide in den gleichen Beitrag rein. Und zwar mit jeweils der
Optimierung mit der die eine Varianten Kräscht und die andere nicht.
Nee, hatte es missverständlich ausgedrückt. Wir haben 2 Stückchen C
Code. Mit Optimierung kräscht der eine, aber nicht der andere. Was ich
brauche ist der Code dieser beiden Versionen mit ebendieser Optimierung
eingeschaltet.
Dr. Sommer schrieb:> Das ldrb ... ,#1 ist doch schon höchst verdächtig.Christian J. schrieb:> ldrb.w r0, [r5], #1>> Hmmm.....A. K. schrieb:> Was stört dich an dem? Das ist> r0 = *r5++
Hubbs, mit ldrb r0, [r5, #1] d.h. Offset-Adressierung, verwechselt.
A. K. schrieb:> Nee, hatte es missverständlich ausgedrückt. Wir haben 2 Stückchen C> Code. Mit Optimierung kräscht der eine, aber nicht der andere. Was ich> brauche ist der Code dieser beiden Versionen mit ebendieser Optimierung> eingeschaltet.
Sekunde... muss mir mal ne Kaffee holen.... kommt gleich....
Dr. Sommer schrieb:> Aber leider falsch. Zugriff auf den Backup RAM geht bei vollem Takt.
laut ST hängt es am APB1 Bus
"an APB1 interface used to interface with the APB1 bus. The backup
domain
registers are accessible through the APB1 bus in read/write access
mode."
Mein G... Der Cortex bietet mit dem Hardfault eine super
Fehlerbehandlung, aber der user fummelt weiter wie in Großmutters Zeiten
rum.
Es wurde schon mehrfach erwähnt: Schreib einen eigenen Händler und lese
die Register vom Stack. Dann kennst du den Grund und die Stelle des
Vorkommens.
(Ich gehe auch von einem Timing Problem und damit Design Fehler vom user
aus.)
hardfault schrieb:> Es wurde schon mehrfach erwähnt: Schreib einen eigenen Händler und lese> die Register vom Stack. Dann kennst du den Grund und die Stelle des> Vorkommens.
KANN ICH ABER NICHT !!!!!!!!!!
Weil ich nicht weiss wie das geht, bzw ganz bestimmt nicht in wenigen
Minuten, da dieser Thread hier wie in Chat läuft.
Gib mir den inline Asm und ich mach das, den Handler habe ich schon
überschrieben.
Mann.....
Christian J. schrieb:> Alle beide mit Optimierung -O1.
In der ersten Variante fehlt was.
> 08002EBA bl 0x8002e48 <tls_Set74HCT595>
Dahinter gehts noch weiter.
Dieter Graef schrieb:> The backup> domain> registers are accessible through the APB1 bus in read/write access> mode."
Um die gehts aber nicht.
Christian J. schrieb:> KANN ICH ABER NICHT !!!!!!!!!!
Dann lern es. Wir sollen hier deinen Assembler Code auseinander nehmen
(Was viel nerviger ist) aber selber bist du dir zu fein mal das ARMv7M
Architecture Reference Manual zu lesen? Früher oder später wird dir das
sehr nützlich sein.
> Weil ich nicht weiss wie das geht, bzw ganz bestimmt nicht in wenigen> Minuten, da dieser Thread hier wie in Chat läuft.
Dann fang einfach an zu lesen. So unfassbar kompliziert ist das Auslesen
von einer Handvoll Registern nicht...
Dr. Sommer schrieb:> Dann lern es.
Ruhig bleiben, es zwingt dich niemand. Mit diesem Konstrukt unten kann
man das aber es fehlt mir verdammt nochmal die Möglichkeit das
auszugeben, weil es im Debug Mode nicht auftritt und im Release Mode
keine Ausgabe zur Verfügung steht, die mehr als eine rote LED ist. Keine
Uart, kein Terminal.
Christian J. schrieb:> /* Sendet einen Datensatz über das Schieberegister */> void __attribute__((optimize(0))) tls_74HCT595_SendData(const uint8_t> *data,size_t nrBytes)> {> do> tls_Set74HCT595(*(data++));> while (--nrBytes > 0);> }>> Da ist doch nix Unklares drin ?????
Tja - wenn du so sehr von dir selbst eingenommen bist, dann mach mal so
weiter.
Ich würde das so schreiben:
1
voidHCT595Out(char*data,intnum)
2
{while(num)
3
{SetHCT595(*data);
4
++data;
5
--num;
6
}
7
}
Über das ++data versus data++ könnte man sich streiten, aber die
tatsächliche Umsetzung überlasse ich lieber dem Compiler. Ansonsten bin
ich mir sicher, daß dieser Code NICHT abstürzt, solange data nicht auf
ne Adresse zeigt, die außerhalb zugreifbarer Adreßbereiche liegt.
Christian J. schrieb:> Wieso zur Hölle crashed dieser Code
Du schreibst unverständliches Zeug. Wie crasht denn ein Code, he?
Schreib lieber, was tatsächlich passiert. Also mit was für einer
Exception dein Code abgewürgt wird oder ob der ganze µC dabei einfriert
oder ob er wirkungslos durchlaufen wird oder was denn sonst. Ohne
konkrete Informationen kann dir hhier keiner wirklich weiterhelfen.
W.S.
W.S. schrieb:> Ohne> konkrete Informationen kann dir hhier keiner wirklich weiterhelfen.W.S. schrieb:> Ich würde das so schreiben:void HCT595Out (char* data, int num)> { while (num)> { SetHCT595(*data);> ++data;> --num;> }> }
Das crashed auch und landet im Hardfault Handler. Wo und warum und
weshalb kann ich nicht sagen, mangels Einsehbarkeit. Die rote LED ist
an, die im Handler gesezt wird, das ist alles.
Ok, beenden wir es hier. Ich weiss nicht weiter und kann das hier auch
nicht so darstellen wie mancher es gern hätte.
Trotzdem danke für die Mühen.
Wie erwartet funktioniert es wunderbar. Mein printf habe ich dazu
schlauerweise so konfiguriert, dass es auch im Release-Modus ausgibt.
Meine Compiler Version:
gcc version 5.2.1 20151202 (release) [ARM/embedded-5-branch revision
231848] (GNU Tools for ARM Embedded Processors)
von https://launchpad.net/gcc-arm-embedded
Mein Compiler&Linker-Aufruf:
Die SWV Schnittstelle hast Du auch nicht zur Verfügung ?
Habe mal meinen SWV basierten Hard-Fault-Handler Code angegehängt, hat
mir schon ein paar Mal geholfen.
Habe ich aus ein paar Quellen im Internet zusammen gestellt.
Dr. Sommer schrieb:> __attribute__((noinline));
Kannst du mir mal sagen wie mna das kompilieren muss? Bei mir kommt da
immer ein Fehler:
src\tools.c|165|error: expected ',' or ';' before '{' token|
||=== Build finished: 1 errors, 0 warnings (0 minutes, 2 seconds) ===|
Daniel B. schrieb:> Die SWV Schnittstelle hast Du auch nicht zur Verfügung ?
Doch, müsste ich einschalten, .... aber auf die Schnelle eher nicht,
noch nie benutzt, muss ich mir erst anschauen. Ausgaben ins Debug
Fenster sind das. Ich habe deine Routinen mal gesichert, die sehen gut
aus. Muss mir erstmal eine Uart dranfrickeln, damit ich mehr sehe.
Christian J. schrieb:> Kannst du mir mal sagen wie mna das kompilieren muss? Bei mir kommt da> immer ein Fehler:
Bei mir nicht, weder in C noch C++. Mein Compiler-Aufruf steht doch da.
Christian J. schrieb:> Daniel B. schrieb:>> Die SWV Schnittstelle hast Du auch nicht zur Verfügung ?>> Doch, müsste ich einschalten, .... aber auf die Schnelle eher nicht,> noch nie benutzt, muss ich mir erst anschauen. Ausgaben ins Debug> Fenster sind das. Ich habe deine Routinen mal gesichert, die sehen gut> aus. Muss mir erstmal eine Uart dranfrickeln, damit ich mehr sehe.
Ich muss nur im STM32 ST-Link Utility über den "ST-Link" -> "Printf via
SWO-Viewer" einschalten, und schon erscheint der Output, wenn das Prg in
den
Hard-Fault Handler springt.
Dr. Sommer schrieb:> Bei mir nicht, weder in C noch C++. Mein Compiler-Aufruf steht doch da.
Bei EmBitz sieht man das nur kurz, dann wird es überschrieben. Kann ich
nicht raus extrahieren. Wird sicher aber in irgendeinem Logfile stehen.
es kompiliert jetzt durch aber nur wenn ich es beim Prottypen
reinschreibe und nicht bei der implementierten Funktion.
Ich muss mich mit dem "Semihosting" mal befassen, das wird unterstützt,
nur eben noch nie verwendet.
Ich ziehe mich mit den vielen Infos jetzt mal zurück und muss einiges
ausprobieren bzw., einen vernünftigen Handler einschreiben, damit ich
sehe was die Exception ausgelöst hat, alles andere ist Quark.
Daniel B. schrieb:> Ich muss nur im STM32 ST-Link Utility über den "ST-Link" -> "Printf via> SWO-Viewer" einschalten, und schon erscheint der Output, wenn das Prg in> den> Hard-Fault Handler springt.
Bei EmBitz heisst das Semihosting aber das klappte damals nicht, daher
nie weiter mit befasst.
Daniel B. schrieb:> Christian J. schrieb:>> Daniel B. schrieb:>>> Die SWV Schnittstelle hast Du auch nicht zur Verfügung ?>>>> Doch, müsste ich einschalten, .... aber auf die Schnelle eher nicht,>> noch nie benutzt, muss ich mir erst anschauen. Ausgaben ins Debug>> Fenster sind das. Ich habe deine Routinen mal gesichert, die sehen gut>> aus. Muss mir erstmal eine Uart dranfrickeln, damit ich mehr sehe.>> Ich muss nur im STM32 ST-Link Utility über den "ST-Link" -> "Printf via> SWO-Viewer" einschalten, und schon erscheint der Output, wenn das Prg in> den> Hard-Fault Handler springt.
Sorry, vergessen zu erwähnen, dass ich mit dem ST-Link V2 und der
Software
von ST arbeite.
Daniel B. schrieb:> Sorry, vergessen zu erwähnen, dass ich mit dem ST-Link V2 und der> Software> von ST arbeite.
Grad mal quer gelesen im Netz.
http://klaus4.blogspot.de/2014/05/printf-ganz-einfach-per-semihosting-auf.html
Semihosting muss eingerichtet werden, das ist mehr als nur ein Kreuzchen
machen. Ich sehe nichts bei printf, auch nicht wenn ich den stdout
Buffer abschalte. Und dazu kommt noch dass ich in einer IDE arbeite und
erstmal die tausend Einstellmöglichkeiten durchgehen muss.
Eine Uart benutzen mit einem USB Wandler und einem Terminalfenster oder
htermn etc ist einfacher.
Aber jetzt Ende, mir raucht der Schädel und das ist nicht gut für 2
Tagwe Resturlaub.
Christian J. schrieb:> Ich ziehe mich mit den vielen Infos jetzt mal zurück und muss einiges> ausprobieren bzw., einen vernünftigen Handler einschreiben, damit ich> sehe was die Exception ausgelöst hat, alles andere ist Quark.
Na endlich siegt die Vernunft. ;-)
Viel Erfolg!
hardfault schrieb:> Na endlich siegt die Vernunft. ;-)
Was ist Vernunft? Man kann doch das hier nehmen, es läuft!
for (size_t i = 0;i < nrBytes; i++)
tls_Set74HCT595(data[i]);
Oder sind viele Stunden sinnvoll heraus zu finden warum das andere nicht
läuft? Ich erinnere mich an eine Debatte mit meinem Chef vor vielen
Jahren. Der hätte mir keinen Cent dafür bezahlt warum etwas nicht geht,
wenn eine andere Lösung funktioniert. Auch nicht wegen der "Erkenntnis".
Christian J. schrieb:> hardfault schrieb:>> Na endlich siegt die Vernunft. ;-)>> Was ist Vernunft? Man kann doch das hier nehmen, es läuft!>> for (size_t i = 0;i < nrBytes; i++)> tls_Set74HCT595(data[i]);
Noch. Aber bald taucht der Fehler wieder auf, und dann stehst du wieder
doof da. Denn wir wir ja gerade herausgefunden haben, liegt das Problem
gar nicht in dieser Funktion.
> Oder sind viele Stunden sinnvoll heraus zu finden warum das andere nicht> läuft? Ich erinnere mich an eine Debatte mit meinem Chef vor vielen> Jahren. Der hätte mir keinen Cent dafür bezahlt warum etwas nicht geht,> wenn eine andere Lösung funktioniert. Auch nicht wegen der "Erkenntnis".
Aber vielleicht dafür, sicher zu wissen, dass das dann hoffentlich
gefundene Problem nicht plötzlich bein Kunden auftritt?
Christian J. schrieb:> Oder sind viele Stunden sinnvoll heraus zu finden warum das andere nicht
Ja! Das ist sogar sehr sinnvoll. Dann bist erstens sicher, dass du nicht
nur einen Seiteneffekt kaschierst ( was hier stark zu vermuten ist). Das
Problem wird dann wieder aufzrten und pb es dann so eonfach
reproduzierbar ist? Du kannst doch glücklich sein, dass du das
reproduzieren kannst. Das ist schon die halbe Miete. Und zweitens hilft
es auch beim nächsten Mal. Und du lernst eine Menge (was auch deinem
Chef zugute kommt).
Dr. Sommer schrieb:> Noch. Aber bald taucht der Fehler wieder auf, und dann stehst du wieder> doof da. Denn wir wir ja gerade herausgefunden haben, liegt das Problem> gar nicht in dieser Funktion.
Mache jetzt Schluss. Habe die debug Routinen oben, die bei mir so nicht
laufen weil da vieles wohl noch fehlt mal runter gestripped auf die
reinen Entscheidungen ohne die printf und Ausgaben auf die SWD. Und dann
die Exceptions auf LED verteilt wovon genug da sind. Er landet in der
Funktion
void printMemoryManagementErrorMsg(uint32_t CFSRValue)
"Memory Management fault".
Das zu wissen bringt mich auch nicht weiter, außer dass es eben auffiel,
dass nur das Backup Ram betroffen ist und alles andere nicht, was da
durchgespielt wird.
Normalerweise würde ich es sowas mit einem Debug Tracer rangehen, der
die letzten zig Anweisungen aufzeichnet, bevor er "abhebt". Aber das
gibt es hier nicht.
PS: Ist nur privat, beruflich bin in Sachen Normung wie GS-ET, DIN und
CENELEC unterwegs.
Man, man, man, atme einmal kräftig durch und setze deinen Plan um, die
Sache richtig anzugehen. Unter den gesicherten Registern liegt auch der
PC mit der "error" Anweisung auf dem Stack. Was willst du mehr?
Es gibt Bastler und Entwickler. Leider gibt es auch unter den Profis
viele Bastler und damit schlechte Produkte.
(Wie verbohrt muss man sein, die vielen guten Hinweise zu ignorieren,
und sich weiter mit Nebensächlichkeiten abzulenken?)
:'( :'( :'(
>Man, man, man, atme einmal kräftig durch und setze deinen Plan um, die>Sache richtig anzugehen.
Aber nicht mehr heute! Das dauert zu lange, um das ganze Instrumentarium
aufzusetzen und ich habe Urlaub und eine Frau, die hier langsam sauer
wird!
>> f814 0b01 ldrb.w r0, [r4], #1
Hier geht er raus, das weiss ich jetzt.
Halten wir für die Nachwelt fest (habe schon mal nach 5 Jahren eine PN
auf einen Beitrag von 2009 bekommen)
Die Kombination
- Verwendung des Backup Rams als Source
- Verwendung der -O1,O2,O3 GCC Optimierung aber
- NICHT die der -Os
- in Verbindung mit Zeigeroperationen bie der Parameterübergabe
scheint ein Problem vermuten zu lassen. Das lasse ich erstmal so stehen
und jetzt gehts ans Mittag- bzw Abendessen machen, meine Holde fragt eh
schon wieso ich nur auf dem Dachboden rumhänge den ganzen Tag...
Die Kombination "Christian" und Cortex-Dokumentation ist das wirkliche
Problem. Es könnte so einfach sein, aber wer nicht will ...
Die Doku kannst du auch in der Küche oder auf dem Sofa neben der Holden
lesen. ;-)
Hallo Herr Hardfault,
mein Freund wird sich sicherlich irgendwann dem Thema wieder zuwenden
aber es werden garantiert nicht im Wohnzimmer oder in der Küche
irgendwelche Apparaturen oder technische Bücher abgelagert !!!!! Und
notfalls wird das Kabel aus dem Router rausgezogen.
Ende der Durchsage und einen schönen Abend.
Karina T.
A. K. schrieb:> Nur ist hier nicht data konstant, sondern das, worauf es zeigt.
Korrekt!
*data = waswasich;
erzeugt einen Compiler Fehler.
data++,
aber nicht.
Alter.... ich riskiere noch meine Beziehung hier :-( Was ist wichtiger,
die Lösung des Problems oder evtl. kein Sex heute abend, weil der
Haussegen schief hängt?
Mannomann....
Christian J. schrieb:> Dr. Sommer schrieb:>>> Ja, vermutlich dass die Leute ungültigen C Code schreiben, der bei>> Verwendung von Compiler Optimierungen kaputt geht, was dann natürlich>> immer auf den Compiler geschoben wird.>> Ich wäre vorsichtig mit solchen Behauptungen. Ich arbeite nicht in einer> Klitsche sondern einem deutschen Weltkonzern mit einem "B" vorne und mit> hohen Qualitätsstandards. Und im Gespräch mit jemandem aus der Firmware> Ecke wurde mir das gesagt. MISRA + Optimierung alle aus und noch vieles> mehr.
Sorry für's Offtopic:
Ich kenne die Firma von der du sprichst ebenfalls sehr gut, und kann
durch persönliche Erfahrung eigentlich eher Dr. Sommer recht geben als
dir bzw. deinem Kollegen. Ich will nicht alle schlechtmachen, aber das
Knowhowlevel ist niedriger als man es von einem Konzern in dieser
Branche erwarten würde. Da ist es natürlich leicht die Schuld überall
nur nicht bei sich selbst zu suchen.
Ja, man ist um hohe Qualität bemüht, aber man versucht das nicht durch
qualitativen Code sondern durch gigantische Testaufwände und Manpower zu
erreichen.
Christian J. schrieb:>>> f814 0b01 ldrb.w r0, [r4], #1>> Hier geht er raus, das weiss ich jetzt.
Das war zu vermuten. Wenn du jetzt noch herausfindest, was dabei in r4
stand, weißt du welcher Speicherzugriff schuld war. Beim Betreten der
Exception wird r4 nicht verändert, solltest du also direkt danach
auslesen können (der Handler-Code kann das aber evtl. überschreiben).
Christian J. schrieb:> Alter.... ich riskiere noch meine Beziehung hier :-( Was ist wichtiger,> die Lösung des Problems oder evtl. kein Sex heute abend, weil der> Haussegen schief hängt?
Ach den gibts danach sowieso nicht weil Kopfweh, Essen hat nicht
geschmeckt, Frisur nicht sitzt etc., die Mühe kannst du dir also
sparen...
Manuel W. schrieb:> Ja, man ist um hohe Qualität bemüht, aber man versucht das nicht durch> qualitativen Code sondern durch gigantische Testaufwände und Manpower zu> erreichen.
Das ist richtig. Die Whitebox und Blackbox Test bzw. Arbeit nach
V-Modell und 61508, bzw. Code Review sind ein wesentlicher Bestandteil
der Aufdeckung von Fehlern. Ein Update ist 4 Wochen alt wenn es
eingespielt wird, weil es 4 Wochen lang vorher auf einem Testrechner
lief usw. Dazu noch Tools wie lint und andere Runtime Analyzer.
Allerdings kann niemand verlangen, dass sich der Programmierer noch mit
dem Werkzeug selbst in der Tiefe auseinander setzt wie seine Entwickler.
Daher ist der GCC sowieso kein Thema, da niemand weiss, wer da alles
dran baut und wer zur Haftung gezogen werden kann.
Ich gehe davon aus dass Probleme wie "Gaspedal bei Toyota" und anderes
auf solche Dinge zurück zu führen sind. Genauso wie Raketen abgestürtzt
sind, weil man alten Code auf neue Hardware portiert hat oder so simple
Dinge wie angelsächsische Maße und SI Maße verwürfelt hat (Mars Lander).
Wir sind Menschen, keine Maschinen....
Allerdings hab ich bei diesser CPU zwei GPIO zerschossen. Habe Stunden
verbracht um herauszufinden wieso die "flackern", wenn ihre Nachbarn
geschaltet werden. Dann erst ein anderes Board eingesetzt und da war es
nicht. Jetzt wieder das mit PE0 und PE1 = kaputt. Vielleicht ist da noch
was anderes hnüber gegangen bei dem Rumgebastel, anfassen, löten usw.
Montag kommt ne neue CPU drauf im Labor, habe kein Tools hier die
auszuulöten.
Dr. Sommer schrieb:> Beim Betreten der> Exception wird r4 nicht verändert, solltest du also direkt danach> auslesen können (der Handler-Code kann das aber evtl. überschreiben).
Sobald ich ein Debug Tool aufgesetzt habe, gerne :-) Aber dazu muss ich
dieses Semihosting erstmal durchdrungen haben anhand von Beispielen aus
dem Netz. Das tuts hier nämlich nicht so wie zb auf meiner Rowley
Crossworks IDE damals, wo das out of the box lief, printf und fertig.
Aber Rowley kaufe ich nicht mehr, 150 Ocken sind mir auch für die
Student Version zu viel. Und an Eclipse habe ich verzweifelt und ST
Studio kenne ich nicht.
Jojo S. schrieb:> Das Semihosting sollte sich einfach durch Auswahl der entsprechenden Lib> aktivieren lassen,
Welche Lib? EmBitz kommt nackt daher. Die IDE ist nur eine GUI, die die
Kommandozeile verbirgt aber im Hintergrund aufruft und deren Ausgaben
herein holt. Das muss man sich alles selbst basteln.
Zum Register auslesen braucht's doch kein Semihosting... einfach einen
Breakpoint in den Handler setzen und dann in die Register Anzeige der
IDE gucken...
Dr. Sommer schrieb:> dann in die Register Anzeige der> IDE gucken...Dr. Sommer schrieb:> einfach einen> Breakpoint in den Handler setzen und dann in die Register Anzeige der> IDE gucken...
s.o. Im Release Mode (= Endzustand, keine Debug Infos etc) besteht keine
Verbindung zum St-Link V2 und im Debug Mode kommt es nicht. Auf die Idee
bin ich schon früher gekommen, hätte den Thread dafür nicht starten
müssen. Im Debug Mode kann man schritt für Schritt das Problem
einkreisen. Aber auch ein "Run" (F5) ist nicht das Gleiche wie im
Release Mode. Das Programm läuft erheblich langsamer als sonst... danke
erstmal und bin jetzt weg, Kopf raucht, kann nicht mehr.
Muß ich mir eigentlich Sorgen machen, wenn ich hier mitlese, oder machen
die wirklich wichtigen Dinge in dem Weltkonzern mit "B" eh nur Externe,
die sich mit so was auskennen?
Christian J. schrieb:> s.o. Im Release Mode (= Endzustand, keine Debug Infos etc) besteht keine> Verbindung zum St-Link V2
Was ist das denn für eine miese IDE. Die würde ich direkt mal entsorgen.
eclipse kann das, gdb direkt auf der Konsole auch. Kannst du nicht in
Debug-Modus einfach noch -Os übergeben...
Dr. Sommer schrieb:> Was ist das denn für eine miese IDE. Die würde ich direkt mal entsorgen.
Du hast recht, das geht wirklich. Man kann sogar zuschauen wie sich
Regster life verändern .Wusste ich aber auch noch nicht. Man muss
allerdings Debug Infos dazu linken und ein .svd File musste ich mir auch
besorgen. Dann rennt er auch direkt in den Handler rein und das kommt
dabei heraus. Ich kann das allerdings noch nicht deuten, da ich nicht
genau weiss welche Register ich mir anschauen muss aber das kommt noch.
Wieder was dazu gelernt....
PS: Auch wenn es hin und wieder Probs gibt, muss ja mal sagen, dass das
ne saugeile CPU ist :-) Da komm ich richtig von meinem Z80 runter seit
ich die habe.
Christian J. schrieb:> Das crashed auch und landet im Hardfault Handler. Wo und warum und> weshalb kann ich nicht sagen, mangels Einsehbarkeit.
O je.
Jeder normale Entwickler hätte sich in weiser Voraussicht irgend einen
blöden UART zwecks Log-Ausgabe eingerichtet und könnte vor dem
Lesezugriff mit *data den Wert von data dort ausgeben. Und schon wüßte
man, auf welche unzulässige Speicherstelle data hinzeigt.
Ist man heutzutage dafür zu doof?
Alternativ könnte man sich nen Hardfault-Handler schreiben, der diese
Ausgabe erledigt und dann in die App zurückspringt - oder der den Zeiger
irgendwo hin rettet, ein Flag setzt und dann nen Kaltstart auslöst.
Danach kann man in aller Ruhe Flag und Zeiger auswerten.
W.S.
hardfault schrieb:> Die Kombination "Christian" und Cortex-Dokumentation ist das wirkliche> Problem. Es könnte so einfach sein, aber wer nicht will ...
Ich greif das nochmal auf ..... das Problem ist inzwischen gelöst. Und
das ganz ohne den Aufwand mit Debug Modulen usw. Es war auch ein
Problem, wo ich 3 Tage an einem NRF24L01 frickelte und mich wunderte,
dass die Ausgaben auf dem Logger "seltsam" waren und wieso 2 LEDs
manchmal etwas glimmten, nur so ein bisschen.
Manchmal ist die einfache Lösung die beste ..... man tausche einfach mal
die CPU aus. Nur so, auf gut Glück.
Denn seitdem läuft das einwandfrei durch. Durch das ständige Anfassen,
Rumstecken, auf dem Teppich rumrutschen usw. hat die ne Macke weg
gehabt. Auch eine SPI war betroffen, der MOSI "klebte" stuck-at-hi fest
nach dem ersten Setzen auf High.
ESD in den Kaffee! :-)
Gruss,
Christian