Uma arquitetura PWM em VHDL

PWM em VHDL

Introdução

Neste artigo vamos implementar um PWM em VHDL. PWM é a abreviação de Pulse Width Modulation ou Modulação por Largura de Pulso. Este circuito é de grande importância e muito utilizado no nosso domínio de estudo, aplicando-se por exemplo para: controle de potência de motores e outras cargas, fontes chaveadas, modulação de sinais como IrDA (Infrared Data Association) e outras aplicações.

A implementação digital deste circuito é vantajosa em relação à implementação analógica devido à diminuição de ruído, tendo em vista que o circuito digital é menos afetado pelas variações de tensão, corrente, temperatura, entre outros fatores. Além disso, tem-se uma grande flexibilidade de especificar a frequência de operação, embarcá-lo e reprogramá-lo.

Em contrapartida, existem algumas limitações como a escolha do Duty Cycle, devido a não se ter uma variação continua deste e sim discreta devido a sua dependência em relação ao relógio (clock).

Princípio de funcionamento do PWM

Em uma frequência fixa pode-se variar o ciclo ativo (Duty Cycle) da onda e com isso tem-se um valor médio de tensão e uma potência entregue à carga controlados pela escolha do Duty Cycle. O valor do ciclo ativo e a tensão média são determinados como segue:

PWM em VHDL - ONDA PWM
Figura 1: Possível forma de onda de um PWM
formula

Para a implementação deste projeto, deve-se pensar no relógio e com isso fazer uma análise discreta do PWM. Na figura abaixo pode-se ver um possível comportamento de um sinal PWM digital que nos ajuda a compreender o que deve ser feito no código.

PWM em VHDL - ONDA PWM DIGITAL
Figura 2: Possível saída de PWM digital

Observando a figura 2 e considerando a entrada TIMER carregada com o valor 15 (isto é, “1111”) e a variável CONTADOR contando as bordas de subida do relógio, então pode-se escolher um valor do Duty Cycle. Desta forma o CONTADOR vai contar até chegar ao valor CYCLE OFF e alterará o estado do PWM para alto, e quando chegar ao valor do TIMER alterará o estado do PWM para baixo e recomeçará a contar de zero. Pode-se notar então que, se o CONTADOR é alterado a cada período do clock não é possível obter uma faixa contínua de 0% à 100% do Duty Cycle. Para ilustrar, a tabela abaixo mostra os possíveis valores do ciclo ativo para esse caso:

Tabela 1: Duty Cycles possíveis para um TIMER de 4 bits

tabela

Poderá surgir a seguinte pergunta: “Não existe Duty Cycle em 0%?” A resposta é sim! O ciclo ativo é nulo quando a entrada ENABLE for zero e não quando DUTY=0. Foi escolhido projetar desta maneira para obter um total aproveitando das escolhas do ciclos ativo.

Exemplo: Ao carregar o TIMER com 1 e o Duty Cycle com zero, teremos a saída do PWM igual a uma onda com frequência metade da frequência do relógio e Duty Cycle 50%; se o Duty vale 1 a saída é 100%; se o ENABLE é ativo saída do PWM é zero. (Imagine agora esse mesmo exemplo com a condição em VHDL “se DUTY=0, saída igual a zero”).

Foi escolhido para o projeto um TIMER e um DUTY de 8 bits flexibilizando a escolha da frequência de trabalho e de Duty Cycles.

Diante do exposto, não é difícil ver que a frequência do PWM pode ser determinada pela fórmula abaixo, onde o valor do TIMER é somado mais 1, pois o TIMER começa em zero, logo conta-se mais 1 pulso do clock.

formula2

Circuito Prescaler

Para melhorar a flexibilidade da frequência do PWM foi implementado o circuito para dividir a frequência do clock, circuito denominado PRESCALER. Foi escolhida a possibilidade de escolher três PRESCALER’s 1, 4 e 16, que são, respectivamente, a frequência do clock original, a frequência dividida por 4 e a frequência dividida por 16. E assim a frequência do PWM pode ser reescrita como segue:

formula3

O esquema abaixo mostra como foi pensado e descrito o código VHDL. Pode-se ver que se o reset não estiver ativo, todos os sinais de clock estão disponíveis no MUX 4:1, onde a entrada SEL_PR de 2 bits seleciona o clock desejado na saída do MUX. Esta entrada determina o PRESCALER da seguinte maneira: SEL_PR = “00” implica PRESCALER = 1; SEL_PR = “01” implica PRESCALER = 4; SEL_PR = “10” implica PRESCALER = 16 e SEL_PR = “00” implica saída de clock zero (opção inválida).

