Falk B. schrieb: > Ach so, du bist es ja! > Und du auch schon wieder ! Kannst du dir nicht wenigstens Punkt 5 der universellen Forumsregeln merken ? Die fünf universellen Forumsregeln : 1. Threadüberschrift lesen 2. Evtl. Datum beachten 3. Posting verstehen 4. Falls nicht 3., dann nachfragen oder Klappe halten. 5. Auf die Fragen eingehen und / oder Alternativen bzw. Verbesserungen nennen. Die Punkte kann man an einer Hand abzählen und deshalb evtl. gut merken, wenn nicht dann nur Punkt 3 und Punkt 4 merken. Der Fehler ist natürlich nicht weg, sondern taucht bei der Konstellation nicht auf. Wenn ich OCR3A z.B. mit 694 lade ist er wieder da. Das ganze dient zum Erkennen, wann meine Schrittmotorkonstruktion anfängt Schritte zu verlieren. Es wird die FastPWM Mode 15-Kurve ohne Vorteilung mit einem CPU-Takt von 16MHz druchlaufen. Dazu lasse ich den SM einen bestimmten Kurvenbereich abfahren, dann sofort zurück und hiernach wird ca. 1,5 Sekunden gewartet bis es von neuem losgeht. Aber sporadisch läuft die Sache dann schief. Dort im leider schlechtem Video kann man es sehen : Beitrag "Schrittmotor : Programmfehler" Ich würde mich freuen, falls mal jemand oben auf Punkt 5 eingeht. Debuggen kann ich nur mit dieser Print-Krücke. Bernd_Stein
Arduino F. schrieb: > Die Print::print() werden sofort ausgeführt. > Es wird ein char/uint8_t Ringbuffer mit den Ausgaben gefüllt. > Die Probleme/Blockaden entstehen, wenn der Ringbuffer voll ist. > Seltsam, ich hatte doch 3 weitere Print-Befehle hinzugefügt, da hätte der Fehler demnach erst recht auftauchen müssen. Arduino F. schrieb: > Auch da sich Ausgaben des Hauptprogramms und Ausgaben in der ISR > vermischen können/werden. > Das Hauptproblem ist halt, dass stepCount entweder nachgeladen oder mit einem falschen Wert geladen wird. Das kann ich halt nicht festellen. Ich verstehe halt nicht wie dies sein kann. Nur bei stepCount == 0, wird ja die entscheidene Loop-Routine durchlaufen und nur wenn dann auch die Richtung stimmt, wird stepCount neu geladen. Da wird wohl irgend ein Interrupt dazwischenfunken, aber dass dürfte doch egal sein, wenn dieser IRQ nicht die selbe Varialbe ( stepCount ) nutzt oder ? Bernd_Stein
Dachte nun wenn ich IRQ`s generell unterbinde, aber seht euch den Anhang an.
1 | cli(); |
2 | stepCount = SM_SCHRITTANZAHL; // Variable wird in ISR runtergezaehlt |
3 | // Sofortigen Interrupt verhindern
|
4 | TCNT3 = 0; // Timer ruecksetzen |
5 | TIFR3 = 1<< OCF3A; // Output Compare Interrupt Flag loeschen |
6 | TIMSK3 |= 1<< OCIE3A; // Output Compare Interrupt freigeben |
7 | sei(); |
Bernd_Stein
1 | if( stepCount == 0 ) { |
2 | ...
|
3 | Serial.print ( "stepCount" ); |
4 | Serial.print ( stepCount ); |
5 | Serial.println( ); |
6 | ...
|
7 | }
|
Da muss auch eine Interruptsperre drumherum. Denn sonst kann die Variable beim Lesen verändert werden. Angenommen, StepCount hat vor dem if-Befehl gerade den Wert 256 (hex: 00 00 01 00). Nun werden die vier Bytes nacheinander von rechts nach links gelesen: Viertes Byte: 00 Jetzt kommt ein Interrupt, welcher den Wert auf 255 ändert (hex: 00 00 00 FF) Drittes Byte: 00 Zweites Byte: 00 Erstes Bytes: 00 Alle vier haben "scheinbar" den Wert 0, die if-Bedingung ist erfüllt. Dann kommt die korrekte Ausgabe der Variable. Anmerkung: Wenn die Intervalle zwischen den Interrupts kürzer wären, könnte auch die Ausgabe mittels Serial.print(steCount) gestört werden. Korrekturvorschlag:
1 | void loop() |
2 | {
|
3 | int32_t tmp; |
4 | |
5 | cli(); |
6 | tmp=stepCount; |
7 | sei(); |
8 | |
9 | if( tmp == 0 ) { |
10 | TIMSK3 &= ~1<< OCIE3A; // Output Compare Interrupt sperren |
11 | |
12 | // Nur jedes 2te mal eine Pause einlegen
|
13 | if( !( SM_RICHTUNG_PORT & SM_RICHTUNG )) { |
14 | |
15 | |
16 | Serial.print ( errorZaehler ); |
17 | Serial.print ( " PAUSE" ); |
18 | Serial.print ( "\t" ); // Neu |
19 | Serial.print ( "stepCount" ); // Neu |
20 | Serial.print ( tmp ); // Neu |
21 | Serial.println( ); |
22 | |
23 | errorZaehler ++; |
24 | |
25 | delay( SM_PAUSE ); |
26 | }
|
27 | |
28 | cli(); |
29 | stepCount = SM_SCHRITTANZAHL; // Variable wird in ISR runtergezaehlt |
30 | // Sofortigen Interrupt verhindern
|
31 | TCNT3 = 0; // Timer ruecksetzen |
32 | TIFR3 = 1<< OCF3A; // Output Compare Interrupt Flag loeschen |
33 | TIMSK3 |= 1<< OCIE3A; // Output Compare Interrupt freigeben |
34 | sei(); |
35 | }
|
36 | } // Ende void loop() |
Gewöhne dir an: 1) Variablen die sowohl innerhalb als auch außerhalb einer ISR benutzt werden, müssen volatile sein. 2) Wenn diese Variable größer als 8 Bit ist, dann muss der Zugriff durch eine Interruptsperre geschützt werden. Es gibt sehr spezielle Ausnahmen, wo das nicht nötig ist, aber das ist eher ein Thema für fortgeschrittene Programmierer.
Steve van de Grens schrieb: > 1) Variablen die sowohl innerhalb als auch außerhalb einer ISR benutzt > werden, müssen volatile sein. > > 2) Wenn diese Variable größer als 8 Bit ist, dann muss der Zugriff durch > eine Interruptsperre geschützt werden. Punkt 1 stimme ich nicht zu Punkt 2 durchaus ja. Hier würde ich zu den Atomic Block Makros raten. Die sind recht einfach zu handhaben und tun was sie sollen.
:
Bearbeitet durch User
Steve van de Grens schrieb: > 1) Variablen die sowohl innerhalb als auch außerhalb einer ISR benutzt > werden, müssen volatile sein. Zwar bekommt man mit dieser Holzhammerregel keine Probleme mit dem Optimizer, jedoch ist diese Aussage in Gänze falsch.
Arduino F. schrieb: > Punkt 1 stimme ich nicht zu Wilhelm M. schrieb: > Zwar bekommt man mit dieser Holzhammerregel keine Probleme mit dem > Optimizer, jedoch ist diese Aussage in Gänze falsch. Vielleicht einfach mal vollständig lesen und zitieren: Steve van de Grens schrieb: > Es gibt sehr spezielle Ausnahmen, wo das nicht nötig ist, aber das ist > eher ein Thema für fortgeschrittene Programmierer. Ihr könnte das ja gerne in einem weiter führenden Thread ausdiskutieren. Das letzte mal ist immerhin länger als ein Monat her. Aber seid dem Bernd bitte nicht böse, wenn er an diesem Detail (gerade) kein Interesse hat.
Steve van de Grens schrieb: > Aber seid dem > Bernd bitte nicht böse, wenn er an diesem Detail (gerade) kein Interesse > hat. Ich glaube nicht, dass es deine Entscheidung ist, was ihm schmeckt, oder auch nicht. Weiterhin: Es gibt diese schönen Makros. Also kann man sie auch verwenden. Ist nicht so dolle eigenbrötlerisch denn es nutzt einen dokumentierten und ausgetretenen Pfad. Dann brauchts auch kein volatile. Man/Bernd muss noch nicht mal verstehen, was die Makros "wirklich" tun. Disclaimer: Dieses ist ein Rat. Ein kostenloser Rat. PS: Dass ihm da schlampig vorgegangen ist, sollte ihm auch mittlerweile klar geworden sein.
:
Bearbeitet durch User
Steve van de Grens schrieb: > Angenommen, StepCount hat vor dem if-Befehl gerade den Wert 256 (hex: 00 > 00 01 00). Nun werden die vier Bytes nacheinander von rechts nach links > gelesen: > > Viertes Byte: 00 > Jetzt kommt ein Interrupt, welcher den Wert auf 255 ändert (hex: 00 00 > 00 FF) > Drittes Byte: 00 > Zweites Byte: 00 > Erstes Bytes: 00 > > Alle vier haben "scheinbar" den Wert 0, die if-Bedingung ist erfüllt. > Dann kommt die korrekte Ausgabe der Variable. > Vielen dank für diese verständliche Erklärung. Habe dies umgesetzt und es scheint die Ursache gewesen zu sein. Bisher 140 Errorzählungen ohne Fehler auch beim Verfahren des SM.
1 | int32_t tmp; |
2 | |
3 | cli(); |
4 | tmp = stepCount; // Ein verfaelschen durch ISR verhindern |
5 | sei(); |
6 | |
7 | if( tmp == 0 ) { |
Ach, in diesem Zusammenhang fällt mir ein: Ist der Zugriff in C auf 16-Bit Register bzw. Variablen schon von Haus aus geschützt oder müsste ich dies auch per Interruptsperre schützen?
1 | TCNT3 = 0; // Timer ruecksetzen |
2 | |
3 | uint16_t spanne = 0; |
Bernd_Stein
:
Bearbeitet durch User
Bernd S. schrieb: > Ist der Zugriff in C auf 16-Bit Register bzw. Variablen schon von Haus > aus geschützt Ist er nicht. Nur Variablen, die deine CPU atomar (mit einem Assembler-Befehl) laden/speichern kann, haben das "Problem" nicht. Zu TCNT3 lies mal https://ww1.microchip.com/downloads/en/Appnotes/doc1493.pdf Wo du die "spanne" jetzt her geholt hast, ist mir schleierhaft. Diskutieren wir nicht mehr über https://www.mikrocontroller.net/attachment/highlight/613919 ?
Steve van de Grens schrieb: > Bernd S. schrieb: >> Ist der Zugriff in C auf 16-Bit Register bzw. Variablen schon von Haus >> aus geschützt > > Ist er nicht. Nur Variablen, die deine CPU atomar (mit einem > Assembler-Befehl) laden/speichern kann, haben das "Problem" nicht. > Jo, habe da auch was gefunden. Ich kann zwar
1 | TCNT3 = 65535; |
schreiben, anstelle von
1 | TCNT3H = 0xFF; |
2 | TCNT3L = 0xFF; |
aber trotzdem werden zwei Schreibzugriffe erzeugt. https://www.mikrocontroller.net/articles/AVR_16-Bit-Register#Zugriffe_in_C Steve van de Grens schrieb: > Wo du die "spanne" jetzt her geholt hast, ist mir schleierhaft. > Diskutieren wir nicht mehr über > https://www.mikrocontroller.net/attachment/highlight/613919 ? > Das war nur ein Beispiel. Und nein, darüber brauchen wir nicht mehr diskutieren dass Problem hast du ja bereits erkannt und eine Lösung dargebracht. Bernd_Stein
:
Bearbeitet durch User
Hi
>aber trotzdem werden zwei Schreibzugriffe erzeugt.
Weil es zwei 8-Bit Register sind und kein 16 Bit Register.
MfG Spess
Leute: Also Echt. Der Autor stellt eine simple Frage. Was folgt: Ein Kindergarten von Animositäten wird in über 200 Post´s aktiv. Ich hoffe, dass ich in diesem Forum niemals über ein Problem berichten muss.
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.