Abend! Wie ist das auf dem Bild gezeigte möglich? Steh ich aufm Schlauch? Wie kann 0x36 AND 0x1FFF = 0x30AD0801 ergeben? Grüße Reggie
Das sieht man auf dem Bild nicht, aber ich steh auf dem Breakpoint.
Also erstmal geht es dabei nicht um C, sondern um C++, wie man an Zeile 05 sieht. Zweitens wäre es möglich, daß DMATxDescToSet in den Wald zeigt. Vielleicht kein Speicher dafür alloziert, oder use after free. Oder kein Heap definiert (falls man für C++ an der Stelle mit dynamischem Speichermanagement arbeitet, was man nicht tun sollte). Oder der Stack ist in den Heap reingelaufen, bzw. in die globalen Variablen. Drittens, DMA geht nicht im CCM. Nicht daß der Zeiger da aufs CCM zeigt. Viertens, wenn es dabei um DMA geht, eventuell verändert die DMA-Routine ja den Wert hinterrücks und irrtümlich?
Step doch mal über die Zeile drüber. Debugger führen erfahrungsgemäß die Instruktion, die am Breakpoint steht, beim Anhalten nicht aus. Grüße Oliver
Oliver J. schrieb: > Step doch mal über die Zeile drüber. Debugger führen erfahrungsgemäß die > Instruktion, die am Breakpoint steht, nicht aus. Wenn er da am Breakpoint steht, ist die if-Anweisung schon durchgeführt. Der Wert steht definitiv. Nop schrieb: > Also erstmal geht es dabei nicht um C, sondern um C++, wie man an Zeile > 05 sieht. gnagnagna Nop schrieb: > Zweitens wäre es möglich, daß DMATxDescToSet in den Wald zeigt. Definitiv nicht, das Verhalten zeigt sich erst nach einiger Zeit. Bisschen komplex zu erklären, da is noch anderes Zeug im Spiel, welches allerdings mit dem Pointer nix zu tun hat. Das geschieht übrigens in einer ISR mit höchster Prio. Das was ist, kann eigentlich nicht sein. Nop schrieb: > Vielleicht kein Speicher dafür alloziert, oder use after free. Oder kein > Heap definiert (falls man für C++ an der Stelle mit dynamischem > Speichermanagement arbeitet, was man nicht tun sollte). In meinem Code ist kein Furz dynamisch, wenn ich das so mal ausdrücken darf. Auf den Glaubenskrieg lasse ich mich aber nicht ein. Nop schrieb: > Oder der Stack > ist in den Heap reingelaufen, bzw. in die globalen Variablen. Genau an sowas habe ich irgendwie gedacht, aber wie gesagt, mein Code is sowas von statisch :> Nop schrieb: > Drittens, DMA geht nicht im CCM. Nicht daß der Zeiger da aufs CCM zeigt. Kein CCM. Nop schrieb: > Viertens, wenn es dabei um DMA geht, eventuell verändert die DMA-Routine > ja den Wert hinterrücks und irrtümlich? Ja, der Ethernet-DMA, der läuft so ziemlich automatisch über die Descriptors gesteuert. Daran habe ich noch nicht gedacht. Schau ich mir gleich mal an ob ich hier Bockmist gebaut habe.
Reginald L. schrieb: > gnagnagna Naja C++ ist doch schon anders als C. > Definitiv nicht, das Verhalten zeigt sich erst nach einiger Zeit. Auch dann kann der Zeiger in den Wald zeigen. Beispielsweise, weil er unerwartet von irgendwoher überschrieben wurde. Ich hatte mal einen interessanten Fall, wo ein Buffer Overrun die nachfolgende Variable überschrieben hatte, jedenfalls manchmal. Bei seltenen Eingabedaten. Der Absturz kam dann erst bei Verwendung dieser nachfolgenden Variable, welche ein Zeiger war und somit sonstwohin zeigte. Häufigkeit, so etwa in 5% der Programmläufe. > In meinem Code ist kein Furz dynamisch, wenn ich das so mal ausdrücken > darf. Auf den Glaubenskrieg lasse ich mich aber nicht ein. Ich wollte darauf hinaus, daß in C++ Dinge manchmal implizit dynamisch passieren können. Ich gehe dann mal davon aus, Du kennst C++ genug, um dynamisches implizites Verhalten zu vermeiden. (: > Genau an sowas habe ich irgendwie gedacht, aber wie gesagt, mein Code is > sowas von statisch :> Stack Overflow kann auch in statischem Code passieren. Dann hast Du keinen Heap, der übergemarmelt wird, sondern dann sind gleich die globalen Variablen dran. Jedenfalls, wenn Du den Stack ganz nach oben ins RAM gelinkt hast. Ich linke ihn deswegen nach unten, damit ich nen sauberen hard fault kriege, wenn ich einen Stack Overflow habe.
Nop schrieb: > Auch dann kann der Zeiger in den Wald zeigen. Beispielsweise, weil er > unerwartet von irgendwoher überschrieben wurde. Ich hatte mal einen > interessanten Fall, wo ein Buffer Overrun die nachfolgende Variable > überschrieben hatte, jedenfalls manchmal. Bei seltenen Eingabedaten. Der > Absturz kam dann erst bei Verwendung dieser nachfolgenden Variable, > welche ein Zeiger war und somit sonstwohin zeigte. Häufigkeit, so etwa > in 5% der Programmläufe. Das geht wohl genau in die selbe Richtung. Ich logge mich ins Device ein, es tut was es soll. Dann lasse ich einen bestimmten Buffer mit ein paar bytes über SPI füllen. Es tut immer noch alles. Sobald ich mich ins Device aber wieder relogge tritt das o.g. Problem auf. Nop schrieb: > Ich wollte darauf hinaus, daß in C++ Dinge manchmal implizit dynamisch > passieren können. Ich gehe dann mal davon aus, Du kennst C++ genug, um > dynamisches implizites Verhalten zu vermeiden. (: Das hoffe ich :) Nop schrieb: > Stack Overflow kann auch in statischem Code passieren. Dann hast Du > keinen Heap, der übergemarmelt wird, sondern dann sind gleich die > globalen Variablen dran. Jedenfalls, wenn Du den Stack ganz nach oben > ins RAM gelinkt hast. Ich linke ihn deswegen nach unten, damit ich nen > sauberen hard fault kriege, wenn ich einen Stack Overflow habe. Kann aber doch eigentlich nur passieren, wenn man doof pointed oder?
Ich glaub ich habs. Ich Vollhonk, habe mal wieder was übersehen. Dummheit muss einfach bestraft werden. Mein ehem. Meister hat immer gesagt: Das ist keine Strafe, das ist Übung :)
Reginald L. schrieb: > Ich glaub ich habs. Ich Vollhonk, habe mal wieder was übersehen. > Dummheit muss einfach bestraft werden. Läßt du uns an deinen Erkenntnissen teilhaben? Was war's?
Reginald L. schrieb: > Kann aber doch eigentlich nur passieren, wenn man doof pointed oder? Nee, das passiert, wenn man den Stack zu klein macht. Dessen Größe muß man ja explizit irgendwo reservieren. Zuviele Aufruf-Verschachtelungen mit jeweils zuviel lokalen Variablen, und es rumst. Besonders, wenn man bei der Stackberechnung die Library-Funktionen oder die Interrupts vergißt. Oder wenn man Rekursion verwendet und bei den Abbruchbedingungen keine korrekte Maximaltiefe vorgesehen hat. Aber woran lag es nun? Der Gärtner war's, richtig?
Naja, ich verliere so langsam den Überblick: Habe eine Software am PC mit C# programmiert die mit einem STM32F429 kommuniziert. An dem hängt ein Frequenzumrichter und ein STM32F407. Das ist inzwischen eine Unmenge an Code. Vor kurzem habe ich alle Codes überarbeitet um die Übersichtlichkeit zu verbessern. Hier habe ich wahrscheinlich einen Fehler an der PC-Software gemacht: Die Kommunikation des FU läuft über RS232, welches auf dem STM32F429 auf Ethernet umgesetzt wird. Diese Frames schleichen sich wohl zwischen die Frames des STM32F429 und machen die Descriptors "kaputt". Heute schau ich mir das nicht mehr genauer an, aber mein alter Versionsstand funktioniert ja, weshalb das jetzt das naheliegenste wäre. Ich hoffe es zumindest. EDIT: Wenn ich mir das so durchlese, sollte ich nicht nur die Übersichtlichkeit, sondern auch so manche Programmiertaktiken verändern. Ist eigentlich Schwachsinn, dass durch fehlerhafte PC-Software der µC in einen Hardfault laufen kann.
Reginald L. schrieb: > EDIT: Wenn ich mir das so durchlese, sollte ich nicht nur die > Übersichtlichkeit, sondern auch so manche Programmiertaktiken verändern. Jepp.. ein übliches Paradigma dabei ist "die Welt ist schlecht". Alles, was von draußen reinkommt, kann und wird böswillig sein. Dein kleiner Controller muß dann mit einer Welt klarkommen, die seine pure Existenz schon mißbilligt. Designreviews sind an der Stelle eine Methode, wo man sich das System anschaut mit der Fragestellung "was muß ich tun, damit der Ansatz auf die Nase fällt?". Und dann iterativ das Design verbessern, bis die Antwort lautet "außer einem großen Hammer gibt es da nichts". Während die von außen mit allen möglichen gemeinen Tricks dem Controller übel mitspielen, muß er sich trotzdem bei seinen Ausgaben genauestens an die Regeln halten. Systeme, die so entwickelt wurden, werden im industriellen Einsatz gerne auch deutlich teurer bezahlt als Schönwettersoftware, weil jeder Ausfall da richtig Geld kostet. Sprich, das ist ein Weg, wie man gutes Geld verdienen kann. Aber hey, Du bist nicht der Erstem bei dem Refactoring zum Refucktoring wird. (;
Nop schrieb: > Dein kleiner > Controller muß dann mit einer Welt klarkommen, die seine pure Existenz > schon mißbilligt. Sehr schön forumliert :)
Nop schrieb: > Aber hey, Du bist nicht der Erstem bei dem Refactoring zum Refucktoring > wird. (; Das is aber auch ein nettes Wortspiel:) Naja, ich mach mich jetz mal ran.
Vielleicht hat noch jemand eine Denkhilfe für mich: Die Ethernetframes werden vom PC angestoßen. Der Controller läuft nach dem Empfang der Frames in eine Ethernet-Rx-ISR, in der ebendiese dekodiert werden. Nun gibt es zwei Möglichkeiten. Die Frame ist für den Controller bestimmt: In gleicher ISR erstellt der Controller eine Antwort und startet die DMA-Übertragung. ISR schließt. Die Frame ist für den Frequenzumrichter: In gleicher ISR werden die benötigten Bytes aus dem Frame in einen neuen Buffer kopiert und der UART gestartet (kein UART DMA, lediglich UART-TxEmpty-ISR). ISR Ende. Nun ist es so, dass der PC eine Antwort vom Frequenzumrichter erwartet. Aufgrund der langen Antwortverzugszeit und RS-232 mit ~56kbit/s wäre es natürlich Schwachsinn, in der Ethernet-Rx-ISR auf die Antwort zu warten. Bisher habe ich das so gelöst: UART empfängt erst die komplette Nachricht des FUs über eine UART-RxNotEmpty-ISR. Sobald das letzte Byte angekommen ist, erstellt die gleiche ISR den kompletten Header für die Ethernet-Übertragung, kopiert die empfangenen Bytes vom FU in einen neuen Buffer und startet die Ethernet-DMA-Übertragung. Eigentlich wartet der PC nach jeder neu abgesendeten Nachricht auf eine Antwort bevor er eine neue versendet. Deshalb wundert es mich etwas, dass hier ein Fehler auftritt, zumal es in der alten Version ohne Probleme funktioniert hat. Hättet ihr einen Tipp, wie ich das Problem prinzipiell lösen könnte? Ich hätte an einen flag gedacht, den ich setze, aber dann muss man sicherstellen, dass das Frame zu einem späteren Zeitpunkt noch versendet werden muss. Vielleicht habt ihr eine ganz andere Lösung? Danke schonmal Grüße Reggie
Vielleicht so zum Verständnis, wie es bisher läuft:
1 | void ETH_RX_ISR() |
2 | {
|
3 | if (FrameForController) |
4 | {
|
5 | CreateEthTx(); |
6 | StartEthTxDMA(); |
7 | }
|
8 | else
|
9 | SendToConverter(); |
10 | }
|
11 | |
12 | void UART_RX_ISR() |
13 | {
|
14 | ...
|
15 | ...
|
16 | if (LastByte) |
17 | {
|
18 | CreateEthTx(); |
19 | StartEthTxDMA(); |
20 | }
|
21 | }
|
In der StartEthTxDMA() wird der aktuelle Descriptor bearbeitet und dann auf den nächsten Descriptor gezeigt. Ich versteh zwar nicht wirklich, warum sich das anfangs erwähnte Verhalten zeigt, aber um das Problem mal anzugehen, möchte ich eben erst mal diesen Fehler ausschließen.
Mir fällt da als erstes auf daß Du relativ viel in den ISRs machst. Ich versuche das immer so weit wie möglich zu vermeiden. In meinen ISRs setzte ich meist entweder nur ein Flag oder sichere Daten und setze dann ein Flag. Der Rest wird im normalen Hauptprogramm gemacht. Grund ist daß Du alle Variablen und Ressourcen, die Du in einer ISR verwendest, besonders schützen musst bevor Du sie in einem anderen Programmteil verwendest. Desto aufwendiger die ISR, desto schwieriger wird es und desto leichter übersieht man da etwas. Natürlich gibt es Außnahmen davon, z.B. wenn es aus Timinig-Gründen nicht anders geht. Aber STM32F429 und Serielle Kommunikation klingt jetzt nicht so, als ob Du da bereits am Takte zählen bist. Dein "CreateEthTx(); StartEthTxDMA();" in der ISR sehen mir da gefährlich aus. Was passiert, wenn ein anderer Programmteil auch ein Ethernet-Paket senden möchte? Der zweiter Punkt der mir auffällt, ist daß der Programmfluss relativ stark von den ISRs gesteuert werden zu scheint. Also von außen. Dort, wo lt. Nop schon die Existenz Deines µC mißbilligt wird: Was passiert, wenn einfach so, unvermittelt, vom FU Daten kommen die Deine "LastByte"-Bedingung erfüllen? Was passiert, wenn vom PC zwei Frames mit Daten für den FU kurz hintereinander kommen, ohne daß der FU Zeit hatte zu antworten? Was passiert, wenn der FU nicht innerhalb realistischer Zeit antwortet? etc. Ich baue für sowas gerne eine Statemachine. Also die Daten werden in den ISRs gesichert und ein Flag gesetzt. Das Hauptprogramm bemerkt das Flag und bearbeitet diese Eingabe dann nach den Regeln der Statemachine. Also ist dieses Flag an der Stelle gültig, in welchen State wechsle ich jetzt und was wird dann gemacht etc. Zwischen den States gibt es dann an vielen Stellen Timeouts. Wenn eine Antwort nicht nach soundsoviel Sekunden kam, dann protokolliere einen Timeout-Fehler und gehe in einen Failsafe-Status, Resette die Anlage etc. Wenn Du den Programmfluss vom Hauptprogramm aus steuerst und nicht aus ISRs raus, hast Du es auch viel leichter den Watchdog des µC zu verwenden. Denn Du kannst den bei jedem vollständigem Durchlauf der Hauptschleife (und meinetwegen noch ein paar zusätzlichen Checks) resetten. Ein weiterer Vorteil der Statemachine ist das Debugging. Du kannst Dir meist im normalen Programmlauf, ohne Debugger, die Statewechsel auf einem Terminal protokollieren lassen. Wenn ein Bug sehr selten oder nur ohne Debugger auftritt, hast Du dann zumindest schon mal einen guten Indikator was da passiert ist.
Gerd E. schrieb: > Mir fällt da als erstes auf daß Du relativ viel in den ISRs machst. Ja, darauf habe ich damals meinen Code ausgelegt. Ich habe gedacht, dass ich so möglichst definierte Timings und Zustände des Programms erreiche. Die MainLoop ist bei mir eigentlich leer, darin hängen nur GUI-Aktualisierungen für einen TFT. Wenn ich dich richtig verstehe, ist dieses Vorgehen unüblich? Gerd E. schrieb: > Grund ist daß Du alle Variablen und Ressourcen, die Du in einer ISR > verwendest, besonders schützen musst bevor Du sie in einem anderen > Programmteil verwendest. Was meinst du mit schützen? Ich setze jede Variable in den ISRs auf volatile. Andererseits habe ich keine Compileroptimierungen aktiviert. Noch nicht. Gerd E. schrieb: > Natürlich gibt es Außnahmen davon, z.B. wenn es aus Timinig-Gründen > nicht anders geht. Aber STM32F429 und Serielle Kommunikation klingt > jetzt nicht so, als ob Du da bereits am Takte zählen bist. Dazu zählt beispielsweise die SPI Kommunikation zwischen den beiden Controllern. Bei dem Rest hast du sicherlich absolut recht. Ein Grund bspws. für die Ethernet-ISR war für mich, dass die Frames möglichst schnell losgeschickt werden. Selbstverständlich habe ich auf eine korrekte Prioritätenvergabe der Interrupts geachtet. Da hat man beim F4 echt gute Möglichkeiten. Gerd E. schrieb: > Dein "CreateEthTx(); StartEthTxDMA();" in der ISR sehen mir da > gefährlich aus. Was passiert, wenn ein anderer Programmteil auch ein > Ethernet-Paket senden möchte? Das dürfte eigentlich nicht vorkommen. Der FU antwortet nur einmalig. Wenn er nicht antwortet wird auch kein Ethernet-Frame versendet. Das wird alles am PC gesteuert, weshalb ich jetzt wohl die Probleme her habe. Gerd E. schrieb: > Was passiert, wenn einfach so, unvermittelt, vom FU Daten kommen die > Deine "LastByte"-Bedingung erfüllen? Das kann, wie gesagt, nicht passieren. Sowas macht der FU nicht. Die LastByte()-Bedingung kann nur vorkommen, wenn der UART Daten empfängt. Gerd E. schrieb: > Was passiert, wenn vom PC zwei Frames mit Daten für den FU kurz > hintereinander kommen, ohne daß der FU Zeit hatte zu antworten? Kann eigentlich auch nicht passieren, Die PC-Software ist so geschrieben, dass das unmöglich ist / sein sollte. Gerd E. schrieb: > Was passiert, wenn der FU nicht innerhalb realistischer Zeit antwortet? Der Controller kriegt das nicht mit. Die PC-Software hat dafür einen Timeout und resendet die EthernetFrame. Das passiert auch relativ oft, das ist bei dem FU auch normal. Ist alles auch gegengeprüft, den FU kenne ich inzwischen wie meine Westentasche :) Gerd E. schrieb: > Ich baue für sowas gerne eine Statemachine. Also die Daten werden in den > ISRs gesichert und ein Flag gesetzt. Das werde ich jetzt wohl auch machen, mein Vorgehen mit den ISRs scheint also wohl total fehl am Platz gewesen zu sein?
Also grundsätzlich wird da für meinen Geschmack zuviel in Interrupts gemacht, was eigentlich in die Applikation gehören würde. Vor allem wird der DMA-Transfer aus zwei verschiedenen ISRs angestoßen, ohne daß eine Zentralstelle verwalten würde, ob der DMA-Transfer schon zuende ist. Spurious Interrupts wären da auch noch anzudenken. Bei DMA fiel mir noch dieser Beitrag hier auf, wo es zwar um den ADC ging, aber evtl. ist das mit LISR und LISH hier ja auch relevant: Beitrag "STM32, triple mode Interleaved mode, periodisch falsch" Wenn Du kein RTOS verwendest, sondern das "bare metal" gehen soll, wäre es ein Weg, in der main die Endlosschleife zu nehmen und periodisch das RX/TX zu koordinieren. Sofern dann auch noch eine "eigentliche" Applikation läuft, was ja auch der Grund sein könnte, wieso soviel in den ISRs gemacht wird, wird es ohne RTOS natürlich hakelig. Aber nicht unmöglich; man kann auch in der Mainloop die einzelnen Taskfunktionen durchtickern lassen, die dann eben nicht blockieren dürfen. Das bekommt man entweder mit expliziten Zustandsautomaten in den Funktionen hin, oder man nimmt computed gotos, was besonders für Wartefunktionen sehr bequem geht. Das würde übrigens auch die Aufteilung der Prios für DMA und Ethernet/UART ISR vereinfachen. Ach ja, und der PC kann auch durchaus ungewollt Ethernet-Frames senden, die mit der Applikation nichts zu tun haben. Speziell Windows ist berüchtigt dafür, auf allen Ethernet-Interfaces periodisch irgendwelche ARP-Pakete rauszublasen, um zu gucken, wer da so alles ist. Du mußt also jederzeit damit rechnen, daß dort Pakete ankommen, die Du eh wieder verwerfen mußt.
Nop schrieb: > Vor allem wird der DMA-Transfer aus zwei verschiedenen ISRs angestoßen, > ohne daß eine Zentralstelle verwalten würde, ob der DMA-Transfer schon > zuende ist. Das macht eigentlich nichts, da in Wirklichkeit dort nur die descriptors beschrieben werden. Der DMA schnappt sich die Daten dann selbstständig. Es geht hier um den Ethernet MacDMA der mit dem STM DMA nichts zu tun hat. Nop schrieb: > Ach ja, und der PC kann auch durchaus ungewollt Ethernet-Frames senden, > die mit der Applikation nichts zu tun haben. Speziell Windows ist > berüchtigt dafür, auf allen Ethernet-Interfaces periodisch irgendwelche > ARP-Pakete rauszublasen, um zu gucken, wer da so alles ist. Du mußt also > jederzeit damit rechnen, daß dort Pakete ankommen, die Du eh wieder > verwerfen mußt. Ist alles bedacht, implementiert und mit wireshark überprüft. Hat ja bisher auch funktioniert. Aber ich versuche jetzt mal den Anlauf mit der Mainloop. Wie gesagt, ich dachte mit den ISRs wird das ganze einen absolut definierten Zustand einnehmen. War wohl zu kurz gedacht.
Reginald L. schrieb im Beitrag #4674445 > Die MainLoop ist bei mir eigentlich leer, darin hängen nur > GUI-Aktualisierungen für einen TFT. > Wenn ich dich richtig verstehe, ist dieses Vorgehen unüblich? Man kann das schon so machen, aber Du holst Dir halt einige Risiken in Dein Design rein. > Gerd E. schrieb: >> Grund ist daß Du alle Variablen und Ressourcen, die Du in einer ISR >> verwendest, besonders schützen musst bevor Du sie in einem anderen >> Programmteil verwendest. > Was meinst du mit schützen? Ich setze jede Variable in den ISRs auf > volatile. Das ist das eine, reicht aber nicht. Stell Dir z.B. folgenden Code vor
1 | volatile int a; |
2 | |
3 | if (a>10) |
4 | {
|
5 | int copy=a; |
6 | a=0; |
7 | |
8 | do_something(copy); |
9 | }
|
Zwischen dem a>10 und dem then-Block könnte die ISR a auf kleiner 10 gesetzt haben. Auch zwischen dem Kopieren und auf 0 setzten könnte die ISR gelaufen sein und noch einen Wert in a reingeschrieben haben, der dann verloren geht. Du müsstest also eigentlich für diesen Teil des Codes die ISR sperren. > Andererseits habe ich keine Compileroptimierungen aktiviert. obiges Problem hat nix mit Optimierungen zu tun. Einfach damit, daß die ISR an jeder Stelle im Code "zuschlagen" kann. > Gerd E. schrieb: >> Dein "CreateEthTx(); StartEthTxDMA();" in der ISR sehen mir da >> gefährlich aus. Was passiert, wenn ein anderer Programmteil auch ein >> Ethernet-Paket senden möchte? > Das dürfte eigentlich nicht vorkommen. Der FU antwortet nur einmalig. Der FU vielleicht. Aber wenn eine Störung auf das Kabel einkoppelt? Oder jemand am Stecker wackelt? > Gerd E. schrieb: >> Was passiert, wenn einfach so, unvermittelt, vom FU Daten kommen die >> Deine "LastByte"-Bedingung erfüllen? > Das kann, wie gesagt, nicht passieren. Sowas macht der FU nicht. Die > LastByte()-Bedingung kann nur vorkommen, wenn der UART Daten empfängt. siehe oben. > Gerd E. schrieb: >> Was passiert, wenn vom PC zwei Frames mit Daten für den FU kurz >> hintereinander kommen, ohne daß der FU Zeit hatte zu antworten? > Kann eigentlich auch nicht passieren, Die PC-Software ist so > geschrieben, dass das unmöglich ist / sein sollte. Die Software macht das vielleicht nicht. Aber Dein OS (siehe Post von Nop). Oder Deine Software läuft aus Versehen zwei mal. Oder oder oder. > Gerd E. schrieb: >> Was passiert, wenn der FU nicht innerhalb realistischer Zeit antwortet? > Der Controller kriegt das nicht mit. Die PC-Software hat dafür einen > Timeout und resendet die EthernetFrame. Und wenn in dem Moment dann der FU doch noch antwortet?
Nop schrieb: > Wenn Du kein RTOS verwendest, sondern das "bare metal" gehen soll, wäre > es ein Weg, in der main die Endlosschleife zu nehmen und periodisch das > RX/TX zu koordinieren. Sofern dann auch noch eine "eigentliche" > Applikation läuft, was ja auch der Grund sein könnte, wieso soviel in > den ISRs gemacht wird, wird es ohne RTOS natürlich hakelig. > > Aber nicht unmöglich; man kann auch in der Mainloop die einzelnen > Taskfunktionen durchtickern lassen, die dann eben nicht blockieren > dürfen. Das bekommt man entweder mit expliziten Zustandsautomaten in den > Funktionen hin, oder man nimmt computed gotos, was besonders für > Wartefunktionen sehr bequem geht. Ja, so sehe ich das auch. Bei einfacheren Programmen kommt man mit einer Mainloop und Statemachines gut hin. Wenn es komplexer wird, wird es immer schwerer die Funktionen so zu schreiben, daß sie nicht blockieren. Irgendwann wird das unübersichtlich. Spätestens dann ist der Zeitpunkt für nen RTOS gekommen. Da hast Du dann mehrere Threads die jeder für sich blockieren können. Dafür musst Du aber an allen Stellen, an denen die Threads untereinander kommunizieren oder gemeinsame Ressourcen verwenden, aufpassen. Nen RTOS stellt dafür normal verschiedene Funktionen bereit. Aber dennoch muss man wissen was man tut, man kann bei unbedarftem Einsatz von Locking auch schnell in ein Deadlock reinlaufen. Ich nehme als RTOS gerne ChibiOS. Wenn Du Dich dafür interessierst, hier gibt es ein Tutorial dazu: http://chibios.org/dokuwiki/doku.php?id=chibios:book:start Dort wird nicht nur ChibiOS erklärt, sondern auch generell worauf man bei RTOSsen, Locking etc. achten sollte. Finde ich als Einführung gut gemacht.
Gerd E. schrieb: > Zwischen dem a>10 und dem then-Block könnte die ISR a auf kleiner 10 > gesetzt haben. Auch zwischen dem Kopieren und auf 0 setzten könnte die > ISR gelaufen sein und noch einen Wert in a reingeschrieben haben, der > dann verloren geht. > > Du müsstest also eigentlich für diesen Teil des Codes die ISR sperren. Puh, das wird ein Spaß in solchen Konstrukten im Nachhinein den Fehler zu finden. Gerd E. schrieb: > Der FU vielleicht. Aber wenn eine Störung auf das Kabel einkoppelt? Oder > jemand am Stecker wackelt? Ja klar, kann man nicht ausschließen. Aber letztendlich kann man solche Fehlerquellen nie ausschließen, egal wie man etwas programmiert. Es wird immer einen Fehler geben der dein System zum erliegen bringt. Auf jeden Fall habe ich diesen Umstand nicht betrachtet, da hier in der von dir beschriebenen Hinsicht Fehler bisher nicht aufgetreten sind. Ich werde den Code trotzdem umschreiben und versuchen möglichst viele Fehlerquellen zu beachten. Ich sehe ja was sonst rauskommt. Gerd E. schrieb: > Und wenn in dem Moment dann der FU doch noch antwortet? Dann kann ich eigentlich nur noch damit arbeiten, dass ich den UART immer wieder aktiviere und deaktiviere, je nachdem ob ich eine Antwort erwarte. Kann ich mir nicht vorstellen, dass das so gehandhabt wird? Gerd E. schrieb: > Spätestens dann ist der Zeitpunkt für nen RTOS > gekommen. Wie RealTime ist denn so ein RTOS? Ich bin mit dem STM schon ziemlich an der Grenze des Machbaren, vor kurzem habe ich mir überlegt Programmteile auf einen FPGA auszulagern. Im Prinzip schaufele ich Daten vom ADC aus einem µC zu nem Andern und dann zum PC. Nebenher läuft ein TFT, I2C, 2x SPI, UART, Ethernet, Flash, SDRam... wenn ich nichts vergessen habe. Kritisch ist da vor allem das SPI, da is das Timing schon ganz knapp an den Grenzen.
HA, jetzt weiß ich auch wieder, warum die ISRs so praktisch waren: Somit konnte die GUI in der Mainloop unterbrochen werden. Jetzt müsste ich die GUI-Funktionen so anpassen, dass diese unterbrochen werden, sobald eine wichtigere Aktion zu handlen ist.
Reginald L. schrieb: > Gerd E. schrieb: >> Du müsstest also eigentlich für diesen Teil des Codes die ISR sperren. > Puh, das wird ein Spaß in solchen Konstrukten im Nachhinein den Fehler > zu finden. Wenn Du nur eine Variable und ein Auge für diesen Fehlermechanismus hast, dann geht das noch. Aber bei längeren, verschachtelten Funktionen die Du gemischt aus der ISR und normalen Programmteilen aufrufst wird das wirklich lustig... > Gerd E. schrieb: >> Der FU vielleicht. Aber wenn eine Störung auf das Kabel einkoppelt? Oder >> jemand am Stecker wackelt? > Ja klar, kann man nicht ausschließen. Aber letztendlich kann man solche > Fehlerquellen nie ausschließen, egal wie man etwas programmiert. Es wird > immer einen Fehler geben der dein System zum erliegen bringt. Der Trick ist daß das System entweder selbst die Störung beheben kann oder aber sich definiert in einen sicheren Zustand bringt bzw. sich abschaltet. Irgendwie undefiniert "zum erliegen" zu kommen geht gar nicht. Vor allem wenn Du es mit potentiell gefährlichen Maschinen zu tun hast. > Auf jeden Fall habe ich diesen Umstand nicht betrachtet, da hier in der > von dir beschriebenen Hinsicht Fehler bisher nicht aufgetreten sind. Du solltest nicht nur im Code auf die Fehler reagieren, die Du bei Dir beobachtet hast, sondern im Vorfeld genau bedenken was für Fehler theoretisch auftreten können und für diese eine Behandlung definieren. Stell Dir mal vor Du lieferst Dein Gerät so an einen Kunden aus und der hat dann nen FU mit z.B. anderem Firmwarestand oder sowas. Oder starken Störungen aus der Umgebung die ins Kabel einstrahlen. Wenn Du dann erst mit Fehleranalyse und Umdesignen Deines Programms anfängst, ist die Inbetriebnahme gründlich daneben gegangen. > Gerd E. schrieb: >> Und wenn in dem Moment dann der FU doch noch antwortet? > Dann kann ich eigentlich nur noch damit arbeiten, dass ich den UART > immer wieder aktiviere und deaktiviere, je nachdem ob ich eine Antwort > erwarte. Kann ich mir nicht vorstellen, dass das so gehandhabt wird? Damit würdest Du versuchen den Fehler zu ignorieren. Was passiert wenn Du jetzt die richtige Antwort ignorierst und nur die falschen Daten durchlässt? Nein, Du solltest erkennen daß da ein Protokollfehler vorliegt und dann z.B. versuchen das Protokoll zu resetten und wieder in einen sauberen Zustand zu kommen. Bei einem Modem mit AT-Befehlssatz könnte man hierfür z.B. <1sec>+++<1sec>AT<CR> senden. Wenn da dann auch nach 3 Versuchen kein "OK" zurückkommt, würde ich alles abschalten und in einen sauberen Fehlerzustand gehen. Bei Deiner Maschine also z.B. den E-STOP triggern. Wichtig ist dabei daß Du ein sauber definiertes Protokoll mit defnierten Protokollebenen hast. Also sowohl FU <-> µC als auch µC <-> PC. Und dann Dir überlegst wer für welche Fehlererkennung und Behandlung zuständig ist. Da gibt es keine allgemeingültige Vorlage für, das hängt von Deiner Anwendung ab. > Gerd E. schrieb: >> Spätestens dann ist der Zeitpunkt für nen RTOS >> gekommen. > Wie RealTime ist denn so ein RTOS? siehe mein Link oben. > Ich bin mit dem STM schon ziemlich an > der Grenze des Machbaren, vor kurzem habe ich mir überlegt Programmteile > auf einen FPGA auszulagern. Im Prinzip schaufele ich Daten vom ADC aus > einem µC zu nem Andern und dann zum PC. Nebenher läuft ein TFT, I2C, 2x > SPI, UART, Ethernet, Flash, SDRam... wenn ich nichts vergessen habe. > Kritisch ist da vor allem das SPI, da is das Timing schon ganz knapp an > den Grenzen. Das klingt eher nach RTOS als nach großer Mainloop.
Gerd E. schrieb: > Du solltest nicht nur im Code auf die Fehler reagieren, die Du bei Dir > beobachtet hast, sondern im Vorfeld genau bedenken was für Fehler > theoretisch auftreten können und für diese eine Behandlung definieren. Bin absolut deiner Meinung, am PC kein Thema. Aber beim µC verlangsamt man die ganze Geschichte schon ziemlich, zumindest, wenn man zeitkritische Dinge macht. Da habe ich ein besonderes Augenmerk drauf gehabt. Witzigerweise hat der Controller in meinem speziellen Fall immer noch die softwareseitige Nothalt des FUs bewirkt. Gerd E. schrieb: > Stell Dir mal vor Du lieferst Dein Gerät so an einen Kunden aus und der > hat dann nen FU mit z.B. anderem Firmwarestand oder sowas. Oder starken > Störungen aus der Umgebung die ins Kabel einstrahlen. Wenn Du dann erst > mit Fehleranalyse und Umdesignen Deines Programms anfängst, ist die > Inbetriebnahme gründlich daneben gegangen. Ich bin Maschinenbauer und programmiere noch nicht so lange :) So hoch will ich erst mal nicht hinaus. Gerd E. schrieb: > amit würdest Du versuchen den Fehler zu ignorieren. Was passiert wenn > Du jetzt die richtige Antwort ignorierst und nur die falschen Daten > durchlässt? > > Nein, Du solltest erkennen daß da ein Protokollfehler vorliegt und dann > z.B. versuchen das Protokoll zu resetten und wieder in einen sauberen > Zustand zu kommen. Nee, in meinem Fall handle ich nach Vorgaben. Nach USS-Protokoll soll man bei nicht-Beantwortung die Anfrage solange resenden bis die Antwort kommt. Klingt komisch ist aber in besagtem Protokoll-Manual nachzulesen. Ich habe auch noch weitere Sensorik angeschlossen die Auswertbar ist. Aber darum gehts hier ja jetzt auch nicht. Ich wollte damit eigentlich nur sagen, dass auch das sicherste System offene Fehlerquellen hat. Gerd E. schrieb: > Wichtig ist dabei daß Du ein sauber definiertes Protokoll mit defnierten > Protokollebenen hast. Also sowohl FU <-> µC als auch µC <-> PC. Und dann > Dir überlegst wer für welche Fehlererkennung und Behandlung zuständig > ist. Ist eigentlich auch nicht das Thema, aber der µC ist zwischen PC und FU eigentlich nur ein Protokollwandler. Ansonsten habe ich natürlich ein eigenes Protokoll zwischen µC und PC. Gerd E. schrieb: > Das klingt eher nach RTOS als nach großer Mainloop. Durch das RTOS kriegt man doch wieder overhead in die ganze Geschichte. Aber ich sehs mir mal an. Hab schon Kopfschmerzen von der ganzen Umschreiberei, für heute is genug..
Wow. Ich lasse jetzt das komplette Ethernet nur über die Mainloop laufen und alles funktioniert so wie es soll, besser als vorher. Ich muss wohl irgend einen Bockmist gebaut haben. Vorher bekam ich sporadisch etwa einmal pro Minute keine Antwort auf eine Frame. Ich hatte die physikalische Verbindung im Verdacht, da es dazu ja so "Frame-Loss-Statistics" gibt. Jetzt ist alles wunderbar und vor allem auch weniger komplex geworden -> somit kann der Code auch schneller abgearbeitet werden. Und ich bekomme eine Antwort in wenigen hundert µs vom Controller. Top, ich danke euch für den Tipp mit der Mainloop! Ich dachte das Timing wird dann problematisch, aber das funktioniert jetzt besser als vorher :) Der C# Code am PC kommt mit dem µC gar nicht mehr mit :)
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.
