Benötigen Sie Hilfe beim Verständnis der gespiegelten Ausgabe des AVR ATMEGA / ATTINY-Timers?

10

Ich versuche, Timer1 des Atmel AVR-Mikrocontrollers, entweder AtMega328, wie er im Arduino verwendet wird, oder ATTiny85 zu verwenden, um zwei Taktsignale auszugeben, die Spiegelbilder voneinander sind. Die Frequenz, die ich zu erzeugen versuche, ist eine Variable von 1 MHz bis 2 MHz oder mehr, die zu hoch ist, um dies mithilfe von Code zum Umschalten der Ausgangspins zu tun, es sei denn, ich möchte fast nichts anderes im Controller tun. Daher möchte ich den Timer-Ausgang direkt an den zugehörigen Pins verwenden. Ich verwende die GCC-Toolchain, die nicht durch Arduino-Bibliotheken oder -Sprachen eingeschränkt ist.

Mit Timer1 im Atmega328 sind zwei Pins verbunden, und ich kann zwei identische 1-MHz- bis 2-MHz-Signale aus ihnen herausholen. Obwohl das Datenblatt zu sagen scheint, dass ich eine invertierte Wellenform erhalten kann, verwirrt es mich. Ich bin auch in der Lage, zwei Signale mit unterschiedlichen Arbeitszyklen bei 1 MHz zu erhalten, indem ich die PWM-Einstellungen mit Timer1 verwende, aber beide Signale gehen gleichzeitig hoch, das kürzere geht früher niedrig. Dies dient nicht meinem Projekt. Ich brauche nicht einmal die PWM-Impulsbreitenvariation, ich brauche nur zwei identische "Takt" -Signale mit entgegengesetzter Phase, das ist alles.

Ich fordere niemanden auf, Code zu schreiben, damit ich dies tun kann. Ich brauche nur jemanden, der mir sagt, welcher Modus / welche Flags des Timers mir eine einfache invertierte Wellenform auf einem der beiden dem Timer zugeordneten Pins geben sollen. Wenn möglich, möchte ich die Verwendung einer externen Invertierungsschaltung für einen der Ausgänge vermeiden, es sei denn, dies ist nur eine Option.

Wenn dies im ATTiny überhaupt möglich ist, ist das sogar noch besser. Das ATTiny hat auch 2 Pins, die einem Timer zugeordnet sind, aber ich bin nicht sicher, ob es die gleichen Optionen wie das ATMega hat.

Ich habe bereits einen 20-MHz-Quarz und Kondensatoren auf der Leiterplatte angeschlossen, und der 20-MHz-Takt arbeitet zuverlässig auf dem ATMega328. Auf der ATTiny85-Platine habe ich einen 8-MHz-Quarz und das funktioniert auch zuverlässig.

Bitte helfen Sie. Vielen Dank.


UPDATE : Es gibt einige ungültige Annahmen in den Antworten und Kommentaren, daher sollte ich vielleicht klarstellen: Beachten Sie, dass ich in meinem ursprünglichen Beitrag angegeben habe, dass ich einen 20-MHz-Takt verwende, nicht 8 MHz , und dass ich auch kein PWM benötige .

Der einzige Modus, der eine ausreichend hohe Ausgangsfrequenz liefert, scheint der CTC-Modus zu sein, da die PWM-Modi für einen 2-MHz-Ausgang nicht funktionieren. Gibt es eine Möglichkeit, entweder Timer 1-Ausgang A oder Ausgang B im CTC-Modus zu invertieren?

Ich habe jetzt zu einem Standard-Arduino Uno (ATMega328, 16 MHz) anstelle meiner eigenen 20-MHz-Karte gewechselt, um meinen Code zu überprüfen, und dies ist mein Code für einen schönen stabilen 2-MHz-Takt im CTC-Modus von den Pins 9 und 10, dem Timer 1 Ausgangspins:

#define tick 9
#define tock 10

void setup() {
  pinMode(tick, OUTPUT);  
  pinMode(tock, OUTPUT); 

  TCCR1A = _BV(COM1A0) | _BV(COM1B0) ;   // activate both output pins 
  TCCR1B = _BV(WGM12)| 1;                // set CTC mode, prescaler mode 1

  // various frustrating attempts to invert OC1B failed. What do I put here?

  OCR1A = 3;                             // set the counter max for 2 MHz

}

void loop() {
}

Die Oszilloskopspuren für beide Pins sind identisch und synchron. Wie kann ich eines der beiden Signale invertieren? Der Invertierungsmodus im Datenblatt scheint im CTC-Modus nichts zu bewirken. Lese ich das Datenblatt falsch oder bin ich schließlich gezwungen, einen niedrigeren Frequenz- und PWM-Modus zu verwenden?

So fügen Sie meiner ursprünglichen Abfrage eine bestimmte "Kopfgeld" -Frage hinzu:
Welche Änderungen muss ich an meinem obigen Code vornehmen, damit er perfekt invertierte Signale an Pin 9 und 11 mit der höchstmöglichen Frequenz für einen 16-MHz-Takt liefert , ob das ist 2 MHz oder nicht?

