Hai bisogno di aiuto per comprendere l'uscita speculare del timer AVR ATMEGA / ATTINY


10

Sto cercando di utilizzare Timer1 del microcontrollore Atmel AVR, AtMega328 come utilizzato in Arduino o ATTiny85, per emettere due segnali di clock che sono immagini speculari l'uno dell'altro. La frequenza che sto cercando di generare è una variabile da 1 MHz a 2 MHz o più che è troppo alta per farlo usando il codice per attivare / disattivare i pin di uscita a meno che non voglia fare quasi nient'altro nel controller. Quindi voglio usare l'uscita del timer direttamente sui pin associati. Sto usando la toolchain di GCC, quindi non limitato dalle librerie o dal linguaggio di Arduino.

Timer1 nell'Atmega328 ha due pin associati e posso ottenere due segnali identici da 1 MHz a 2 MHz. Anche se il foglio dati sembra dire che posso ottenere una forma d'onda invertita, mi confonde. Sono anche in grado di ottenere due segnali che sono cicli di lavoro diversi a 1 MHz, utilizzando le impostazioni PWM con Timer1, ma entrambi i segnali aumentano contemporaneamente, mentre quello più breve si abbassa prima. Questo non serve al mio progetto. Non ho nemmeno bisogno della variazione dell'ampiezza dell'impulso PWM, ho solo bisogno di due segnali identici di tipo "clock" di fase opposta, tutto qui.

Non sto chiedendo a nessuno di scrivere codice per farlo, ho solo bisogno di qualcuno che mi dica quale modalità / flag del timer dovrebbe darmi una semplice forma d'onda invertita su uno dei due pin associati al timer. Se possibile, voglio evitare di utilizzare un circuito di inversione esterno per una delle uscite, a meno che questa non sia l'unica opzione.

Se ciò è possibile in ATTiny, sarà ancora meglio. ATTiny ha anche 2 pin associati a un timer, ma non sono sicuro che abbia le stesse opzioni di ATMega.

Ho già un cristallo da 20 MHz e condensatori collegati sul PCB e l'orologio da 20 MHz funziona in modo affidabile su ATMega328. Sul PCB ATTiny85 ho un cristallo da 8 MHz e anche questo funziona in modo affidabile.

Per favore aiuto. Grazie.


AGGIORNAMENTO : Finora ci sono alcune ipotesi non valide nelle risposte e nei commenti, quindi forse dovrei chiarire: nota che nel mio post originale ho dichiarato che sto usando un clock a 20 MHz, non 8 MHz , e anche che non ho bisogno di PWM .

L'unica modalità che fornisce una frequenza di uscita sufficientemente elevata sembra essere la modalità CTC perché le modalità PWM non funzionano per l'uscita a 2 MHz. Esiste un modo per invertire l'uscita A del timer 1 o l'uscita B in modalità CTC?

Ora sono passato ad un Arduino Uno standard (ATMega328, 16 MHz) invece della mia scheda da 20 MHz per controllare il mio codice, e questo è il mio codice per un bel orologio stabile da 2 MHz in modalità CTC dai pin 9 e 10, il Timer 1 pin di uscita:

#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() {
}

Le tracce dell'oscilloscopio per entrambi i pin sono identiche e sincronizzate, come posso invertire uno dei due segnali? La modalità di inversione nel foglio dati sembra non fare nulla in modalità CTC. Sto leggendo il foglio dati in modo errato, o sarò costretto a utilizzare una frequenza più bassa e la modalità PWM dopo tutto?

Per aggiungere una domanda "bounty" specifica alla mia query originale:
Quindi quali modifiche devo apportare al mio codice sopra, per fargli dare segnali perfettamente invertiti ai pin 9 e 11 alla massima frequenza possibile per un clock a 16 MHz , sia che che è 2 MHz o no?

Continuerò con un Arduino Uno standard per ora, in modo che non ci sia modalità di errore introdotta dalla mia scheda homespun e in modo che chiunque abbia un arduino possa provare il mio codice sopra e confermare che funziona come ho già detto e non come bisogno!


1
Guardando la pagina 97-98 del foglio dati atmega8L , c'è una tabella delle modalità di funzionamento. Pagina 108 afferma "I bit COM21: 0 controllano se l'uscita PWM generata deve essere invertita o meno (PWM invertita o non invertita)". Tienici aggiornati sul tuo successo!
Vorac,

Perché non utilizzare un semplice inverter a transistor per le uscite con mirroring?
Jonny B, buono il

Risposte:


10

Dalla scheda tecnica ATtiny85:

La modalità operativa, ovvero il comportamento dei pin Timer / Counter e Output Compare, è definita dalla combinazione della modalità Waveform Generation (WGM0 [2: 0]) e Compare Output mode (COM0x [1: 0]) bit. I bit della modalità di confronto dell'output non influiscono sulla sequenza di conteggio, mentre i bit della modalità di generazione della forma d'onda lo fanno. I bit COM0x [1: 0] controllano se l'uscita PWM generata deve essere invertita o meno (PWM invertita o non invertita ).

