Potrzebujesz pomocy w zrozumieniu wyjścia lustrzanego timera AVR ATMEGA / ATTINY

10

Próbuję użyć Timera1 mikrokontrolera AVR Atmel, albo AtMega328, jak w Arduino, lub ATTiny85, aby wyprowadzić dwa sygnały zegarowe, które są wzajemnie odbiciami lustrzanymi. Częstotliwość, którą próbuję wygenerować, jest zmienną od 1 MHz do 2 MHz lub więcej, które są zbyt wysokie, aby to zrobić za pomocą kodu do przełączania pinów wyjściowych, chyba że nie chcę nic więcej robić w kontrolerze. Chcę więc użyć wyjścia timera bezpośrednio na powiązanych pinach. Korzystam z zestawu narzędzi GCC, więc nie są ograniczone bibliotekami lub językami Arduino.

Timer1 w Atmega328 ma z nim dwa piny i mogę wydobyć z nich dwa identyczne sygnały od 1MHz do 2MHz. Chociaż wydaje się, że arkusz danych mówi, że mogę uzyskać odwrócony przebieg, to mnie dezorientuje. Jestem w stanie uzyskać dwa sygnały, które są różnymi cyklami pracy przy 1 MHz, używając ustawień PWM z Timerem 1, ale oba sygnały idą jednocześnie w górę, tym krótszy wcześniej. To nie służy mojemu projektowi. Nie potrzebuję nawet zmiany szerokości impulsu PWM, potrzebuję tylko dwóch identycznych sygnałów typu „zegar” przeciwnej fazy, to wszystko.

Nie proszę nikogo o napisanie dla mnie kodu, po prostu potrzebuję kogoś, kto powie mi, który tryb / flagi timera powinny dać mi prosty odwrócony przebieg na jednym z dwóch pinów powiązanych z timerem. Jeśli to możliwe, chcę uniknąć używania zewnętrznego obwodu odwracającego dla jednego z wyjść, chyba że jest to tylko opcja.

Jeśli jest to w ogóle możliwe w ATTiny, będzie jeszcze lepiej. ATTiny ma również 2 piny związane z jednym zegarem, ale nie jestem pewien, czy ma takie same opcje jak ATMega.

Mam już kryształ 20 MHz i kondensatory podłączone na płytce drukowanej, a zegar 20 MHz działa niezawodnie na ATMega328. Na płytce ATTiny85 mam kryształ 8 MHz, który również działa niezawodnie.

Proszę pomóż. Dziękuję Ci.


AKTUALIZACJA : Do tej pory w odpowiedziach i komentarzach są pewne nieprawidłowe założenia, więc może powinienem wyjaśnić: Zauważ, że w moim oryginalnym poście stwierdziłem, że używam zegara 20 MHz, a nie 8 MHz , a także, że nie potrzebuję PWM .

Jedynym trybem, który zapewnia wystarczająco wysoką częstotliwość wyjściową, wydaje się być tryb CTC, ponieważ tryby PWM nie działają na wyjściu 2 MHz. Czy istnieje sposób na odwrócenie wyjścia Timera 1 A lub wyjścia B w trybie CTC?

Teraz sprawdziłem swój kod na standardowym Arduino Uno (ATMega328, 16 MHz) zamiast na własnej płycie 20 MHz, a to jest mój kod ładnego stałego zegara 2 MHz w trybie CTC ze styków 9 i 10, Timer 1 styki wyjściowe:

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

Ślady oscyloskopu dla obu pinów są identyczne i zsynchronizowane, jak mogę odwrócić jeden z dwóch sygnałów? Tryb odwracania w arkuszu danych wydaje się nic nie robić w trybie CTC. Czy źle czytam arkusz danych, czy w końcu będę zmuszony użyć niższej częstotliwości i trybu PWM?

Aby dodać określone pytanie „nagroda” do mojego pierwotnego zapytania:
Więc jakie zmiany muszę wprowadzić w powyższym kodzie, aby nadawał idealnie odwrócony sygnał na styku 9 i 11 przy najwyższej możliwej częstotliwości dla zegara 16 MHz , czy to jest 2 MHz czy nie?

Na razie będę się trzymał standardowego Arduino Uno, aby moja własna płyta nie wprowadziła trybu błędu i aby każdy, kto ma arduino, mógł wypróbować mój kod powyżej i potwierdzić, że działa tak, jak wspomniałem, a nie tak, jak ja potrzeba!

ExcitingProjects
źródło
1
Patrz strona 97-98 arkusza danych atmega8L , zawiera tabelę trybów działania. Strona 108 stwierdza: „Bity COM21: 0 kontrolują, czy wygenerowany sygnał wyjściowy PWM powinien być odwrócony, czy nie (PWM odwrócony lub nieodwrócony)”. Informuj nas o swoim sukcesie!
Vorac,
Dlaczego nie zastosować prostego falownika tranzystorowego do lustrzanych wyjść?
Jonny B Good

Odpowiedzi:

10

Z arkusza danych ATtiny85:

Tryb działania, tj. Zachowanie pinów Timer / Counter i Output Output, jest definiowany przez kombinację trybu Generowania Przebiegu (WGM0 [2: 0]) i Trybu porównywania Wyjścia (COM0x [1: 0]) bitów Bity trybu porównywania danych wyjściowych nie wpływają na sekwencję zliczania, podczas gdy bity trybu generowania fali mają taki wpływ. Bity COM0x [1: 0] kontrolują, czy generowane wyjście PWM powinno być odwrócone, czy nie (PWM odwrócony lub nieodwrócony ).