Ich werde mich vorerst an ein Standard-Arduino-Uno halten, damit kein Fehlermodus von meinem selbstgesponnenen Board eingeführt wird und jeder mit einem Arduino meinen obigen Code ausprobieren und bestätigen kann, dass er wie erwähnt funktioniert und nicht wie ich brauchen!

Spannende Projekte
quelle
1
Auf Seite 97-98 des atmega8L- Datenblattes finden Sie eine Tabelle der Betriebsarten. Seite 108 lautet "Die COM21: 0-Bits steuern, ob der erzeugte PWM-Ausgang invertiert werden soll oder nicht (invertierte oder nicht invertierte PWM)". Halten Sie uns über Ihren Erfolg auf dem Laufenden!
Vorac
Warum nicht einen einfachen Transistorinverter für die gespiegelten Ausgänge verwenden?
Jonny B Good

Antworten:

10

Aus dem ATtiny85-Datenblatt:

Die Betriebsart, dh das Verhalten der Timer / Zähler- und Ausgangsvergleichspins, wird durch die Kombination des Wellenformgenerierungsmodus (WGM0 [2: 0]) und des Ausgangsvergleichsmodus (COM0x [1: 0]) definiert. Bits. Die Bits für den Vergleichsausgangsmodus wirken sich nicht auf die Zählsequenz aus, während die Bits für den Wellenformgenerierungsmodus dies tun. Die COM0x [1: 0] -Bits steuern, ob der erzeugte PWM-Ausgang invertiert werden soll oder nicht (invertierte oder nicht invertierte PWM ).

Tabelle 11-5 zeigt, wie Sie den Modus einstellen.

Mode   WGM  WGM  WGM  Timer/Counter Mode    TOP      Update of    TOV Flag
c0     02   01   00   of Operation                   OCRx at      Set on
==========================================================================
0      0    0    0    Normal                0xFF     Immediate    MAX(1)
1      0    0    1    PWM, Phase Correct    0xFF     TOP          BOTTOM
2      0    1    0    CTC                   OCRA     Immediate    MAX
3      0    1    1    Fast PWM              0xFF     BOTTOM       MAX
4      1    0    0    Reserved                                  
5      1    0    1    PWM, Phase Correct    OCRA     TOP          BOTTOM
6      1    1    0    Reserved                                  
7      1    1    1    Fast PWM              OCRA     BOTTOM       TOP

Sie möchten einen schnellen PWM-Modus (also entweder Modus 3 oder Modus 7). Wenn Sie den Arbeitszyklus ändern möchten und es sich so anhört, möchten Sie Modus 7 und den Arbeitszyklus durch Einstellen von OCRA variieren.

Tabelle 11-3 zeigt, wie Sie den Vergleichsausgabemodus für den Fast PWM-Modus einstellen.

COM0A1/   COM0A0/
COM0B1    COM0B0     Description
===============================================================================
0         0          Normal port operation, OC0A/OC0B disconnected.
0         1          Reserved
1         0          Clear OC0A/OC0B on Compare Match, set OC0A/OC0B at BOTTOM
                     (non-inverting mode)
1         1          Set OC0A/OC0B on Compare Match, clear OC0A/OC0B at BOTTOM
                     (inverting mode)

Das heißt, Sie können den OC0A-Ausgang so einstellen, dass er niedrig wird, wenn der Timer-Wert == OCR0A ist, und hoch, wenn der Timer-Wert == 0x00 ist, indem Sie COM0A1: COM0A0 = 0b10 einstellen. Oder umgekehrt, indem Sie COM0A1 setzen: COM0A0 = 0b11. Und ebenso für OC0B, OCR0B, COM0B0, COM0B1.

Die PWM-Frequenz wird durch die E / A-Uhr (8 MHz, wie es sich für Sie anhört) und Ihre Timer-Prescaler-Einstellung bestimmt. Und die Gleichung wird als f_clk_IO / (N * 256) für den schnellen PWM-Modus angegeben.

Sie können also OC0A für "normale" Polarität und OC0B für "invertierte" Polarität verwenden, indem Sie OCR0A und OCR0B auf den gleichen Wert einstellen und COM0A1: COM0A0 = 0b10 und COM0B1: COM0B0 auf 0b11 einstellen.

AKTUALISIEREN

Wenn Sie den Ausgang so schnell wie möglich umschalten möchten und den Mega328 mit 16 MHz verwenden, können Sie im CTC-Betriebsmodus eine Schaltfrequenz von:

