CTC - Timer 2 - TCCR2A - gezielter Reset notwendig - Warum?

Hallo,

bin gerade etwas ratlos warum das Timer 2 Register TCCR2A nicht richtig gesetzt wird und davon auch die serielle Ausgabe beeinträchtig ist.

Ich weise allen Timerregistern konkrete Werte zu. Ich verodere nichts. Sodass ich mir das vorherige notwendige Nullen sparen kann. Eigentlich! Setze ich TCCR2A nicht auf 0, dann stimmt die Frequenz nicht und die 2. serielle Ausgabe fehlt.
Alles hängt von Zeile 47 ab.
Kann das jemand nachvollziehen?
Sieht jemand irgendeinen Fehler den ich nicht sehe?

/* 
 Arduino Mega2560
 Timer 2: CTC, Mode 2
  
 Pinouts  >>> http://www.pighixxx.net/pinoutspg/boards/
 Uno      >>> http://www.pighixxx.net/portfolio-items/uno/?portfolioID=314
 Mega2560 >>> http://www.pighixxx.net/portfolio-items/mega/?portfolioID=314
*/

const byte pin_T2 = 10;


void setup(void) {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(pin_T2, OUTPUT);

  Serial.print("OCR2A");  Serial.print('\t'); formatiere_Byte (OCR2A);    
  Serial.print("OCR2B");  Serial.print('\t'); formatiere_Byte (OCR2B);
  Serial.print("TCCR2A"); Serial.print('\t'); formatiere_Byte (TCCR2A);
  Serial.print("TCCR2B"); Serial.print('\t'); formatiere_Byte (TCCR2B); 
  Serial.print("TIMSK2"); Serial.print('\t'); formatiere_Byte (TIMSK2);  
  Serial.flush();
  
  set_Timer2();   
 
  Serial.println();
  Serial.print("OCR2A");  Serial.print('\t'); formatiere_Byte (OCR2A);    
  Serial.print("OCR2B");  Serial.print('\t'); formatiere_Byte (OCR2B);
  Serial.print("TCCR2A"); Serial.print('\t'); formatiere_Byte (TCCR2A);
  Serial.print("TCCR2B"); Serial.print('\t'); formatiere_Byte (TCCR2B); 
  Serial.print("TIMSK2"); Serial.print('\t'); formatiere_Byte (TIMSK2);
  
}

void loop(void) {
  
}


// ****** Funktionen ******* //
    
void set_Timer2()         // CTC, Mode 2
{
  cli();                  // Interrupts ausschalten
  TCNT2 = 0;              // Reset Register                 
  //TCCR2A = 0;           // Warum Nullen notwendig?
  OCR2A = 249;            // Compare
  TIMSK2 = (1<<OCIE2A);   // Compare Match A
  TCCR2A = (1<<WGM21);    // set Mode
  TCCR2B = (1<<CS22);     // Prescaler 64
  sei();                  // Interrupts einschalten
}  


ISR(TIMER2_COMPA_vect)          // Timer 2 Interrupt 
{  
  static bool state = LOW;
  state = !state;
  digitalWrite(pin_T2, state);                    
}


void formatiere_Byte (unsigned int data)
{
  Serial.print(F("data: "));
  for (char i=7;i>=4;i--) {
    Serial.print( (data >> i) & 0x01);
  }
  Serial.print("'");
  for (char i=3;i>=0;i--) {
    Serial.print( (data >> i) & 0x01);
  }
  Serial.println();
}

TCCR2A = 0; // Warum Nullen notwendig?

Du musst an der Stelle nicht nullen.

TCCR2A = (1<<WGM21);

Den richtigen/beabsichtigten Modus setzen, wäre doch an der Stelle viel sinnvoller.

Warum, das aber stehen bleibt?
KA, vermute, dass du einen ungültigen inneren Zustand erzeugst.

Hallo,

hast du wirklich meinen Text gelesen?

Natürlich!
Sogar ausprobiert.

Und meinen Vorschlag getestet!
Welcher sich als gangbar erwiesen hat.