Tabela 11-5 pokazuje, jak ustawić tryb.

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

Chcesz szybkiego trybu PWM (więc albo w trybie 3, albo w trybie 7). Jeśli chcesz zmieniać cykl pracy i brzmi to tak, jak chcesz, chcesz tryb 7 i zmieniać cykl pracy, ustawiając OCRA.

Tabela 11-3 pokazuje, jak ustawić tryb wyjścia porównania dla trybu szybkiego PWM.

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)

To znaczy, możesz ustawić wyjście OC0A tak, aby było niskie, gdy wartość Timera == OCR0A, i wysokie, gdy wartość Timera == 0x00, ustawiając COM0A1: COM0A0 = 0b10. Lub odwrotnie, ustawiając COM0A1: COM0A0 = 0b11. I podobnie dla OC0B, OCR0B, COM0B0, COM0B1.

Częstotliwość PWM jest określana przez Zegar I / O (8MHz, jak dla Ciebie brzmi) i ustawienie preskalera timera. Równanie jest podane jako f_clk_IO / (N * 256) dla trybu szybkiego PWM.

Możesz więc użyć OC0A dla polaryzacji „normalnej” i OC0B dla polaryzacji „odwróconej”, ustawiając OCR0A i OCR0B na tę samą wartość i ustawiając COM0A1: COM0A0 = 0b10 i COM0B1: COM0B0 na 0b11.

AKTUALIZACJA

Biorąc pod uwagę, że chcesz przełączyć wyjście tak szybko, jak to możliwe i używasz Mega328 pracującego z częstotliwością 16 MHz, tryb pracy CTC pozwoli ci uzyskać częstotliwość przełączania:

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

Tryb Fast PWM pozwala przełączać pin na:

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

Więc nadal uważam, że chcesz szybkiego trybu PWM. W szczególności tryb 3 z OCR0A = OCR0B = 0x80 dla 50% cyklu pracy. I ustaw bity COM0A na 0x3, a bity COM0B na 0x2, aby utworzyć dwa przebiegi na odwróceniu OC0A i OC0B.

Aktualizacja # 2 Więcej Mega328 Wypróbuj ten kod 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(){

}
vicatcu
źródło
Pozwól mi to trochę przeżuć i sprawdź, czy to działa. Dziękuję Ci.
ExcitingProjects
Po ponownym przeczytaniu twojej odpowiedzi, aby ją wypróbować dzisiaj, widzę kilka nieprawidłowych założeń: podałem zegar 20 MHz (a teraz przełączyłem się na 16 MHz), a nie „(8 MHz to dla ciebie brzmi)” . Podałem również, że nie potrzebuję zmiany szerokości impulsu PWM, więc nie jestem pewien, gdzie się domyślasz „Jeśli chcesz zmienić cykl pracy i brzmi to tak jak Ty” .
ExcitingProjects,
@ExcitingProjects Odrzuciłem twoje stwierdzenie „Na płytce ATTiny85 mam kryształ 8 MHz i to działa niezawodnie”. a moja odpowiedź odnosi się do ATtiny85. Spróbuję zaktualizować odpowiedź w odpowiedzi na zaktualizowane pytanie.
vicatcu
@vicateu Dziękujemy. Zaktualizowałem pytanie, ponieważ tryb inwertowania wydaje się nie działać w trybie CTC, chyba że brakuje mi jakiegoś kroku.
ExcitingProjects
@ExcitingProjects z arkusza danych ATmega328: „W trybach innych niż PWM bity COM0x1: 0 kontrolują, czy dane wyjściowe powinny być ustawione, wyczyszczone lub przełączone podczas porównania”
vicatcu
1

Rodzina ATtinyX5 ma PLL wewnątrz, użyj go, duży chłopcze.

Używam również wewnętrznego PLL do zasilania zegara procesora i mam 16 MHz bez XTAL. Jest to cenne, ponieważ masz tylko 5 pinów. (Nie liczę kodu PIN resetowania). Również jeden PWM (PLCR) PWM (OCR1B) działa na pinach XTAL z opcjonalnym wyjściem komplementarnym. Musisz tylko wyregulować bezpieczniki dla Xtalless ATtiny 16 MHz ... Lub po prostu pozwolić procesorowi pracować na 8 MHz, ale uruchomić PWM z zegarem 64 MHz bez zmiany bezpieczników.

Możesz mieć PWM z zegarem do 64 MHz (ale z rozdzielczością 1-bitową). Lub 125 Khz przy rozdzielczości 8 bitów. Możesz zmniejszyć rozdzielczość PWM i zwiększyć prędkość poprzez zmniejszenie rejestru OCR1C.

Dla 1 Mhz musisz ustawić OCR1C na 63. Dla 2 Mhz musisz ustawić OCR1C na 31. Dla 4 Mhz musisz ustawić OCR1C na 15. ...

Wystarczy włączyć PLL za pomocą tego kodu:

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

Teraz masz 64 MHz zegar na PWM „OCR1B0 / OCR1A0”.

Możesz także ustawić OCR1 [A / B] 0 i XOCR1 [A / B] 0 dla wyjścia lustrzanego.

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

Musisz wiedzieć, że Dead Time Generator zje PWM outout, jeśli ustawisz OCR1A = 1. Potrzebujesz wartości wyższych niż czas martwy.

Pozdrowienia,

Erdem

EUA
źródło