Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> VHDL

Implementación de un controlador PWM en VHDL: Diseño, simulación y demo en FPGA

La modulación por ancho de pulso (PWM) convierte un pin digital de FPGA en un potente controlador analógico. Al conmutar la alimentación entre encendido y apagado a alta velocidad, el PWM entrega la corriente promedio exacta que un dispositivo necesita, sin generar nunca un voltaje analógico real.

Aplicaciones típicas de PWM incluyen salida de audio para altavoces, atenuación de LEDs, y control del par de motores de inducción como servomotores, ventiladores de computadora, bombas y motores DC sin escobillas para vehículos eléctricos.

Ver también: Controlador de servo RC usando PWM desde pin de FPGA

Cómo funciona el PWM

Cuando una fuente de alimentación se conmuta entre 100 % y 0 % a alta frecuencia, la corriente promediada en el tiempo vista por la carga es directamente proporcional a la fracción de tiempo que la fuente está encendida. El siguiente diagrama ilustra el principio:

Implementación de un controlador PWM en VHDL: Diseño, simulación y demo en FPGA

Ciclo de trabajo

El ciclo de trabajo define cuánto tiempo la salida PWM se mantiene alta durante cada período. Expresado como porcentaje, se calcula a partir del valor del contador binario:

Implementación de un controlador PWM en VHDL: Diseño, simulación y demo en FPGA

En una implementación VHDL tratamos el ciclo de trabajo como un entero sin signo, dándonos la resolución completa del contador PWM. Un ciclo de trabajo del 0 % apaga la salida permanentemente, mientras que un 100 % la mantiene continuamente encendida. La resolución alcanzable está determinada por la anchura del contador.

Para convertir el valor binario de ciclo de trabajo a porcentaje, use:

\mathit{duty\_cycle\_percentage} = \frac{\mathit{commanded\_duty\_cycle} * 100}{2^\mathit{pwm\_bits} - 1}

Frecuencia PWM

La frecuencia PWM es el inverso del período:

\mathit{pwm\_freq} = \frac{1}{\mathit{pwm\_period}}

Elegir la frecuencia adecuada depende del dispositivo objetivo. Para LEDs, unos cientos de hercios son suficientes para evitar parpadeo visible. Los motores DC sin escobillas, en cambio, suelen operar en el rango de decenas de kilohercios; una frecuencia demasiado baja puede producir vibraciones mecánicas, mientras que una demasiado alta desperdicia potencia.

Implementación de un controlador PWM en VHDL: Diseño, simulación y demo en FPGA

Como los interruptores MOSFET son más lentos que la lógica del FPGA, operar el PWM demasiado rápido puede hacer que el transistor pase tiempo en un estado parcialmente conductor, disipando calor extra.

Módulo generador PWM

A continuación se muestra una implementación VHDL genérica de un controlador PWM que puede instanciarse con cualquier anchura de contador y factor de división de reloj.

Declaración de entidad

 entity pwm is generic ( pwm_bits : integer; clk_cnt_len : positive := 1 ); port ( clk : in std_logic; rst : in std_logic; duty_cycle : in unsigned(pwm_bits - 1 downto 0); pwm_out : out std_logic ); end pwm; 

Los puertos clk y rst proporcionan control síncrono. La entrada duty_cycle tiene una anchura definida por pwm_bits, por lo que la resolución del contador es directamente configurable. La señal pwm_out se enruta al pin del FPGA que controla la compuerta del MOSFET.

Señales internas

 signal pwm_cnt : unsigned(pwm_bits - 1 downto 0); signal clk_cnt : integer range 0 to clk_cnt_len - 1; 

El contador pwm_cnt refleja la anchura del ciclo de trabajo. El contador clk_cnt implementa un divisor de reloj opcional; establecer clk_cnt_len a 1 desactiva el divisor y elimina la lógica asociada.

Proceso divisor de reloj

 CLK_CNT_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then clk_cnt <= 0; else if clk_cnt < clk_cnt_len - 1 then clk_cnt <= clk_cnt + 1; else clk_cnt <= 0; end if; end if; end if; end process; 

Con el clk_cnt_len = 1 por defecto, las herramientas de síntesis eliminarán este proceso automáticamente.

