Precisa de ajuda para entender a saída espelhada do temporizador AVR ATMEGA / ATTINY

10

Estou tentando usar o microcontrolador Timer1 do Atmel AVR, o AtMega328, usado no Arduino ou no ATTiny85, para emitir dois sinais de relógio que são imagens espelhadas um do outro. A frequência que estou tentando gerar é uma variável de 1 MHz a 2 MHz ou mais, que é muito alta para fazer isso usando o código para alternar os pinos de saída, a menos que eu queira fazer quase nada mais no controlador. Então, eu quero usar a saída do timer diretamente nos pinos associados. Estou usando o conjunto de ferramentas GCC, portanto não limitado por bibliotecas ou idioma do arduino.

O Timer1 no Atmega328 possui dois pinos associados e posso obter dois sinais idênticos de 1MHz a 2MHz. Embora a folha de dados pareça dizer que posso obter uma forma de onda invertida, ela está me confundindo. Também consigo obter dois sinais com ciclos de trabalho diferentes a 1 MHz, usando as configurações de PWM com Timer1, mas ambos os sinais aumentam ao mesmo tempo, o menor diminui mais cedo. Isso não serve ao meu projeto. Eu nem preciso da variação da largura de pulso PWM, só preciso de dois sinais idênticos do tipo "relógio" de fase oposta, isso é tudo.

Não estou pedindo que alguém escreva código para fazer isso, só preciso que alguém me diga qual modo / sinalizadores do timer devem fornecer uma forma de onda invertida simples em um dos dois pinos associados ao timer. Se possível, quero evitar o uso de um circuito inversor externo para uma das saídas, a menos que seja a única opção.

Se isso for possível no ATTiny, será ainda melhor. O ATTiny também possui 2 pinos associados a um timer, mas não tenho certeza de que tenha as mesmas opções que o ATMega.

Eu já tenho um cristal de 20 MHz e os capacitores conectados no PCB e o relógio de 20 MHz está funcionando de maneira confiável no ATMega328. No PCB ATTiny85, tenho um cristal de 8 MHz e isso também está funcionando de maneira confiável.

Por favor ajude. Obrigado.


ATUALIZAÇÃO : Existem algumas suposições inválidas nas respostas e comentários até agora, então talvez eu deva esclarecer: Observe que na minha postagem original afirmei que estou usando um relógio de 20 MHz, não 8 MHz , e também que não preciso de PWM .

O único modo que fornece uma frequência de saída suficientemente alta parece ser o modo CTC porque os modos PWM não estão funcionando para saída de 2 MHz. Existe uma maneira de inverter a saída A do temporizador 1 ou a saída B no modo CTC?

Agora mudei para um Arduino Uno padrão (ATMega328, 16 MHz) em vez de minha própria placa de 20 MHz para verificar meu código, e este é o meu código para um bom e estável relógio de 2 MHz no modo CTC dos pinos 9 e 10, o Timer 1 pinos de saída:

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

Os traços do osciloscópio para os dois pinos são idênticos e sincronizados. Como posso inverter um dos dois sinais? O modo invertido na folha de dados parece não fazer nada no modo CTC. Estou lendo a folha de dados incorretamente ou serei forçado a usar uma frequência mais baixa e o modo PWM, afinal?

Para adicionar uma pergunta específica de "recompensa" à minha consulta original:
Então, quais alterações eu preciso fazer no meu código acima, para que ele produza sinais perfeitamente invertidos nos pinos 9 e 11 na frequência mais alta possível para um relógio de 16 MHz , seja isso é 2 MHz ou não?

Por enquanto, continuarei com um Arduino Uno padrão, para que não haja um modo de erro sendo introduzido pela minha placa caseira, e para que qualquer pessoa com um arduino possa experimentar o meu código acima e confirmar que funciona como eu mencionei e não como eu. precisar!

ExcitingProjects
fonte
11
Olhando para a página 97-98 da folha de dados do atmega8L , há uma tabela dos modos de operação. A página 108 afirma "Os bits COM21: 0 controlam se a saída PWM gerada deve ser invertida ou não (PWM invertida ou não invertida)". Mantenha-nos informados sobre o seu sucesso!
Vorac #
Por que não usar um inversor de transistor simples para as saídas mirrorred?
Jonny B Bom

Respostas:

10

Da folha de dados do ATtiny85:

O modo de operação, ou seja, o comportamento dos pinos do timer / contador e de comparação de saída, é definido pela combinação do modo de geração de forma de onda (WGM0 [2: 0]) e modo de saída de comparação (COM0x [1: 0]) bits. Os bits do modo Compare Output não afetam a sequência de contagem, enquanto os bits do modo Waveform Generation. Os bits COM0x [1: 0] controlam se a saída PWM gerada deve ser invertida ou não (PWM invertido ou não invertido ).