PWM em VHDL - PRESCALER
Figura 3: Esquema do circuito PRESCALER

VHDL PRESCALER

O código da implementação deste circuito foi feito como mostrado em seguida:

TESTBENCH PRESCALER

A seguir tem-se o código do testbench feito usando um clock de entrada em 1MHz.

Abaixo tem-se as formas de ondas encontradas, onde pode-se validar o bom funcionamento do nosso circuito:

PWM em VHDL - Wave Form PRESCALER
Figura 4: Forma de onda do PRESCALER

CIRCUITO PWM

O esquema do projeto final é mostrado abaixo, onde tem-se as entradas TIMER (8 bits), DUTY (8 bits), SEL_PR (2 bits), ENABLE CLK e RST (1 bit), e logicamente a saída do PWM (1 bit). Com o embasamento teórico feito até aqui, pode-se entender/descrever o código facilmente.

PWM em VHDL - ESQUEMA Projeto PWM
Figura 5: Esquema da arquitetura do PWM

VHDL

O código abaixo mostra o que foi feito:

TESTBENCH

Foram feitos os testes, porém devido à gama muito grande de resultados, vamos fazer um exemplo prático para demonstração.

Iremos usar o circuito para gerar um PWM em 38kHz, frequência geralmente usada para modulação de controles remotos em infravermelho, TV, DVD, etc. Portanto, precisamos escolher o PRESCALER e o TIMER.

Considerando um clock de 1MHz e usando o PRESCALER = 1, achamos o valor do TIMER =25.31, seguindo a formula:

formula4

Da mesma maneira se usarmos PRESCALER = 4, achamos o valor do TIMER = 5.57 e para PRESCALER = 16 temos um TIMER = 0.64. Dessa forma, a melhor escolha é o PRESCALER = 1 e carregar o TIMER com 25 (maior resolução).

Como o TIMER deve ser arredondado para um inteiro mais próximo temos um erro na frequência. Ou seja:

formula5

De qualquer maneira, mesmo não tendo a frequência perfeitamente em 38kHz, esse resultado é bem aceitável para aplicações práticas, como a do nosso exemplo de modular sinal de controle remoto nessa frequência.

O test bench feito para esse exemplo é mostrado abaixo, onde foi variado o Duty Cycle a cada período do PWM, exemplificando todos os casos de Duty.

Pode-se ver na figura gerada o círculo vermelho mostrando o período de PWM esperado. Além disso, a modulação do sinal.

PWM em VHDL - Forma de onda do PWM em 38kHz variando Duty Cycle
Figura 6: Forma de onda do PWM em 38kHz variando Duty Cycle

INTERESSANTE

Abaixo é mostrado um esquema de PWM retirado do datasheet do microcontrolador PIC16F877A. Pode-se ver registradores para Duty Cycle, o TIMER (TMR2) e comparadores, que de modo geral é similar ao que foi feito nesse projeto.

Dessa forma podemos ter uma ideia do que acontece “por trás” do código C, quando necessitamos de usar uma saída PWM de um microcontrolador por exemplo, ganhando confiança ao programá-lo e ficando sensíveis aos possíveis erros de programação. Vamos estudar HDL!

Diagrama simplificado de PWM PIC16F877A
Figura 7: Diagrama simplificado de PWM PIC16F877A

Espero que tenham gostado do artigo! Até a próxima!

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Hardware, Sistemas Digitais
,
Comentários:
Notificações
Notificar
guest
13 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Doulgas
Doulgas
15/01/2021 21:00

@Grabiel
tentei rodar o seu código, e apareceu o seguinte erro:
Error (10533): VHDL Wait Statement error at TB_PWM.vhd(40): Wait Statement must contain condition clause with UNTIL keyword
a linha 40 no código é: wait for 1250 ns;
O que pode ser isso?

cleiton dal agnol
cleiton dal agnol
29/07/2018 22:33

Sou novo no assunto, porém estou me aprofundando o máximo que posso. Minha dificuldade foi em gerar um pwm de 50 KHz, ao compilar da um erro do TimeQuest e de design. Alguém poderia me dar algumas dicas?

Euripedes Filho
Euripedes Rocha Filho
29/02/2016 07:48

Pode ser um exercício interessante transformar esse testbench em um testbench automatizado.

