Forum: Mikrocontroller und Digitale Elektronik Bitte um Hilfe bei der Programmierung von AVR8-Mikrocontrollern in C


von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

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

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

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

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

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

von Steve van de Grens (roehrmond)


Lesenswert?

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.

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

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
von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Steve van de Grens (roehrmond)


Lesenswert?

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.

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

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
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

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
von Steve van de Grens (roehrmond)


Lesenswert?

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 ?

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

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
von Spess53 .. (hardygroeger)


Lesenswert?

Hi

>aber trotzdem werden zwei Schreibzugriffe erzeugt.

Weil es zwei 8-Bit Register sind und kein 16 Bit Register.

MfG Spess

von Peter H. (hp-soft)


Lesenswert?

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
Noch kein Account? Hier anmelden.