f_OCnA = f_clk_IO / (2 · N · [1 + OCRnA) = 16e6 / (2 · 1 · [1 + 1]) = 4 MHz

Im Fast PWM-Modus können Sie den Pin umschalten auf:

f_OCnxPWM = f_clk_IO / (N * [1 + TOP]) = 16e6 / (1 * [1 + 1]) = 8 MHz

Ich denke immer noch, dass Sie den schnellen PWM-Modus wollen. Speziell Modus 3 mit OCR0A = OCR0B = 0x80 für 50% Einschaltdauer. Setzen Sie die COM0A-Bits auf 0x3 und die COM0B-Bits auf 0x2, um die beiden Wellenformen bei OC0A- und OC0B-Inversionen voneinander zu erzeugen.

Update Nr. 2 Mehr zum Mega328 Probieren Sie diesen Arduino-Code aus:

#define tick 9
#define tock 10

void setup(){

  pinMode(tick, OUTPUT);  
  pinMode(tock, OUTPUT); 

  // Setup Waveform Generation Mode 15
  // OC1A Compare Output Mode = inverting mode
  // OC1B Compare Output Mode = non-inverting mode
  // Timer Prescaler = 1
  // TOP = OCR1A = 1

  //COM1A[1:0] = 0b11, COM1B[1:0] = 0b10, WGM1[1:0] = 0b11
  TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);

  //WGM1[3:2] = 0b11, CS1[2:0] = 0b001
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);

  OCR1A = 0x0001;
  OCR1B = 0x0001;
}

void loop(){

}
vicatcu
quelle
Lassen Sie mich ein bisschen daran kauen und sehen, ob es funktioniert. Vielen Dank.
Spannende
Nachdem ich Ihre Antwort noch einmal gelesen habe, um sie heute auszuprobieren, sehe ich einige ungültige Annahmen: Ich habe einen 20-MHz-Takt angegeben (und jetzt habe ich auf 16 MHz umgeschaltet), nicht "(8 MHz klingt für Sie)" . Außerdem habe ich angegeben, dass ich keine PWM-Pulsbreitenvariation benötige, also nicht sicher, wo Sie vermutet haben "Wenn Sie den Arbeitszyklus variieren möchten und es sich so anhört" .
Aufregende
@ExcitingProjects Ich habe Ihre Aussage "Auf einer ATTiny85-Platine habe ich einen 8-MHz-Quarz und das funktioniert auch zuverlässig." und meine Antwort bezieht sich auf den ATtiny85. Ich werde versuchen, meine Antwort zu aktualisieren, um Ihre aktualisierte Frage zu beantworten.
Vicatcu
@vicateu Danke. Ich habe die Frage aktualisiert, da der Invertierungsmodus im CTC-Modus keine Auswirkung zu haben scheint, es sei denn, mir fehlt ein Schritt.
Spannende
@ExcitingProjects aus dem ATmega328-Datenblatt: "Für Nicht-PWM-Modi steuern die COM0x1: 0-Bits, ob die Ausgabe bei einer Vergleichsübereinstimmung gesetzt, gelöscht oder umgeschaltet werden soll"
vicatcu
1

Die ATtinyX5-Familie hat PLL im Inneren, benutze es, großer Junge.

Ich verwende interne PLL, um auch den CPU-Takt mit Strom zu versorgen, und habe 16 MHz ohne XTAL. Dies ist wertvoll, da Sie nur 5 Stifte haben. (Ich zähle nicht den Reset-Pin). Außerdem läuft ein PLL-PWM (OCR1B) an XTAL-Pins mit optionalem kostenlosem Ausgang. Sie müssen nur die Sicherungen für 16 MHz Xtalless ATtiny einstellen ... Oder lassen Sie die CPU einfach mit 8 MHz laufen, aber führen Sie PWM mit 64 MHz Takt aus, ohne die Sicherungen zu wechseln.

Sie können bis zu 64 MHz Takt-PWM (aber 1 Bit Auflösung) haben. Oder 125 kHz bei 8 Bit Auflösung. Sie können die PWM-Auflösung reduzieren und die Geschwindigkeit erhöhen, indem Sie das OCR1C-Register verringern.

Für 1 MHz müssen Sie OCR1C auf 63 einstellen. Für 2 MHz müssen Sie OCR1C auf 31 einstellen. Für 4 MHz müssen Sie OCR1C auf 15 einstellen. ...

Aktivieren Sie einfach PLL mit diesem Code:

PLLCSR |= (1 << PLLE);           //Start PLL
while( !(PLLCSR & (1<<PLOCK)) ); //Wait for PLL lock
//PLLCSR |= (1<<LSM );           //Low Speed PLL that clocks 32Mhz, not 64Mhz
PLLCSR |= (1 << PCKE);           //Enable PLL

Jetzt haben Sie einen 64-MHz-Takt für PWMs "OCR1B0 / OCR1A0".

Sie können auch OCR1 [A / B] 0 und XOCR1 [A / B] 0 für die gespiegelte Ausgabe anpassen.

if(0){ //Synch mode
     //OCR1A & XOCR1A enable for Synch operation but not allow odd PWM values!
     TCCR1 |= (1 << PWM1A) | (0 << COM1A1) | (1 << COM1A0); 
     //Also ATtinyX5 has "Dead Time Generator", use it ;)
     DTPS1 = 3;   //8x Prescaler for dead time generator (maximum)
     DT1A = 0xff; //Clk dead on both channels (maximum)
     }
   else
     TCCR1 |= (1 << PWM1A) | (1 << COM1A1) | (0 << COM1A0);  //ONLY OCR1A enabled

Sie müssen wissen, dass der Dead Time Generator PWM ausgibt, wenn Sie OCR1A = 1 setzen. Sie benötigen höhere Werte als die Totzeit.

Grüße,

Erdem

EUA
quelle