controlador PWM LED

1

Quiero crear un controlador PWM de Led y creo que es fácil, pero una línea en mi código genera más advertencias que todos mis pequeños proyectos anteriores. Aquí está el código:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity pwmLed is
generic(    N : integer := 4
);
port( pwm : in std_logic_vector(N-1 downto 0);
        clk : in std_logic;
        leds : out std_logic_vector(7 downto 0)
);
end pwmLed;

architecture Behavioral of pwmLed is
constant CLOCK_CYCLES : integer := 1000;
signal counter : integer ;
begin

process(clk)
begin
    if counter > CLOCK_CYCLES then
        counter <= 0;
    elsif (clk'event and clk = '1') then
        counter <= counter + 1;
    end if;
end process;

leds <= "11111111" when counter < (to_integer(unsigned(pwm))/(2**N) * CLOCK_CYCLES) else "00000000";
end Behavioral;

La línea problemática es:

leds <= "11111111" when counter < (to_integer(unsigned(pwm))/(2**N) * CLOCK_CYCLES)  else "00000000";

Todas las advertencias:

ADVERTENCIA: HDLCompiler: 92 - "E: \ Xilinx \ Projects \ PWM_LED \ pwmLed.vhd" Línea 48: el contador debe estar en la lista de sensibilidad del proceso

ADVERTENCIA: Xst: 647 - La entrada nunca se usa. Este puerto se conservará y se dejará desconectado si pertenece a un bloque de nivel superior o pertenece a un subbloque y se conserva la jerarquía de este subbloque.

ADVERTENCIA: Xst: 3002: este diseño contiene uno o más registros / cierres que están directamente    Incompatible con la arquitectura Spartan6. Las dos causas principales de esto es    ya sea un registro o pestillo descrito con un conjunto asíncrono y    reinicio asíncrono, o un registro o cierre descrito con un asíncrono    establecer o restablecer que sin embargo tiene un valor de inicialización del contrario    polaridad (es decir, reinicio asíncrono con un valor de inicialización de 1).

ADVERTENCIA: Xst: 1426 - El valor init del FF / Latch counter_31_LD dificulta la limpieza constante en el bloque pwmLed.    Debería obtener mejores resultados estableciendo este inicio en 0.

ADVERTENCIA: Par: 288 - La señal pwm < 0 > _IBUF no tiene carga. PAR no intentará enrutar esta señal.

ADVERTENCIA: Par: 288 - La señal pwm < 1 > _IBUF no tiene carga. PAR no intentará enrutar esta señal.

ADVERTENCIA: Par: 288 - La señal pwm < 2 > _IBUF no tiene carga. PAR no intentará enrutar esta señal.

ADVERTENCIA: Par: 288 - La señal pwm < 3 > _IBUF no tiene carga. PAR no intentará enrutar esta señal.

ADVERTENCIA: Par: 283 - Hay 4 señales sin carga en este diseño. Este diseño hará que Bitgen emita advertencias de DRC.

ADVERTENCIA: PhysDesignRules: 372 - Reloj cerrado. Red de reloj    counter [31] _GND_4_o_LessThan_1_o se obtiene mediante un pin combinatorio. Esto es    No es una buena práctica de diseño. Utilice el pin CE para controlar la carga de datos en    el flip-flop.

Los entiendo pero no tengo idea de por qué ocurren. Utilizo pwm explícitamente, por eso la advertencia de que esta entrada nunca se usa.

    
pregunta Al Bundy

1 respuesta

1

Está realizando una división y una operación de multiplicación en una señal. Al menos la multiplicación se asigna a un circuito de multiplicación de hardware en su FPGA.

Su módulo proporciona el parámetro genérico N, que también podría llamarse PWM_RESOLUTION. Además de esto, echo de menos dos parámetros o constantes adicionales en su módulo:

  1. La frecuencia de reloj del reloj del sistema
  2. La frecuencia de salida pwm [Aviso: no olvide que las señales pwm tienen una frecuencia fija pero un ciclo de trabajo variable.]

Una forma fácil de construir un generador pwm es usar dos contadores:

  • El contador 1 es un divisor de frecuencia, que divide el reloj del sistema en \ $ 2 ^ N \ cdot f_ {pwm} \ $ Hz
  • El contador 2 cuenta \ $ 2 ^ N \ $ ciclos en cada tick del contador 1

Aquí algunos cálculos para el contador de frecuencia:

constant PWM_FREQ          : freq     := 25 kHz;
constant SYSTEM_CLOCK_FREQ : freq     := 100 MHz;

constant STEPS             : positive := 2**N;
constant STEP_FREQ         : freq     := PWM_FREQ * STEPS;
constant FREQ_COUNTER_MAX  : positive := TimingToCycles(to_period(STEP_FREQ), SYSTEM_CLOCK_FREQ);
constant FREQ_COUNTER_BITS : positive := log2ceilnz(FREQ_COUNTER_MAX);

signal Freq_Counter  : unsigned(FREQ_COUNTER_BITS - 1 downto 0) := (others => '0');
signal Pulse_Counter : unsigned(N - 1 downto 0)                 := (others => '0');

Algunos consejos sobre el código compacto anterior:

  • freq es un nuevo tipo físico que representa una frecuencia, también puede usar el tipo real
  • to_period convierte una frecuencia en un período (un tiempo)
  • TimingToCyles es una función que calcula cuántos ciclos deben transcurrir hasta que haya transcurrido un tiempo (período) dado en una frecuencia de circuito determinada.
  • log2ceilnz (logaritmo dualis, redondeo hacia arriba, no cero) calcula \ $ max (1, \ lceil log_2 (x) \ rceil) \ $

Ejemplo 1:
Si N = 4, la señal pwm puede tener 16 pasos de ciclo de trabajo. El contador 1 está funcionando a 400 kHz. Esto equivale a un período de 2.5 us, que necesita 250 ciclos a 100 MHz para lograr este tiempo. Se necesita una señal de 8 bits para el contador 1.

La salida es entonces una comparación simple:

PWMOut <= to_sl(PulseCounters < unsigned(PWMIn));

Este código no prohíbe que la entrada de PWMIn = 0 produzca una salida de línea plana, lo que no sería una señal pwm correcta (100% bajo, 0% alto, sin bordes, > sin frecuencia)

Ejemplo 2:
Si PWMIn es 3 ("0011"), PWMOut es '1' para valores de contador 0,1,2 en caso contrario '0'.

    
respondido por el Paebbels

Lea otras preguntas en las etiquetas