Hast du meine Antwort gelesen?
Wenn ja, dann wohl nicht verstanden.

Aber ich kann dich ja nochmal deutlich was fragen:
Warum willst du unbedingt vorher den Timer in Modus 0 setzen und später dann in Modus 2, wenn du ihn AN DER STELLE genauso gut sofort in den gewünschtenModus bringen könntest?

void set_Timer2()         // CTC, Mode 2
{
  cli();                  // Interrupts ausschalten
  TCNT2 = 0;              // Reset Register                 
  TCCR2A = (1<<WGM21);           // hier setzen
  //TCCR2A = 0;           // Warum Nullen notwendig?
  OCR2A = 249;            // Compare
  TIMSK2 = (1<<OCIE2A);   // Compare Match A
 // TCCR2A = (1<<WGM21);    // set Mode
  TCCR2B = (1<<CS22);     // Prescaler 64
  sei();                  // Interrupts einschalten
}

EDIT: korrigiert

Hallo,

du sagst mir doch nichts neues. Das weiß ich doch selbst. Steht im Text und im Sketch.
Die einzige Frage die mich beschäftigt ist warum das Register TCCR2B nur richtig gesetzt wird wenn man es vorher nullt?

Die einzige Frage die mich beschäftigt ist warum das Register TCCR2B nur richtig gesetzt wird wenn man es vorher nullt?

Das stimmt doch gar nicht!

Ich habe den Gegenbeweis hier bei mir laufen.

Ersetze deine Funktion durch diese, dann klappts auch bei dir ohne nullen.

void set_Timer2()         // CTC, Mode 2
{
  cli();                  // Interrupts ausschalten

  // erst die Control Register setzen
  TCCR2A = (1<<WGM21);    // Mode 2
  TCCR2B = (1<<CS22);     // Prescaler 64

  // dann die davon abhaengigen.
  OCR2A = 249;            // Compare
  TIMSK2 = (1<<OCIE2A);   // Compare Match A
  TCNT2 = 0;              // Reset Register    
               
  sei();                  // Interrupts einschalten
}

Hallo,

du hast meine Eingangsfrage demnach nicht verstanden.

Das Einzigste was auffällig ist, das die Reihenfolge der Registeränderung Einfluss hat.
Das kann ich nun noch weniger nachvollziehen.
Wenn man TCCR2A vor OCR2A und vor TIMSK2 ändert, dann klappt alles ohne ordnungsgemäß.
Wenn man die Reihenfolge anders hat, wie zum Bsp. im Eingangspost gezeigt, muss man TCCR2A vorher nullen.
Damit entsteht die 2. Frage seit wann die Reihenfolge Einfluss auf die Settings haben?

das hier funktioniert wie es soll

void set_Timer2()         // CTC, Mode 2
{
  cli();                  // Interrupts ausschalten
  TCNT2 = 0;              // Reset Register          
  TCCR2A = (1<<WGM21);    // set Mode        
  OCR2A  = 249;           // Compare
  TIMSK2 = (1<<OCIE2A);   // Compare Match A
  TCCR2B = (1<<CS22);     // Prescaler 64
  sei();                  // Interrupts einschalten
}

Damit entsteht die 2. Frage seit wann die Reihenfolge Einfluss auf die Settings haben?

Offensichtlich hat es einen Einfluss.

Das kann ich dir auch nicht mehr beantworten, als ich es schon getan habe!

KA, vermute, dass du einen ungültigen inneren Zustand erzeugst.

PS:
Habe schon einiges mit den Timern gemacht,
Bin dabei aber noch nie auf deine Reihenfolge gekommen.

Habe IMMER erst die Controll Register gesetzt, und dann die anderen.
Nie damit auf deine Probleme/Fragen gestoßen


du hast meine Eingangsfrage demnach nicht verstanden.

Damit endet diese Diskussion hier und jetzt für mich.
Ich wünsche dir einen erfolgreichen Kampf gegen die Windmühlen.

Hallo,

