Forum: Mikrocontroller und Digitale Elektronik STM32: Drama mit "Hard Fault Error"


von Christian J. (Gast)


Lesenswert?

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 */
2
void __attribute__((optimize(0))) tls_74HCT595_SendData(const uint8_t *data,size_t nrBytes)
3
{
4
    do
5
       tls_Set74HCT595(*(data++));
6
    while (--nrBytes > 0);
7
}

Da ist doch nix Unklares drin ?????

Hier die Senderoutine aber die läuft, mit und ohne Optimierung
1
void  __attribute__((optimize(0))) tls_Set74HCT595(uint8_t data)
2
{
3
    #define DELAY_595   2
4
    for (uint8_t i = 0; i < 8; i++) {
5
        // Datenbit setzen
6
        GPIO_SetPinValue(GPIOE,HCT595_DS,(data & 0x80));
7
        GPIO_SetBits(GPIOE,HCT595_SHCP);        // SHCP -> High
8
        //wait(DELAY_595);
9
        GPIO_ResetBits(GPIOE,HCT595_SHCP);      // SHCP -> LOW
10
        //wait(DELAY_595);
11
        data = data << 1;
12
    }
13
14
    // 8 Bit an die Ausgaenge clocken
15
    GPIO_SetBits(GPIOE,HCT595_STCP);            // STCP -> HIGH
16
    //wait(DELAY_595);
17
    GPIO_ResetBits(GPIOE,HCT595_STCP);          // STCP -> LOW
18
    GPIO_ResetBits(GPIOE,HCT595_OE);            // OE -> LOW (aktiv)
19
}

von temp (Gast)


Lesenswert?

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?

von larx (Gast)


Lesenswert?

kannst Du das nicht Schritt für Schritt durchsteppen, um die Stelle kurz 
vor dem Hard Fault Error zu finden?

von Dirk (Gast)


Lesenswert?

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"?

von Off by one? (Gast)


Lesenswert?

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.

von Roland E. (roland0815)


Lesenswert?

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.

von 900ss (900ss)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

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
/ Backup Ram aktivieren
2
void Init_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
6
7
    // Prüfe, ob Spannungsregler eingeschaltet ist
8
    if (PWR_GetFlagStatus(PWR_FLAG_BRR) == RESET)
9
    {
10
        PWR_BackupAccessCmd(ENABLE);                                  // Schreibzugriff aufs Backup Ram
11
        PWR_MainRegulatorModeConfig(PWR_Regulator_Voltage_Scale1);    // Regulator auf Strom für 168 Mhz setzen
12
        PWR_BackupRegulatorCmd(ENABLE);                               // Backup Spannungsregler aktivieren
13
        while(PWR_GetFlagStatus(PWR_FLAG_BRR) != SET);                // Warte bis er stabil ist
14
    }
15
16
    PWR_BackupAccessCmd(ENABLE);                                      // Schreibzugriff aufs Backup Ram
17
}

von Dr. Sommer (Gast)


Lesenswert?

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...

von Christian J. (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

Sicher, dass es der Backup RAM und nicht die Backup Register sind? Auf 
die kann man nämlich nur 32Bit- Word - weise zugreifen.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

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

von Dieter Graef (Gast)


Lesenswert?

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.

von Off by one (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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_t i = 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.

von Christian J. (Gast)


Lesenswert?

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.

von Nase (Gast)


Lesenswert?

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.

von Nase (Gast)


Lesenswert?

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 :-)

von Christian J. (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

Christian J. schrieb:
> Ähm... also das ist mir jetzt neu.

Um welchen Typ gehts hier denn? ST hat ja mehr als eine Familie.

von Christian J. (Gast)


Lesenswert?

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....

von Christian J. (Gast)


Lesenswert?

A. K. schrieb:
> Um welchen Typ gehts hier denn? ST hat ja mehr als eine Familie.

STM32F407VG

von Dr. Sommer (Gast)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

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.
1
* Sendet einen Datensatz über das Schieberegister */
2
void tls_74HCT595_SendData(const uint8_t *data,size_t nrBytes)
3
{
4
//    do
5
//       tls_Set74HCT595(*(data++));
6
//    while (nrBytes-- > 0);
7
8
    for (uint16_t i = 0;i < nrBytes; i++)
9
        tls_Set74HCT595(data[i]);
10
11
12
}

Tja....

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

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.....

von Dr. Sommer (Gast)


Lesenswert?

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...

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

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 ....

von 900ss (900ss)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

Soooooo....


Kräääääääsch!
1
/* Sendet einen Datensatz über das Schieberegister */
2
void tls_74HCT595_SendData(const uint8_t *data,size_t nrBytes)
3
{
4
    for (size_t i = 0;i < nrBytes; i++)
5
        tls_Set74HCT595(*data++);
6
7
}

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.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

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.....

von 900ss (900ss)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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. ;-)

von Christian J. (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

Christian J. schrieb:
> Kräääääääsch!

Der erzeugte Code könnte helfen.

von Dr. Sommer (Gast)


Lesenswert?

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...

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

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...

von (prx) A. K. (prx)


Lesenswert?

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? ;-)

von Christian J. (Gast)


Lesenswert?

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 :-)