A Tabela 11-5 mostra como definir o modo.

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

Você deseja um modo Fast PWM (modo 3 ou 7). Se você deseja alterar o ciclo de serviço, e isso soa como você deseja, você deseja o modo 7 e varia o ciclo de trabalho configurando OCRA.

A Tabela 11-3 mostra como definir o modo de saída de comparação para o modo Fast 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)

Ou seja, você pode configurar a saída OC0A para baixa quando o valor do Timer == OCR0A e alta quando o valor do Timer == 0x00 configurando COM0A1: COM0A0 = 0b10. Ou vice-versa, definindo COM0A1: COM0A0 = 0b11. E da mesma forma para OC0B, OCR0B, COM0B0, COM0B1.

A frequência PWM é determinada pelo I / O Clock (8MHz soa para você) e pela configuração do seu pré-temporizador. E a equação é dada como f_clk_IO / (N * 256) para o modo Fast PWM.

Portanto, você pode usar OC0A para polaridade "normal" e OC0B para polaridade "invertida" configurando OCR0A e OCR0B para o mesmo valor e configurando COM0A1: COM0A0 = 0b10 e COM0B1: COM0B0 para 0b11.

ATUALIZAR

Como você deseja alternar a saída o mais rápido possível e estiver usando o Mega328 operando em 16 MHz, o modo de operação CTC permitirá obter uma frequência de comutação de:

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

O modo Fast PWM permite alternar o pino em:

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

Então, eu ainda acho que você quer o modo Fast PWM. Especificamente o Modo 3 com OCR0A = OCR0B = 0x80 para um ciclo de trabalho de 50%. E defina os bits COM0A para 0x3 e os bits COM0B para 0x2 para criar as duas formas de onda nas inversões OC0A e OC0B.

Atualização # 2 Mais o Mega328 Experimente o código do 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
fonte
Deixe-me pensar um pouco e ver se funciona. Obrigado.
precisa
Depois de reler sua resposta para testá-la hoje, vejo algumas suposições inválidas: especifiquei o relógio de 20 MHz (e agora mudei para 16 MHz), não "(8MHz soa para você)" . Também especifiquei que não preciso de variação da largura de pulso do PWM, portanto, não sei onde você imaginou "Se você deseja variar o ciclo de trabalho e parece que você precisa " .
ExcitingProjects
@ExcitingProjects Eu estava encerrando sua declaração "No PCB ATTiny85, tenho um cristal de 8 MHz e isso também está funcionando de maneira confiável". e minha resposta está em referência ao ATtiny85. Vou tentar atualizar minha resposta em resposta à sua pergunta atualizada.
vicatcu
@vicateu Obrigado. Atualizei a pergunta, visto que o modo invertido parece não ter efeito no modo CTC, a menos que esteja faltando alguma etapa.
precisa
@ExcitingProjects da folha de dados do ATmega328: "Para modos não PWM, os bits COM0x1: 0 controlam se a saída deve ser definida, limpa ou alternada em uma comparação"
vicatcu
1

A família ATtinyX5 tem PLL por dentro, use-o como garotão.

Eu uso o PLL interno para alimentar o clock da CPU também e tenho 16Mhz sem o XTAL. Isso é precioso, pois você tem apenas 5 pinos. (Não conto o pino de redefinição). Também um PWM com PLL (OCR1B) é executado nos pinos XTAL com sua saída complementar opcional. Você só precisa ajustar os fusíveis para 16Mhz Xtalless ATtiny ... Ou apenas deixar a CPU rodar em 8Mhz, mas rodar o PWM com um relógio de 64Mhz sem trocar os fusíveis.

Você pode ter um relógio PWM de até 64 Mhz (mas com resolução de 1 bit). Ou 125Khz a 8 bits de resolução. Você pode reduzir a resolução PWM e aumentar a velocidade diminuindo o registro OCR1C.

Para 1 Mhz, você precisa definir OCR1C para 63. Para 2 Mhz, você precisa definir OCR1C para 31. Para 4 Mhz, você precisa definir OCR1C para 15. ...

Basta ativar a PLL com este código:

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

Agora você tem um relógio de 64 MHz nos PWMs "OCR1B0 / OCR1A0".

Além disso, você pode ajustar OCR1 [A / B] 0 e XOCR1 [A / B] 0 para saída espelhada.

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

Você precisa saber, o Dead Time Generator interromperá o PWM se você definir OCR1A = 1. Você precisa de valores mais altos que o tempo morto.

Saudações,

Erdem

EUA
fonte