La Tabella 11-5 mostra come impostare la Modalità.

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

Volete una modalità PWM veloce (quindi sia la modalità 3 che la modalità 7). Se si desidera variare il ciclo di lavoro e sembra che lo si faccia, si desidera la modalità 7 e il ciclo di lavoro impostando OCRA.

La Tabella 11-3 mostra come impostare la modalità di output di confronto per la modalità PWM veloce.

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)

Vale a dire, è possibile impostare l'uscita OC0A su bassa quando il valore del timer == OCR0A e alta quando il valore del timer == 0x00 impostando COM0A1: COM0A0 = 0b10. O viceversa impostando COM0A1: COM0A0 = 0b11. E allo stesso modo per OC0B, OCR0B, COM0B0, COM0B1.

La frequenza PWM è determinata dall'I / O Clock (8MHz suona come per te) e dall'impostazione del prescaler del timer. E l'equazione è data come f_clk_IO / (N * 256) per la modalità PWM veloce.

Quindi è possibile utilizzare OC0A per la polarità "normale" e OC0B per la polarità "invertita" impostando OCR0A e OCR0B sullo stesso valore e impostando COM0A1: COM0A0 = 0b10 e COM0B1: COM0B0 su 0b11.

AGGIORNARE

Dato che si desidera attivare / disattivare l'uscita il più rapidamente possibile e si sta utilizzando Mega328 a 16 MHz, la modalità operativa CTC consente di ottenere una frequenza di commutazione di:

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

La modalità PWM veloce ti consente di attivare / disattivare il pin in:

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

Quindi penso ancora che tu voglia la modalità PWM veloce. In particolare la modalità 3 con OCR0A = OCR0B = 0x80 per ciclo di lavoro del 50%. E impostare i bit COM0A su 0x3 e i bit COM0B su 0x2 per creare le due forme d'onda sulle inversioni OC0A e OC0B l'una dell'altra.

Aggiornamento n. 2 Altro Mega328 Prova questo codice Arduino:

#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(){

}

Fammi masticare un po 'su questo e vedere se funziona. Grazie.
ExcitingProjects,

Dopo aver riletto la tua risposta per provarla oggi, vedo un paio di ipotesi non valide: ho specificato un clock da 20 MHz (e ora sono passato a 16 MHz), non "(8 MHz suona come per te)" . Ho anche specificato che non ho bisogno della variazione dell'ampiezza dell'impulso PWM, quindi non sono sicuro di dove tu abbia ipotizzato "Se vuoi variare il duty cycle e suona come te" .
ExcitingProjects

@ExcitingProjects Stavo cancellando la tua affermazione "Sul PCB ATTiny85 ho un cristallo da 8 MHz e anche questo funziona in modo affidabile." e la mia risposta è in riferimento ad ATtiny85. Proverò ad aggiornare la mia risposta in risposta alla tua domanda aggiornata.
Vicatcu,

@vicateu Grazie. Ho aggiornato la domanda, visto che la modalità di inversione sembra non avere alcun effetto nella modalità CTC a meno che non mi manchi qualche passaggio.
ExcitingProjects

@ExcitingProjects dal foglio dati ATmega328: "Per le modalità non PWM i bit COM0x1: 0 controllano se l'output deve essere impostato, cancellato o attivato in una corrispondenza di confronto"
vicatcu

1

La famiglia ATtinyX5 ha PLL all'interno, usalo come un ragazzino.

Uso anche il PLL interno per alimentare il clock della CPU e ho 16Mhz senza XTAL. Questo è prezioso poiché hai solo 5 pin. (Non conto il pin di ripristino). Anche un PWM (OCR1B) PLL funzionante su pin XTAL con uscita gratuita opzionale. Hai solo bisogno di regolare i fusibili per 16Mhz Xtalless ATtiny ... O semplicemente lasciare funzionare la CPU a 8Mhz ma eseguire PWM con clock a 64Mhz senza cambiare i fusibili ..

Puoi avere un clock PWM fino a 64 Mhz (ma una risoluzione di 1 bit). O 125 Khz @ risoluzione a 8 bit. È possibile ridurre la risoluzione PWM e aumentare la velocità diminuendo il registro OCR1C.

Per 1 Mhz è necessario impostare OCR1C su 63. Per 2 Mhz è necessario impostare OCR1C su 31. Per 4 Mhz è necessario impostare OCR1C su 15. ...

Abilita PLL con questo codice:

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

Ora hai un clock a 64 Mhz sui PWM "OCR1B0 / OCR1A0".

Inoltre, è possibile regolare OCR1 [A / B] 0 e XOCR1 [A / B] 0 per l'output speculare.

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

Devi sapere che Dead Time Generator consumerà il PWM in uscita se imposti OCR1A = 1. Hai bisogno di valori più alti rispetto ai tempi morti.

Saluti,

Erdem

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.