quarta-feira, 20 de maio de 2015

Ajustando a frequência dos PWMs do arduino Leonardo parte 2

Fazendo uma abordagem mais completa, esse post visa completar o anterior que fala sobre o mesmo assunto.

Desta vez, a intenção é definir a frequência de 4 pinos PWM. A motivação para este post vem para ser usado em projetos em que seja necessário ter uma frequência diferente da padrão dos pinos do arduino (490 Hz para os pinos 5, 6, 9, 10, 13 e 980 Hz para os pinos 3 e 11), como por exemplo o acionamento de motores DC sem que sejam gerados ruídos audíveis ou para gerar sons com certos tons, que são definidos cada um por uma certa frequência.

Nesse caso, usaremos os pinos 5, 6, 11 e 13 do arduino Leonardo. Cada pino na sua função de PWM, porém, é controlado por registradores comparadores diferentes, e esses registradores estão cada um vinculados a um dos timers do microcontrolador do arduino. Mas não temos um registrador apenas em cada pino, alguns deles possuem 2 registradores e podemos configurar com qual deles queremos trabalhar. Podemos ver essas informações observando no esquema elétrico do arduino Leonardo:

Peguemos o pino IO 11 do arduino, associado ao PB7 do microcontrolador ATMEGA 32u4 como exemplo. Nas suas características internas, temos as seguintes informações: (PCINT7 /OC0A /OC1C /#RTS). OC0A e OC1C são as saídas relacionadas aos registradores OCR0A e OCR1C, vinculados aos timer 0 e 1 respectivamente, logo então, podemos definir qual dos 2 definirá as características do PWM no pino 11, ou até fazê-los trabalharem juntos. A vantagem de podermos fazer essa escolha se dará pelo fato de não precisarmos editar os parâmetros do timer 0, pois as funções millis(), micros(), delay() e delayMicroseconds() estão atreladas a esse timer, e, ao mudar as configurações do timer 0, estaremos mudando os parâmetros de todas essas funções.

Também temos outras bibliotecas que utilizam os parâmetros dos timers, como a biblioteca Servo (que utiliza parâmetros do timer 1) e a biblioteca MsTimer2 (que utiliza parâmetros do timer 4). Logo, caso você precise utilizar alguma dessas bibliotecas, evite manusear os timers em questão.

Podemos configurar o PWM para trabalhar de duas formas: em sngle-slope ou em dual-slope.
Os timers trabalham como contadores, que vão somando valores nos seus registradores conforme o clock interno do microcontrolador, e o que ocorre quando o contador atinge o seu valor máximo é o que difere as duas formas de PWM.

Single-Slope: No caso do single-slope, quando o contador atinge o valor máximo, o mesmo é zerado e volta a contar do zero. Quando temos um valor de comparação no registrador, o valor de saída é alterado quando o valor do contador é igual ao valor do registrador e quando o contador volta a zero, como no exemplo abaixo:
Os valores do PWM 1 e 2 vão ao estado baixo quando o valor de referência é igual ao do contador e vão ao estado alto quando o contador volta para zero.

Double-Slope: No caso do double-slope, o contador ao chegar no valor máximo começa a decrescer, ao invés de voltar a zero, como no single-slope. Assim, os valores de saída são alterados quando o contador tem o mesmo valor dos registradores na subida e na descida.
Os valores de PWM 1 e 2 são alterados vão para o estado alto quando o contador atinge o valor do registrador na borda de descida, e vão para o estado baixo quando o contador atinge o valor do registrador na borda de subida.


Para o nosso exemplo, configuraremos os pinos 5, 6, 11 e 13 para trabalhar com uma frequência de 31,3 kHz, configurados no modo dual-slope. Os registradores usados para cada pino serão o OCR3A do timer 3 para o pino 5, o OCR4D do timer 4 para o pino 6, o OCR1C do timer 1 para o pino 11 e o OCR4A do timer 4 para o pino 13. Nota-se que para o pino 6 e 13 serão usados registradores relacionados ao mesmo timer, logo as configurações dos 2 são as mesmas.

Os timers 1 e 3 são idênticos em suas características, então as suas configurações serão relativamente parecidas.

Configurando timer 1 e 3:


Os nomes dos bits a seguir são relacionados ao timer 1, mas a nomenclatura para o timer 3 muda em detalhes como, por exemplo o bit WGM10 para o timer 1, será o WGM30 para o timer 3.
Abaixo temos em detalhes os registradores de controle do timer 1:




Para os valores COM1A0 e COM1A1,  COM1B0 e COM1B1 e COM1C0 e COM1C1 teremos as configurações para o registrador OCR1A, OCR1B e OCR1C respectivamente. As configurações são selecionadas conforme a tabela abaixo:



Os valores dos WGM10, WGM11, WGM12 e WGM13 definirão se trabalharemos em single-slope ou dual-slope, com 8, 9 ou 10 bits de contador ou em CTC (clear time on compare) conforme a tabela abaixo:


Os valores de CS10, CS11 e CS12 definirão a divisão do valor da frequência máxima escolhida, 31,3kHz para o modo dual-slope (PWM phase correct) e 62,5 kHz para o single-slope (fast PWM):



Configurando timer 4:


Usando o timer 4, podemos chegar a uma frequência de até 96 MHz, utilizando o registrador de controle PLL (PLLFRQ), mas no nosso caso esse registrador não será alterado. Caso for usar esse registrador, as comunicações USB podem ser comprometidas.

As configurações para o timer 4 são um pouco diferentes em comparação às dos timers 1 e 3. Teremos que configurar 4 registradores para esse timer. 
Começaremos pelos TCCR4A e TCCR4C:



Antes de tudo, temos que habilitar os bits PWM4A, PWM4B e PWM4C, dependendo dos registradores que queremos usar, e depois utilizar as configurações abaixo para habilitar os registradores:


Para habilitar os registradores OCR4B e OCR4D, é só usar a tabela acima, considerando a letra relacionada ao registrador.


No TCCR4B, escolheremos a divisão da frequência máxima escolhida conforme a tabela:



No TCCR4D, escolheremos a forma do PWM dos registradores ligados ao timer 4 conforme as opções abaixo:





Abaixo segue um exemplo de código, que acende 4 leds com sinal PWM com frequência de 31,5 kHz. O sinal PWM será definido de acordo com 2 entradas analógicas distintas na porta A0 e A1.

 /*****************************************
 Timers 1, 3 e 4 configurados para trabalhar com uma frequência de PWM de 31,3 kHz

 Os pinos 13, 11, 6 e 5 estão cada um ligados a um registrador um timer. O valor atribuido
 aos registradores será equivalente ao sinal de PWM da porta correspondente.

 Alguns pinos não trabalham tão bem com a função analogWrite() depois das alterações de 
 parâmetros dos timers, sendo assim melhor não utilizá-la.
Editado em 19/05/2015 
 *******************************************/
 
 #define PWM11  OCR1C //ALI-M2
 #define PWM13  OCR4A //BLI-M1
 #define PWM6  OCR4D //ALI-M1
 #define PWM5  OCR3A //BLI-M2
 #define frequencia  1 // 31,3 kHz

void setup() {
  // put your setup code here, to run once:
  pinMode(13, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  
TCCR1A= 0x09; //Configurado canal OCR1C para funcionar como comparador e PWM com 8 bits de resolução
TCCR1B= frequencia; // frequencia definida no #define - 31,3 kHz

TCCR3A = 0x81; //Configurado canal OCR3A para funcionar como comparador e PWM com 8 bits de resolução
TCCR3B= frequencia; // frequencia definida no #define - 31,3 kHz 

TCCR4A = 0x82; //Configurado canal OCR4A para funcionar como comparador e habilita o mesmo
TCCR4B = frequencia; // frequencia definida no #define - 31,3 kHz
TCCR4C = 0x89; //Configurado canal OCR4D para funcionar como comparador e habilita o mesmo
TCCR4D = 1; //Configurada a forma de PWM (fast ou normal)

PWM13 = 0;
PWM11 = 0;
PWM6 = 0;
PWM5 = 0;
}

void loop() {
  // put your main code here, to run repeatedly:
    
  PWM13 = map(analogRead(A0), 0, 1023, 0, 255); 
  PWM11 = map(analogRead(A0), 0, 1023, 0, 255); 
  PWM6 = map(analogRead(A1), 0, 1023, 0, 255); 
  PWM5 = map(analogRead(A1), 0, 1023, 0, 255);  

}


Referências: Fast PWM on Arduino Leonardo e ATmega 32u4 Datasheet

Um comentário: