Hi in mein Freertos + LWIP + stm32 Projekt habe ich das problem dass static uint16_t MyVariable_u16[256u] = { 1, 2,3, 4,5,6,7,... }; ""nicht immer"" richtig initialisiter wird. Die meisten Elemente vom array haben den richtigen wert, einige nicht. Hat jnd eine Idee? Das problem taucht auf wenn ich UDP packete schon vorm Einschalten zum STM32 schicke. Und selbst dann taucht es nicht immer auf! Danke
Kann es sein, dass dein RAM ein SDRAM und noch nicht initialisiert ist, wenn die Startuproutine die copy Loop vom Flash zum RAM macht? Normalerweise hängt der Startupcode der C Runtime direkt am Reset Vektor, und die Prozessorinitialisierung (einschliesslich SDRAM Controller Initialisierung) dahinter. In der Konfiguration mit SDRAM musst Du dann Teile der Controllerinitialisierung vor die C Runtimeinitialisierung setzen.
Könnte auch Stacküberlauf sein, d.h. der Stack läuft in den Speicherbereich des Puffers rein. Oder irgendein Puffer in LWIP läuft über.
Als erstes ist zu eruieren, ob der start-Code das Array korrekt initialisiert und es danach zerstört wird, oder ob was mit dem Start-Code, Linker Skript etc. nicht stimmt.
An diesel Stelle wäre dann noch auf das Symbol File hinzuweisen falls es nicht korrekt initialisiert. Das Alignment des Data Bereichs im Flash ist auch eine Quelle für Fehler.
H. R. schrieb: > static uint16_t MyVariable_u16[256u] = {... Es gibt eine Regel, an die man sich besser halten sollte: Was man benutzen will, das soll man zuvor auch SELBST initialisieren. Punkt. Wer das mißachtet und sich in blindem Vertrauen auf irgendwelche angeblichen Selbstverständlichkeiten sowas verkneift, der ist selber schuld. Abgesehen davon frag ich mich, wozu du sowas überhaupt brauchst. Wen du ein Feld von Konstanten haben willst, wäre es besser, sie im ROM anzusiedeln - und wenn es tatsächlich Variablen sein sollen, dann sollten deine Algorithmen so aufgebaut sein, daß sie eben auch mit uninitialisierten Variablen zurechtkommen. Static heißt ja nur, daß die Variable nicht auf dem Stack liegt, sondern statisch irgendwo im RAM und deshalb beim Verlassen einer Funktion nicht flöten geht. W.S.
W.S. schrieb: >> static uint16_t MyVariable_u16[256u] = {... > > Es gibt eine Regel, an die man sich besser halten sollte: Was man > benutzen will, das soll man zuvor auch SELBST initialisieren. Punkt. Tut er doch. Nur ist aus irgendeinem Grund der Inhalt beim Start gelegentlich kaputt. Er initialisiert mit {1, 2, 3} und findet {1, 2568, 3}, wenn vor dem Start ein UDP-Paket geschickt wurde. So lese ich die Frage. Kann gut sein, dass der Netzwerkchip (oder der Bootloader) das erste Paket empfängt und an eine undefinierte Stelle im RAM schreibt, während der Startup-Code noch fleißig .data vom Flash ins RAM kopiert oder .bss nullt... dazu fehlt mir aber zu viel Kontext.
W.S. schrieb: > Es gibt eine Regel, an die man sich besser halten sollte: Was man > benutzen will, das soll man zuvor auch SELBST initialisieren. Punkt. Es gibt eine Regel, an die man sich besser halten sollte: wenn sich ein Compiler mit seinem Laufzeitssystem nicht an den Sprachstandard hält, sollte man entweder das Problem verstehen und beheben (wie hier versucht), oder der Compiler nebst Zubehör gehört in die Tonne. Punkt. Oliver
:
Bearbeitet durch User
W.S. schrieb: > Es gibt eine Regel, an die man sich besser halten sollte: Was man > benutzen will, das soll man zuvor auch SELBST initialisieren. Punkt. Wenn Du eine globale oder static-Variable bei der Deklaration explizit mit null initialisiert, führt das auch nur dazu, daß sie ins BSS gelinkt wird. Das ist dasselbe, als wenn man sie nur deklarieren würde. Wenn der Startupcode das BSS nicht nullt, geht beides schief. Und wenn Du jetzt Gürtel UND Hosenträger anziehst und gleich in der main Deine globalen Variablen nochmal initialisierst, dann weiß der Compiler, daß er das rauswerfen kann, denn laut C-Standard sind sie ja schon mit null initialisiert. Deine Regel ist somit völlig wertlos.
H. R. schrieb: > ""nicht immer"" richtig initialisiter wird. Die meisten Elemente vom > array haben den richtigen wert, einige nicht. Hat jnd eine Idee? > Das problem taucht auf wenn ich UDP packete schon vorm Einschalten zum > STM32 schicke. Und selbst dann taucht es nicht immer auf! Klingt nach Hardware. Kenne mich mit STM wenig aus aber vielleicht überschreibt eine Variable im UDP Interrupt den Bereich oder die Queue (Buffer) wird falsch ausgelesen. Kannst du den ganzen eingelesenen Kram nicht verbieten und löschen?
Nop schrieb: > Wenn Du eine globale oder static-Variable bei der Deklaration explizit > mit null initialisiert, führt das auch nur dazu... Du hast es nicht gerafft, mein Lieber. Wer also immer nur sowas hinschreibt static int A = 4711; der verläßt sich auf eben die von mir angesprochenen Automatismen - und so etwas ist blauäugig. Ich halte es ganz anders, indem ich tatsächlich das, was es zu initialisieren gilt, dediziert auch initialisiere. Das geht eben NICHT so wie im obigen Beispiel, sondern sinngemäß so: int A; void InitMeinDing(void) { A = 4711; etc.. etc.. } womit eines sichergestellt ist, daß nämlich genau das, was tatsächlich zu initialisieren ist, auch wirklich initialisiert wird - auch dann, wenn man eben nicht aus dem µC-Reset herausgekommen ist, sondern z.B. nach einem Fault o.ä. eine Teil-Initialisierung vornehmen muß. Abgesehen davon finde ich die Manie gar vieler C-Leute, möglichst alles von der Typdefinition über die Variablendeklaration bis zur Vorbelegung in eine Zeile schreiben zu wollen, zum Kotzen. Sowas ist ganz übler Stil und auch hier gilt es, daß man in C sowas durchaus hinschreiben kann, aber ob man diese Möglichkeit auch ausnutzt oder sich sowas verkneift, ist ne Stilfrage. So. Ähem.. Damen mal bitte wegschauen: Also, es ist durchaus nicht verboten, auf den Eßtisch zu scheissen, aber jeder gesittete Mensch tut sowas einfach nicht. Was da manche durchaus prominenten Leute wie z.B. Chan mit seinem FF anstellen, indem sie sich auf das verlassen, was du offenbar als selbstverständlich ansiehst, hab ich zur Genüge durch. Danke, sowas nicht mit mir. Ich bevorzuge es, möglichst zuverlässigen Code zu schreiben. W.S.
W.S. schrieb: > Wer also immer nur sowas hinschreibt > static int A = 4711; > der verläßt sich auf eben die von mir angesprochenen Automatismen - und > so etwas ist blauäugig. Na ja. Kann man machen, muß man aber nicht. Sich für den Startup-Code genauso wie für jeden anderen Bestandteil des Programms verantwortlich zu fühlen und dafür zu sorgen, dass der so funktioniert, dass man sich darauf verlassen kann, reicht auch. Schließlich ist der genau dazu da. Nur leider scheinen sich viele erst dann dafür zu interessieren, wenn was nicht so tut, wie's soll. Im Übrigen scheint mir hier noch längst nicht geklärt, ob's daran überhaupt liegt oder bloss an irgendeinem schludrigen Überschreiber. Da hilft dein Gürtel und Hosenträger nämlich auch nix.
W.S. schrieb: > Ich halte es ganz anders ... Man kann sich auch die Hose mit der Kneifzange anziehen, nen Knopf an die Backe nähen, nen Pudding ans Knie nageln usw.. Du solltest es nur nicht anderen aufoktroyieren.
W.S. schrieb: > Nop schrieb: >> Wenn Du eine globale oder static-Variable bei der Deklaration explizit >> mit null initialisiert, führt das auch nur dazu... > > Du hast es nicht gerafft, mein Lieber. Lies genauer, was ich schrieb. Ich bezog mich auf die Nullinitialisierung (die der häufigste Fall ist), Du bringst als Beispiel eine mit 4711. Finde den Fehler. > Ich halte es ganz anders, indem ich tatsächlich das, was es zu > initialisieren gilt, dediziert auch initialisiere. Und wie initialisierst Du funktionslokale static-Variablen? Oder verwendest Du sowas nicht? > Ich bevorzuge es, möglichst zuverlässigen Code zu schreiben. Tja, und ich bevorzuge es, meine Umgebung im Startupcode korrekt so aufzusetzen, daß sie vor der main Bedingungen herstellt, die dem C-Standard entsprechen. Das ist noch zuverlässiger, weil es sicherstellt, daß auch künftige Compilerversionen keine Startup-Inits rausoptimieren, die sie gemäß C-Standard und as-if-Regel durchaus wegoptimieren dürfen.
Hi Danke für die vielen Inputs. Die Lösung: Mein Firmware geht beim powerup erst durch den bootloader. Beim austritt von bootloader, hat der bootloader den LWIP und ethernet und co nicht ausgeschaltet. So konnte es passieren dass im Bootloader ein DMA mit cstartup routine in die quere kam . Wtf
W.S. schrieb: > womit eines sichergestellt ist, daß nämlich genau das, was tatsächlich > zu initialisieren ist, auch wirklich initialisiert wird - auch dann, > wenn man eben nicht aus dem µC-Reset herausgekommen ist, sondern z.B. > nach einem Fault o.ä. eine Teil-Initialisierung vornehmen muß. Auf einem System, das sich nicht nach bekannten Spezifikationen verhält, sondern irgendwie irgendwas macht, kannst du dich auf gar nichts verlassen. Da ist es am Ende reiner Zufall, wenn etwas anscheinend funktioniert. Ansonsten ist eine init-Funktion, die alles wichtige initialisiert, natürlich das Mittel der Wahl, wenn man das braucht. Oliver
Nop schrieb: > Tja, und ich bevorzuge es, meine Umgebung im Startupcode korrekt so > aufzusetzen, daß sie vor der main Bedingungen herstellt, die dem > C-Standard entsprechen. Jaja, genau DAS hat Chan auch mehrfach betont - und im Ergebnis klatscht sein Code gelegentlich nach Wechsel der SD-Karte auf, eben weil er felsenfest davon ausgeht, daß ja ein Zeiger auf seine Datenstrukturen valid sein muß, wenn er nicht null ist. Ich schrieb ja schon, daß all die Leute, die sich auf sowas verlassen - mit der Begründung, daß ja der C-Standard dies und jenes sagt - viel zu blauäugig sind. Was nützt es dir denn, daß du im Kaltstart deinen RAM ausnullst, wenn du dich (so wie Chan) drauf verläßt, ohne wirklich alle (ALLE!) Rand-Bedingungen berücksichtigt zu haben? Aber wer kann das schon? Niemand natürlich. Genau deshalb ist es die einzig sichere Seite, grundsätzlich anzunehmen, daß jede Variable erstmal unbestimmten inhalt hat, solange man nicht wenigstens ein mal in der zugehörigen Initialisierung ihr einen Wert zugewiesen hat. Nebenbei gesagt, gilt sowas auch für Hardware-Defaults, gelle? Nochwas: angesichts der Worte des TO "Die meisten Elemente vom array haben den richtigen wert, einige nicht" ist meine Vermutung, daß es irgendwo anders einen nicht oder erstmal falsch initialisierten Zeiger gibt, der gelegentlich (je nach Interrupt-Geschehen) dafür sorgt, daß mitten in besagtem Array nach dessen Vorbelegung im Startup etwas geschrieben wird. Und das macht dann das Problem aus. W.S.
Oliver S. schrieb: > Auf einem System, das sich nicht nach bekannten Spezifikationen verhält, > sondern irgendwie irgendwas macht, kannst du dich auf gar nichts > verlassen. Nee, auch auf einem System, das sich brav an alle Konventionen hält, kann man sich auf manches nicht verlassen. Der Grund dafür ist ganz generell, daß sich die Welt eben nicht an Spezifikationen hält. Bei einem C-Programm auf dem PC kann man sich schon drauf verlassen, daß man den benutzten RAM ausgenullt vorfindet - eben weil da ja nix dazwischenkommen kann. Auf einem µC gilt das hingegen nicht mehr. Dort hat man es immer mit der Möglichkeit zu tun, daß Dinge auftreten, die man in keiner Spezifikation vorsehen kann, wie z.B. Busfaults, Störungen aller Art, Unterschiede im Default-Zustand je nach Art des Reset's (HW, SW, Brownout, und was es sonst noch so geben mag) und so weiter. Das deckt dir KEIN C-Standard ab - und manchmal nicht einmal das RefMan des µC - oder berücksichtigst du gewissenhaft wirklich alle Errata-Notes, die es zur verwendeten Revision deiner HW gibt? W.S.
W.S. schrieb: > Jaja, genau DAS hat Chan auch mehrfach betont - und im Ergebnis > klatscht sein Code gelegentlich nach Wechsel der SD-Karte auf Was mal so überhaupt nichts mit startup-Init zu tun hat, sondern damit, eine notwendige Änderung im Betrieb auch durchzuführen. > Genau deshalb ist es die einzig sichere Seite, > grundsätzlich anzunehmen, daß jede Variable erstmal unbestimmten inhalt > hat, solange man nicht wenigstens ein mal in der zugehörigen > Initialisierung ihr einen Wert zugewiesen hat. Ich sage es gerne nochmal, wieso das in der Form Unsinn ist. Weil der C-Compiler annehmen darf, daß globale Variablen, welche genullt initialisiert sein sollen, beim Betreten der main bereits genullt sind. Eine explizite Nullung darf er daher einfach wegoptimieren, und wenn nicht jetzt, dann nach dem nächsten Compiler-Update. Das folgt so aus dem C-Standard. Wer meint, eine nicht-standardkonforme Umgebung mit eigenen Hackarounds kompensieren zu können, der irrt schlichtweg, und das auch noch als die ultimativ sichere Lösung anzupreisen, ist erheiternd.
W.S. schrieb: > Der Grund dafür ist ganz generell, daß sich die Welt eben nicht an > Spezifikationen hält. Damit wären Spezifikationen aber grundsätzlich nutzlos und die Realität sagt, dass dem nicht so ist. Ich fürchte, dass du lieber so defensiv programmierst, weil du nicht willens bist, deine Umgebung korrekt herzustellen. Oder, im besseren Fall, es dir nicht erlaubt ist.
S. R. schrieb: > Oder, im besseren Fall, es dir nicht erlaubt ist. Das ist, wenn man hier von embedded redet, doch ohnehin komisch, weil man seinen Startupcode doch entweder selber schreibt oder zumindest mal überprüft, was zwischen dem Einsprung in den Resetvektor und dem Aufruf der main() alles vor sich geht. Da hat man doch im Unterschied zum PC sowieso die volle Kontrolle.
Nicht, wenn ein Bootloader vorgeschrieben ist, der mit heißer Nadel aus zwei Stückchen Scheiße und ein paar Hühnerbeinen von einem Praktikanten am Wochenende zusammengefrickelt wurde... Der OP hatte ja genau so ein Problem.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.