du musst doch nicht immer gleich komisch tun, nur weil es keine Antworten auf gestellte Probleme gibt. Heute ist nichts weiter passiert als das ich die Reihenfolge zufällig geändert hatte und dabei auf besagtes Problem gestoßen bin. Deswegen stürzt die Welt nicht ein.

Wenn man es direkt macht funktioniert es. Demnach hat das Arduino Framework irgendeinen Einfluss.

int main(void) { 

  DDRB = (1<<4);    // Pin 10
        
  set_Timer2();
  
  while(1) {           
                       
  } 
}  


void set_Timer2()         // CTC, Mode 2 (500Hz)
{
  cli();                  // Interrupts ausschalten
  TCNT2 = 0;              // Reset Register                
  OCR2A  = 249;           // Compare
  TIMSK2 = (1<<OCIE2A);   // Compare Match A
  TCCR2A = (1<<WGM21);    // set Mode  
  TCCR2B = (1<<CS22);     // Prescaler 64
  sei();                  // Interrupts einschalten
}  


ISR(TIMER2_COMPA_vect)   // Timer 2 ISR 
{  
  PINB = _BV(PB4);                  
}

Demnach hat das Arduino Framework irgendeinen Einfluss.

Natürlich!
Es setzt den Modus 1
(das sieht man doch auch an deinen Ausgaben)

Hallo,

bei der Antwort bin ich mir wieder nicht sicher ob du das Problem im vollen Umfang erkannt hast.
Natürlich setzt das Framework erstmal seine Grundeinstellungen für alle Timer usw. Ist ja normal und auch richtig. Der Punkt ist das es danach eigene Einstellungen behindert und sogar die eigene Serielle lahm legt. An den seriellen Einstellungen fummel ich ja nicht rum. Da muss etwas unter der Haube völlig schief laufen.

bei der Antwort bin ich mir wieder nicht sicher ob du das Problem im vollen Umfang erkannt hast.

Das sagst du mir jetzt zum dritten mal.
(habe ich richtig gezählt?)

Was soll das?
Willst du mich für blöd verkaufen?

Fakt ist ja wohl, dass ich häufiger mal eine andere Sicht auf die Dinge habe, als du.
Das "Problem" welches du da aufbauscht, ist irrational, aus meiner Sicht.

Versagen, bei falscher Initialisierung von Hardwarekomponenten, ist keine Seltenheit.
Es gibt also keinen Grund so zu tun, als wäre das jetzt eine grausame Überraschung.

und sogar die eigene Serielle lahm legt.

Ich glaube, da bleibt noch mehr stehen!
Nicht nur die Serielle, sondern eher Alles.

Die Lösung für dein Problem ist: Richtige Initialisierungsreihenfolge einhalten.
Diese Lösung reicht dir nicht, nehme ich mal an...
Du möchtest das "Warum" erfahren.
Richtig?

Vermutlich wirst du dafür den Entwickler des ATMega2560 befragen müssen.
Denn der hält den inneren Aufbau des ATMega2560 vor mir verborgen.

Wobei ich vermute, dass der Entwickler dir nicht die Innereien offen legt, sondern dir nur sagen wird, was "wir" auch schon herausgefunden haben: Richtig Initialisieren, dann klappts auch.

#include <util/atomic.h>
#define AtomicSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
/* 
 Arduino Mega2560
 Timer 2: CTC, Mode 2
  
 Pinouts  >>> http://www.pighixxx.net/pinoutspg/boards/
 Uno      >>> http://www.pighixxx.net/portfolio-items/uno/?portfolioID=314
 Mega2560 >>> http://www.pighixxx.net/portfolio-items/mega/?portfolioID=314
*/



//const byte pin_T2 = 10;
const byte pin_T2 = LED_BUILTIN;