von (prx) A. K. (prx)


Lesenswert?

Dr. Sommer schrieb:
> Laut http://en.cppreference.com/w/cpp/language/operator_precedence haben
> * und ++ die gleiche Priorität, somit müsste *data++ undefiniert sein.

Da steht aber auch, dass sie rechtsassoziativ sind. Und das ++ steht nun 
einmal rechts, das * aber links.

von Dr. Sommer (Gast)


Lesenswert?

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...

von Dr. Sommer (Gast)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

A. K. schrieb:
> Der erzeugte Code könnte helfen.

Steht oben, im Bildchen....

(186)  {
08002EAC  push  {r3, r4, r5, lr}
08002EAE  mov  r5, r0
(187)      if (nrBytes == 0)
08002EB0  mov  r4, r1
08002EB2  cbz  r1, 0x8002ec0 <tls_74HCT595_SendData+20>
(188)          return;
(189)      do
(190)         tls_Set74HCT595(*data++);
08002EB4  ldrb.w  r0, [r5], #1
08002EB8  bl  0x8002e48 <tls_Set74HCT595>
(191)      while (--nrBytes > 0);
08002EBC  subs  r4, #1
08002EBE  bne.n  0x8002eb4 <tls_74HCT595_SendData+8>
08002EC0  pop  {r3, r4, r5, pc}

1 abziehen, Branch not on equal n .. sieht alles ok aus.


ldrb.w  r0, [r5], #1

Hmmm.....

von (prx) A. K. (prx)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

A. K. schrieb:
> Und zwar mit jeweils der
> Optimierung mit der die eine Varianten Kräscht und die andere nicht.

Moment.....

von (prx) A. K. (prx)


Lesenswert?

Christian J. schrieb:
> ldrb.w  r0, [r5], #1

Was stört dich an dem? Das ist
  r0 = *r5++

von Christian J. (Gast)


Lesenswert?

Mit Optimierung und Kräsch:
1
(186)  {
2
08002EAC  push  {r3, r4, r5, lr}
3
08002EAE  mov  r5, r0
4
(187)      if (nrBytes == 0)
5
08002EB0  mov  r4, r1
6
08002EB2  cbz  r1, 0x8002ec0 <tls_74HCT595_SendData+20>
7
(188)          return;
8
(189)      do
9
(190)         tls_Set74HCT595(*data++);
10
08002EB4  ldrb.w  r0, [r5], #1
11
08002EB8  bl  0x8002e48 <tls_Set74HCT595>
12
(191)      while (--nrBytes > 0);
13
08002EBC  subs  r4, #1
14
08002EBE  bne.n  0x8002eb4 <tls_74HCT595_SendData+8>
15
08002EC0  pop  {r3, r4, r5, pc}


Ohne Optimierung und kein Crash:
1
(186)  {
2
08002EAC  push  {r7, lr}
3
08002EAE  sub  sp, #8
4
08002EB0  add  r7, sp, #0
5
08002EB2  str  r0, [r7, #4]
6
08002EB4  str  r1, [r7, #0]
7
(187)      if (nrBytes == 0)
8
08002EB6  ldr  r3, [r7, #0]
9
08002EB8  cmp  r3, #0
10
08002EBA  bne.n  0x8002ebe <tls_74HCT595_SendData+18>
11
(188)          return;
12
08002EBC  b.n  0x8002ed8 <tls_74HCT595_SendData+44>
13
(189)      do
14
(190)         tls_Set74HCT595(*data++);
15
08002EBE  ldr  r3, [r7, #4]
16
08002EC0  adds  r2, r3, #1
17
08002EC2  str  r2, [r7, #4]
18
08002EC4  ldrb  r3, [r3, #0]
19
08002EC6  mov  r0, r3
20
08002EC8  bl  0x8002e48 <tls_Set74HCT595>
21
(191)      while (--nrBytes > 0);
22
08002ECC  ldr  r3, [r7, #0]
23
08002ECE  subs  r3, #1
24
08002ED0  str  r3, [r7, #0]
25
08002ED2  ldr  r3, [r7, #0]
26
08002ED4  cmp  r3, #0
27
08002ED6  bne.n  0x8002ebe <tls_74HCT595_SendData+18>
28
08002ED8  adds  r7, #8
29
08002EDA  mov  sp, r7
30
08002EDC  pop  {r7, pc}

von (prx) A. K. (prx)


Lesenswert?

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.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

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....

von Dieter Graef (Gast)


Lesenswert?

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."

von Christian J. (Gast)


Lesenswert?

Alle beide mit Optimierung -O1.

Die lauffähige  Version:
(186)  {
08002EAC  push  {r3, r4, r5, lr}
(187)      if (nrBytes == 0)
08002EAE  mov  r5, r1
08002EB0  cbz  r1, 0x8002ec2 <tls_74HCT595_SendData+22>
08002EB2  mov  r4, r0
08002EB4  add  r5, r0
(188)          return;
(189)  //    do
(190)  //       tls_Set74HCT595(*data++);
(191)  //    while (--nrBytes > 0);
(192)
(193)      for (size_t i = 0;i < nrBytes; i++)
08002EBE  cmp  r4, r5
08002EC0  bne.n  0x8002eb6 <tls_74HCT595_SendData+10>
08002EC2  pop  {r3, r4, r5, pc}
(194)          tls_Set74HCT595(data[i]);
08002EB6  ldrb.w  r0, [r4], #1
08002EBA  bl  0x8002e48 <tls_Set74HCT595>

[/c]

Die Crash Version
1
(186)  {
2
08002EAC  push  {r3, r4, r5, lr}
3
08002EAE  mov  r5, r0
4
(187)      if (nrBytes == 0)
5
08002EB0  mov  r4, r1
6
08002EB2  cbz  r1, 0x8002ec0 <tls_74HCT595_SendData+20>
7
(188)          return;
8
(189)      do
9
(190)         tls_Set74HCT595(*data++);
10
08002EB4  ldrb.w  r0, [r5], #1
11
08002EB8  bl  0x8002e48 <tls_Set74HCT595>
12
(191)      while (--nrBytes > 0);
13
08002EBC  subs  r4, #1
14
08002EBE  bne.n  0x8002eb4 <tls_74HCT595_SendData+8>
15
08002EC0  pop  {r3, r4, r5, pc}

von hardfault (Gast)


Lesenswert?

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.)

von Christian J. (Gast)


Lesenswert?

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.....

von (prx) A. K. (prx)


Lesenswert?

Christian J. schrieb:
> Alle beide mit Optimierung -O1.

In der ersten Variante fehlt was.

> 08002EBA  bl  0x8002e48 <tls_Set74HCT595>

Dahinter gehts noch weiter.

von Dr. Sommer (Gast)


Lesenswert?

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...

von Christian J. (Gast)


Lesenswert?

Der Unterschied ist aber minimal:

tls_Set74HCT595(data[i]);
08002EB6  ldrb.w  r0, [r4], #1

  tls_Set74HCT595(*data++);
ldrb.w  r0, [r5], #1
08002EB8  bl  0x8002e48 <tls_Set74HCT595>

von (prx) A. K. (prx)


Lesenswert?

Ich schrieb vorhin schon, dass sich in solchem Kontext keine Puzzles zum 
selber zusammensetzen mag.

von Christian J. (Gast)


Lesenswert?

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.
1
static void HardFault_Handler(void)
2
{
3
    __asm volatile
4
    (
5
        " tst lr, #4                                                \n"
6
        " ite eq                                                    \n"
7
        " mrseq r0, msp                                             \n"
8
        " mrsne r0, psp                                             \n"
9
        " ldr r1, [r0, #24]                                         \n"
10
        " ldr r2, handler2_address_const                            \n"
11
        " bx r2                                                     \n"
12
        " handler2_address_const: .word prvGetRegistersFromStack    \n"
13
    );
14
}
15
16
17
void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress )
18
{
19
/* These are volatile to try and prevent the compiler/linker optimising them
20
away as the variables never actually get used.  If the debugger won't show the
21
values of the variables, make them global my moving their declaration outside
22
of this function. */
23
volatile uint32_t r0;
24
volatile uint32_t r1;
25
volatile uint32_t r2;
26
volatile uint32_t r3;
27
volatile uint32_t r12;
28
volatile uint32_t lr; /* Link register. */
29
volatile uint32_t pc; /* Program counter. */
30
volatile uint32_t psr;/* Program status register. */
31
32
    r0 = pulFaultStackAddress[ 0 ];
33
    r1 = pulFaultStackAddress[ 1 ];
34
    r2 = pulFaultStackAddress[ 2 ];
35
    r3 = pulFaultStackAddress[ 3 ];
36
37
    r12 = pulFaultStackAddress[ 4 ];
38
    lr = pulFaultStackAddress[ 5 ];
39
    pc = pulFaultStackAddress[ 6 ];
40
    psr = pulFaultStackAddress[ 7 ];
41
42
    /* When the following line is hit, the variables contain the register values. */
43
    for( ;; );
44
}

von W.S. (Gast)


Lesenswert?

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
void HCT595Out (char* data, int num)
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.

von Christian J. (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

Ich habe das Elend jetzt mal selber kompiliert und auf einem STM32F407VG 
ausgeführt:
1
void tls_Set74HCT595(uint8_t data) __attribute__ ((noinline));
2
void  tls_74HCT595_SendData(const uint8_t *data,size_t nrBytes) __attribute__((noinline));
3
4
void tls_Set74HCT595(uint8_t data)
5
{
6
  printf ("%x", data);
7
}
8
9
/* Sendet einen Datensatz über das Schieberegister */
10
void  tls_74HCT595_SendData(const uint8_t *data,size_t nrBytes)
11
{
12
   if (nrBytes == 0)
13
     return;
14
    do
15
       tls_Set74HCT595(*(data++));
16
    while (--nrBytes > 0);
17
}
ergibt
1
void tls_Set74HCT595(uint8_t data)
2
{
3
  printf ("%x", data);
4
 8000310:  4601        mov  r1, r0
5
 8000312:  4801        ldr  r0, [pc, #4]  ; (8000318 <tls_Set74HCT595(unsigned char)+0x8>)
6
 8000314:  f000 b93a   b.w  800058c <iprintf>
7
 8000318:  0800126c   .word  0x0800126c
8
9
0800031c <tls_74HCT595_SendData(unsigned char const*, unsigned int)>:
10
}
11
12
/* Sendet einen Datensatz über das Schieberegister */
13
void  tls_74HCT595_SendData(const uint8_t *data,size_t nrBytes)
14
{
15
 800031c:  b570        push  {r4, r5, r6, lr}
16
 800031e:  4605        mov  r5, r0
17
   if (nrBytes == 0)
18
 8000320:  460e        mov  r6, r1
19
 8000322:  b139        cbz  r1, 8000334 <tls_74HCT595_SendData(unsigned char const*, unsigned int)+0x18>
20
 8000324:  4604        mov  r4, r0
21
     return;
22
    do
23
       tls_Set74HCT595(*(data++));
24
 8000326:  f814 0b01   ldrb.w  r0, [r4], #1
25
 800032a:  f7ff fff1   bl  8000310 <tls_Set74HCT595(unsigned char)>
26
 800032e:  1b33        subs  r3, r6, r4
27
/* Sendet einen Datensatz über das Schieberegister */
28
void  tls_74HCT595_SendData(const uint8_t *data,size_t nrBytes)
29
{
30
   if (nrBytes == 0)
31
     return;
32
    do
33
 8000330:  42dd        cmn  r5, r3
34
 8000332:  d1f8        bne.n  8000326 <tls_74HCT595_SendData(unsigned char const*, unsigned int)+0xa>
35
 8000334:  bd70        pop  {r4, r5, r6, pc}

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:
1
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -munaligned-access -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -Werror -Wall -Wextra  -g -DSTM32F40_41xxx=1 -DNDEBUG=1 -std=c++1y -fabi-version=0 -fno-exceptions -fno-rtti -c -o "src/main.o" "../src/main.cc"
2
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -munaligned-access -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -Werror -Wall -Wextra  -g -T "STM32F407VG.ld" -Xlinker --gc-sections --specs=nano.specs -fno-exceptions -fno-rtti -static -o "Test.elf" ./src/main.o
Mit den "maximalen" Optimierungen (sogar LTO).

Daraus folgere ich, dass die Funktion funktioniert und bei dir 
irgendetwas anderes falsch ist.

von Daniel B. (dbuergin)


Angehängte Dateien:

Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

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) ===|

von Christian J. (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Daniel B. (dbuergin)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

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.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Daniel B. (dbuergin)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

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.

von hardfault (Gast)


Lesenswert?

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!

von Christian J. (Gast)


Lesenswert?

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".

von Dr. Sommer (Gast)


Lesenswert?

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?

von 900ss (900ss)


Lesenswert?

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).

von Christian J. (Gast)


Lesenswert?

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.

von hardfault (Gast)


Lesenswert?

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?)
:'( :'( :'(

von Christian J. (Gast)


Lesenswert?

>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...

von hardfault (Gast)


Lesenswert?

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. ;-)

von 900ss (900ss)


Lesenswert?

900ss D. schrieb:
> aufzrten und pb es dann so eonfach

Ufff! Ich war das nicht ;-)

von Christian J. (Gast)


Lesenswert?

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.

von hardfault (Gast)


Lesenswert?

Sach ich doch: Der Pantoffelheld ist das Problem! :-P

von Test (Gast)


Lesenswert?

1
tls_74HCT595_SendData(const uint8_t *data,size_t nrBytes)

nimm mal das const weg, da du data ja inkrementierst...
1
tls_74HCT595_SendData(uint8_t *data,size_t nrBytes)

von (prx) A. K. (prx)


Lesenswert?

Test schrieb:
> nimm mal das const weg, da du data ja inkrementierst...

Nur ist hier nicht data konstant, sondern das, worauf es zeigt.

von Christian J. (Gast)


Lesenswert?

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....

von Manuel W. (multisync)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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...

von Christian J. (Gast)


Lesenswert?

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.

von Christian J. (Gast)


Lesenswert?

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.

von Jojo S. (Gast)


Lesenswert?

Das Semihosting sollte sich einfach durch Auswahl der entsprechenden Lib 
aktivieren lassen, im Debugtool hast du das Häkchen ja schon gesetzt.

von Christian J. (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

Zum Register auslesen braucht's doch kein Semihosting... einfach einen 
Breakpoint in den Handler setzen und dann in die Register Anzeige der 
IDE gucken...

von Christian J. (Gast)


Lesenswert?

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.

von Autofahrer (Gast)


Lesenswert?

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?

von Dr. Sommer (Gast)


Lesenswert?

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...

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von GritBall (Gast)


Lesenswert?

> nen

Es muss einen heißen!

> Ist man heutzutage dafür zu doof?

von Christian J. (Gast)


Lesenswert?

W.S. schrieb:

> einen
> blöden UART

eine UART ist nicht blöd.

von Christian J. (Gast)


Lesenswert?

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

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.