1
\$\begingroup\$

I want to create Led PWM controller and I tought it is easy but one line in my code generates more warnings than all my previous little projects. Here is the code:

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;

The problematic line is :

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

All the warnings:

WARNING:HDLCompiler:92 - "E:\Xilinx\Projects\PWM_LED\pwmLed.vhd" Line 48: counter should be on the sensitivity list of the process

WARNING:Xst:647 - Input is never used. This port will be preserved and left unconnected if it belongs to a top-level block or it belongs to a sub-block and the hierarchy of this sub-block is preserved.

WARNING:Xst:3002 - This design contains one or more registers/latches that are directly incompatible with the Spartan6 architecture. The two primary causes of this is either a register or latch described with both an asynchronous set and asynchronous reset, or a register or latch described with an asynchronous set or reset which however has an initialization value of the opposite polarity (i.e. asynchronous reset with an initialization value of 1).

WARNING:Xst:1426 - The value init of the FF/Latch counter_31_LD hinder the constant cleaning in the block pwmLed. You should achieve better results by setting this init to 0.

WARNING:Par:288 - The signal pwm<0>_IBUF has no load. PAR will not attempt to route this signal.

WARNING:Par:288 - The signal pwm<1>_IBUF has no load. PAR will not attempt to route this signal.

WARNING:Par:288 - The signal pwm<2>_IBUF has no load. PAR will not attempt to route this signal.

WARNING:Par:288 - The signal pwm<3>_IBUF has no load. PAR will not attempt to route this signal.

WARNING:Par:283 - There are 4 loadless signals in this design. This design will cause Bitgen to issue DRC warnings.

WARNING:PhysDesignRules:372 - Gated clock. Clock net counter[31]_GND_4_o_LessThan_1_o is sourced by a combinatorial pin. This is not good design practice. Use the CE pin to control the loading of data into the flip-flop.

I understand them but I got no idea why they occur. I use pwm explicitly so why the warning that this input is never used.

\$\endgroup\$
  • \$\begingroup\$ Your using a Spartan 6? \$\endgroup\$ – Spoon Nov 8 '14 at 20:30
  • \$\begingroup\$ Where do you set the port as output? \$\endgroup\$ – Spoon Nov 8 '14 at 20:31
  • \$\begingroup\$ Yes it is Spartan 6. Where do I set the port as output ? What do you mean ? \$\endgroup\$ – Al Bundy Nov 8 '14 at 21:15
  • \$\begingroup\$ If you use "View RTL Schematic" you'll see that synthesis has dropped whatever is not recognized/supported. \$\endgroup\$ – mng Nov 10 '14 at 20:35
1
\$\begingroup\$

You are performing a division and a multiplication operation on a signal. At least the multiplication is mapped to a hardware multiplication circuit on your FPGA.

Your module provides the generic parameter N, which could also be called PWM_RESOLUTION. Beside this, I miss two additional parameters or constants in your module:

  1. The clock frequency of the system clock
  2. The pwm output frequency [Notice: don't forget that pwm signals have a fixed frequency but variable duty cycle.]

One easy way to build a pwm generator is to use two counters:

  • Counter 1 is a frequency divider, which divides the system clock into \$2^N \cdot f_{pwm}\$ Hz
  • Counter 2 counts \$2^N\$ cycles on every tick from counter 1

Here some calculations for the frequency counter:

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');

Some hints on the compact code above:

  • freq is a new physical type representing a frequency - you can also use the real type
  • to_period converty a frequency into a period (a time)
  • TimingToCyles is a function which calculates how many cycles must pass until a given timing (period) has elapsed at a given circuit frequency.
  • log2ceilnz (logarithm dualis, round up, not zero) calculates \$max(1, \lceil log_2(x)\rceil)\$

Example 1:
If N=4 the pwm signal can have 16 duty cycle steps. Counter 1 is running at 400 kHz. This equals a period of 2.5 us, which need 250 cycles at 100 MHz to achieve this timing. A 8 bit signal is needed for counter 1.

The output is then a simple comparison:

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

This code does not prohibit the input of PWMIn=0 to produce a flat-line output, which would not be a correct pwm signal (100% low, 0% high, no edges -> no frequency)

Example 2:
If PWMIn is 3 ("0011") then PWMOut is '1' for counter values 0,1,2 else '0'.

\$\endgroup\$
  • \$\begingroup\$ I understand your idea it is really good. Referring you your first sentence I am not allowed to perform division and a multiplication operation on a signal explicitly ?? \$\endgroup\$ – Al Bundy Nov 11 '14 at 22:32
  • \$\begingroup\$ Yes you can write these operations in vhdl, but I think it was not your intention to use masses of FPGA resources :) if the synthesis tool is smart it will recognize, that your division by 2**N can be replaced by a shift operation, but at least the multiplication needs a hardware multiplier or if the input value is small it can be translated into a ROM / LookupTable. So I think using some synthesis time constant 'calculation magic', 2 counters and a comparator is one of the cheapest and most flexible solutions. \$\endgroup\$ – Paebbels Nov 12 '14 at 0:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.