Proceso de salida PWM

 PWM_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then pwm_cnt <= (others => '0'); pwm_out <= '0'; else if clk_cnt_len = 1 or clk_cnt = 0 then pwm_cnt <= pwm_cnt + 1; pwm_out <= '0'; if pwm_cnt = unsigned(to_signed(-2, pwm_cnt'length)) then pwm_cnt <= (others => '0'); end if; if pwm_cnt < duty_cycle then pwm_out <= '1'; end if; end if; end if; end if; end process; 

El contador incrementa solo cuando clk_cnt es cero, efectivamente limitando la frecuencia PWM. La condicional que resetea pwm_cnt en su penúltimo valor garantiza que un ciclo de trabajo del 100 % sea alcanzable.

\mathit{pwm\_hz} = \frac{\mathit{clk\_hz}}{(2^\mathit{pwm\_bits} - 1) * \mathit{clk\_cnt\_len}}

Diseño de nivel superior

Para demostrar el controlador PWM, el diseño controla el LED de encendido en una FPGA Lattice iCEstick. El oscilador de 12 MHz de la placa alimenta un contador que controla la intensidad del LED en patrón sierra.

Implementación de un controlador PWM en VHDL: Diseño, simulación y demo en FPGA

Declaración de entidad

 entity pwm_led is generic ( pwm_bits : integer := 8; cnt_bits : integer := 25; clk_cnt_len : positive := 47 ); port ( clk : in std_logic; rst_n : in std_logic; led_1 : out std_logic; led_2 : out std_logic; led_3 : out std_logic; led_4 : out std_logic; led_5 : out std_logic ); end pwm_led; 

El reloj de 12 MHz y los genéricos elegidos producen una frecuencia PWM de aproximadamente 1 kHz:
\frac{12e6}{(2^8 - 1) * 47} \approx 1 \text{ kHz}

El genérico cnt_bits impulsa un contador sierra de 25 bits que controla el ciclo de trabajo del LED. Su período es de aproximadamente 2.8 Hz:

\frac{2^{\mathit{cnt\_bits}}}{\mathit{clk\_hz}} = \frac{2^{25}}{12e6} \approx 2.8 \text{ Hz}

Solo se usa el LED 5; los otros LEDs se atan a bajo para evitar iluminación parásita.

Señales internas y cableado

 architecture str of pwm_led is signal rst : std_logic; signal cnt : unsigned(cnt_bits - 1 downto 0); signal pwm_out : std_logic; alias duty_cycle is cnt(cnt'high downto cnt'length - pwm_bits); begin led_1 <= '0'; led_2 <= '0'; led_3 <= '0'; led_4 <= '0'; led_5 <= pwm_out; 

La señal rst es una versión sincronizada, no invertida, del reset externo. El alias duty_cycle mapea los bits más significativos de cnt al controlador PWM.

Instanciación de módulos

 RESET : entity work.reset(rtl) port map ( clk => clk, rst_n => rst_n, rst => rst ); PWM : entity work.pwm(rtl) generic map ( pwm_bits => pwm_bits, clk_cnt_len => clk_cnt_len ) port map ( clk => clk, rst => rst, duty_cycle => duty_cycle, pwm_out => pwm_out ); COUNTER : entity work.counter(rtl) generic map ( counter_bits => cnt'length ) port map ( clk => clk, rst => rst, count_enable => '1', counter => cnt ); 

Simulación

Los genéricos facilitan acelerar la simulación. Reduciendo cnt_bits y clk_cnt_len podemos observar ciclos PWM completos en pocos microsegundos en lugar de varios segundos.

Instanciación del testbench:

 DUT : entity work.pwm_led(str) generic map ( pwm_bits => 8, cnt_bits => 16, clk_cnt_len => 1 ); 

La forma de onda en ModelSim muestra un contador sierra controlando el brillo del LED. Aparece un breve pulso "on" en la punta de cada ciclo cuando el ciclo de trabajo alcanza su valor máximo.

Implementación de un controlador PWM en VHDL: Diseño, simulación y demo en FPGA

Implementación en FPGA

Tras la síntesis con iCEcube2, el diseño consume solo el 5 % de los 64 LUTs disponibles en la parte ice40hx1ktq144:

 Resource Usage Report for pwm_led Mapping to part: ice40hx1ktq144 Cell usage: GND 3 uses SB_CARRY 31 uses SB_DFF 5 uses SB_DFFSR 39 uses SB_GB 1 use VCC 3 uses SB_LUT4 64 uses I/O ports: 7 I/O primitives: 7 SB_GB_IO 1 use SB_IO 6 uses I/O Register bits: 0 Register bits not including I/Os: 44 (3%) Total load per clock: pwm_led|clk: 1 @S |Mapping Summary: Total LUTs: 64 (5%) 

La programación del FPGA por USB con el programador standalone Diamond fue sencilla. La animación LED resultante muestra una rampa de brillo suave seguida de un breve oscurecimiento antes de repetir el ciclo.

Implementación de un controlador PWM en VHDL: Diseño, simulación y demo en FPGA

LED respiratorio con ciclo de trabajo senoidal

Reemplazar el contador sierra con una tabla de búsqueda senoidal produce un efecto "respiratorio" natural, común en LEDs de notificación.

Implementación de un controlador PWM en VHDL: Diseño, simulación y demo en FPGA

En un próximo artículo, mostraremos cómo construir un generador de onda senoidal usando RAM de bloques e integrarlo en el diseño pwm_led.

Lea la siguiente entrada: Cómo crear un efecto LED respiratorio usando una onda senoidal almacenada en RAM de bloques

Ver también: Controlador de servo RC usando PWM desde pin de FPGA

VHDL

  1. Controlador de Potencia PWM: Construye un Driver de Lámpara con Modulación por Ancho de Pulso
  2. Guía paso a paso para cargar condensadores de forma segura y eficiente
  3. Creación de listas de cadenas en VHDL: Buenas prácticas y ejemplo
  4. Creación de un testbench dirigido por Tcl para un módulo VHDL de cerradura por código
  5. Finalizar elegantemente una simulación de testbench VHDL
  6. Generación de números aleatorios en VHDL: De uniforme a OSVVM
  7. Diseño de un búfer circular FIFO robusto en VHDL usando RAM de bloques
  8. Cómo construir un testbench de auto-comprobación en VHDL: Guía práctica
  9. Implementación de lista enlazada dinámica en VHDL con tipos protegidos y punteros de acceso
  10. Aprovechando procedimientos en-proceso para diseños FSM más limpios en VHDL
  11. Dominando funciones VHDL: Guía práctica para diseño eficiente