void setup(void) {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(pin_T2, OUTPUT);

  Serial.print("OCR2A");  Serial.print('\t'); formatiere_Byte (OCR2A);    
  Serial.print("OCR2B");  Serial.print('\t'); formatiere_Byte (OCR2B);
  Serial.print("TCCR2A"); Serial.print('\t'); formatiere_Byte (TCCR2A);
  Serial.print("TCCR2B"); Serial.print('\t'); formatiere_Byte (TCCR2B); 
  Serial.print("TIMSK2"); Serial.print('\t'); formatiere_Byte (TIMSK2);  
  Serial.flush();
  
  set_Timer2();   
 
  Serial.println();
  Serial.print("OCR2A");  Serial.print('\t'); formatiere_Byte (OCR2A);    
  Serial.print("OCR2B");  Serial.print('\t'); formatiere_Byte (OCR2B);
  Serial.print("TCCR2A"); Serial.print('\t'); formatiere_Byte (TCCR2A);
  Serial.print("TCCR2B"); Serial.print('\t'); formatiere_Byte (TCCR2B); 
  Serial.print("TIMSK2"); Serial.print('\t'); formatiere_Byte (TIMSK2);
  
}

void loop(void) {
  
}


// ****** Funktionen ******* //
    
void set_Timer2()         // CTC, Mode 2
{
  AtomicSection
  {
    // erst die Control Register setzen
    TCCR2A = (1<<WGM21);    // Mode 2
    TCCR2B = (1<<CS22);     // Prescaler 64
  
    // dann die davon abhaengigen.
    OCR2A = 249;            // Compare
    TIMSK2 = (1<<OCIE2A);   // Compare Match A
    TCNT2 = 0;              // Reset Counter Register    
  }             
}  


ISR(TIMER2_COMPA_vect)          // Timer 2 Interrupt 
{  
  static bool state = LOW;
  state = !state;
  digitalWrite(pin_T2, state);                    
}


void formatiere_Byte (unsigned int data)
{
  Serial.print(F("data: "));
  for (char i=7;i>=4;i--) {
    Serial.print( (data >> i) & 0x01);
  }
  Serial.print("'");
  for (char i=3;i>=0;i--) {
    Serial.print( (data >> i) & 0x01);
  }
  Serial.println();
}

Hallo,

zeige mir ein Dokument wo drin steht das man die Timer Register nach einer ganz bestimmten Reihenfolge bearbeiten muss.

Und wieso muss ich dir das zeigen?
Wie kommst du auf diese absurde Idee?

Ist es nicht offensichtlich, in der Praxis nachgewiesen, dass eine Reihenfolge eingehalten werden muss?

Hallo,

eben weil es keine amtlich festgelegte Reihenfolge gibt. Wäre ja auch nonsens. Manchmal möchte man zur Laufzeit Änderungen am Timer vornehmen. Erst die Gesamtkonfig ergibt die Timerfunktion. Du stützt dich alleine auf eine funktionierende Reihenfolge. Davon gibts hunderte, hab ich auch selber. Jedoch gibt es offensichtlich einen nicht logisch erklärbaren Abhängigkeitseffekt.

Ich sehe gerade, hier bist du mit deinem Problem voll abgeblitzt.

Habe ich auch Verständnis für.
Denn es ist ganz offensichtlich kein Problem der IDE.
Noch nicht mal der Tool Chain. (der erzeugte asm Code ist korrekt)

Wenn es das Problem überhaupt gibt, dann steckt es im µC selber.
In der Hardware.
Und da können wir alle nichts dran machen.

Merke:

Wir können den Wind nicht ändern,
aber die Segel anders setzen.

Das ganze wurde hier schonmal ausdiskutiert, sehr interessant.

https://www.avrfreaks.net/forum/issue-timer2-ctc-mode-arduino-uno-board

Hallo,

mit Schadenfreude kann bei mir niemand Punkte sammeln.

Den Link werde ich mir anschauen. Danke. Ich forsche weiter ... ob es nur das eine Register betrifft oder nur Timer 2 ...

mit Schadenfreude kann bei mir niemand Punkte sammeln.

Die Schadenfreude existiert nur in deinem Kopf!

Merksatz:

Ich bin verantwortlich, für das, was ich sage.
Nicht für das, was du empfindest.

Am Ende sind immer die anderen schuld die alles falsch verstehen. Ja ne is klar.