Vinicius Lagrota
Vinicius Lagrota
25/02/2016 11:26

Ótima matéria! Trabalho com HDL desde o começo da minha graduação e continuo utilizando no meu mestrado e acho sempre interessante quando esse tipo de linguagem ganha espaço em um site grande como este! Parabéns aos envolvidos e que venham mais matérias como está!

André Castelan
24/02/2016 19:10

Eu utilizava muito o MyHDL, nao utilizo mais pois nao estou trabalhando com FPGA no momento.

Recomendo de mais.

Caio Alonso
Caio Alonso
24/02/2016 19:07

Obrigado por compartilhar os artigos André.
É interessante a abordagem da utilização de variáveis na solução do algoritmo do código gray. Eu, particularmente, tenho receio do que o compilador interpreta e transforma em circuito. Concordo que os compiladores estão muito mais eficientes hoje em dia e que talvez não fosse necessário se preocupar com isso, mas a pulga sempre fica atrás da orelha. Não conheço o MyHDL. Vocês utilizam essa linguagem?

André Castelan
24/02/2016 17:47

Usar variaveis de forma correta eh excelente, nao tenham medo da ferramenta. Otimos artigos: http://www.jandecaluwe.com/hdldesign/thinking-software-rtl.html http://www.jandecaluwe.com/hdldesign/the-case-for-a-better-hdl.html Variables are one of the best understood programming concepts, and they are supported by both Verilog and VHDL. Nevertheless, even though mainstream HDL design is more than 20 years old, HDL designers still haven’t figured out how to use variables properly. Instead of teaching how to use variables, mainstream Verilog guidelines ban them altogether (in clocked processes). Thus, the confusion is “solved” by brute force amputation. In reality, local variables work just fine in clocked processes and synthesis supports them without a problem. They… Leia mais »

Gabriel Villanova Novaes Magalhães
Gabriel Villanova
24/02/2016 17:01

Caio,
Muito obrigado pelo feedback.
Eu estou de acordo, quando
escrevemos sinais ao invés de variáveis podemos ter mais controle do que
será sintetizado, além disso, meio que repetindo o que você já disse,
não temos necessidade de utilizar variáveis, afinal de contas tudo é
bit.
Bom, como o artigo está a nível de “tutorial” escolhi fazer dessa forma pra explorar a linguagem.
Estou aberto a discussões sobre o assunto!

Caio Alonso
Caio Alonso
24/02/2016 12:52

Parabéns pelo artigo Gabriel.
Só queria deixar uma observação quanto a utilização de variáveis em processos deve ser utilizada com cautela. Algumas ferramentas de síntese podem inferir um circuito não desejável.
Eu, particularmente, evito o máximo a utilização de variáveis para deixar o código RTL mais independente do tipo de software de síntese. Até o momento não tive que desenvolver algum código em que fui obrigado a utilizar variáveis. Aproveito para abrir uma discussão sobre a utilização de sinais e variáveis em processos de VHDL.
Quais são as opniões de vocês?

Euripedes Filho
Euripedes Rocha Filho
Reply to  Caio Alonso
29/02/2016 07:46

Como colocado pelo @andrecas:disqus, não vejo qualquer problema em usar variáveis desde que se saiba descrever o circuito. Utilização de variáveis no código não vai torná-lo mais dependente IMHO. Uma coisa que me irrita bem mais é o impacto do circuito de reset na hora de portar entre Xilinx e Altera por exemplo. Mas mesmo isso no fim das contas não deve ser uma barreira pra portabilidade entre os dois principais players.

Caio Alonso
Caio Alonso
Reply to  Euripedes Rocha Filho
29/02/2016 19:35

Obrigado por compartilhar sua opinião Euripedes! Um artigo sobre metodologias de reset em projetos de circuitos digitais (síncrono e assíncrono) seria bem interessante!

André Castelan
Reply to  Caio Alonso
29/02/2016 19:39

http://embarcados.com.br/arquitetura-reset-fpga/

😛

com certeza o Euripedes poderia escrever mais ( e melhor )

Caio Alonso
Caio Alonso
Reply to  André Castelan
29/02/2016 19:47

Desculpe-me o desconhecimento do artigo. Acho que estou precisando aprender a fazer buscas melhores no site. 😎

Talvez você goste:

Séries

Menu

EVENTO ONLINE

Simplificando seus projetos de Internet das coisas com o iMCP HT32SX Sigfox

DATA: 18/05 às 15:00h