Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] How to receive PWM and edit it ?

Status
Not open for further replies.

abimann

Member level 4
Joined
Jun 21, 2016
Messages
77
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
673
In arduino so easy to receive PWM signal and edit it , and so many documentation, But in FPGA VHDL , I cannot find it .. Could someone help me to deal with it ?

PWM coming in std_logic, and how to make it std_logic_vector and edit this ?
 

Hi,

You mean PWM = pulse width modulation?

If so, what to you mean with "receive"?
And "edit" it in which way?

With PWM one usually controls the speed of a DC motor, the brightness of a lamp....

A picture and a good description could help to clarify things.

Klaus
 

Yes it is Pulse Width Modulation, for example i have output from controller is from 1000 to 2000 impulses, ie PWM impulses, but my motor can get only from 1440 to 1850 impulses, so , to adopt it I just divide PWM from Controller to 2.7 and add 1063,,, ( pwm_in / 2.7) + 1063,,..
I have idea to convert std_logic (pwm impulses) to integer and count it , and edit it , like above and then somehow convert it to pwm output..How to convert it to std_logic again ?
 

Be very careful with wording here:

PWM implied the WIDTH of the pulses is modulated but not how frequent they are. You say the controller produces 1000 to 2000 impulses which implies it is FM (frequency modulated) not PWM.

If you divide PWM you lose the information in the modulation because division destroys the waveform shape. Please tell us exactly what your motor expects to be driven by, for example is the PWM fed directly to a DC or AC motor or does it pass through some other circuitry first.

Brian.
 
I would appreciate a clearer problem description, distinguishing between PWM frequency and pulse width. "PWM impulses" is inexpressive.

I guess you want to design a logic receiving an external PWM signal, extracting the pulse width and generating a PWM signal with manipulated pulse width and same(?) or different(?) frequency.

The general method is setting up a timer to measure the pulse width and possibly pulse period.

As the information represented by the pulse width is a numerical value, a straightforward VHDL approach suggests a numerical data type rather than std_logic_vector.
 

Dear All ,Thank you for suggestion, I spend two days to write it,because I am not good in vhdl and english,so this is working code:

Code:
entity pwmedit is
	PORT(       clk100    : IN std_logic;
			pwm_in  : IN std_logic; 
			mult       : IN integer:=1;	
			pwm_out: OUT std_logic);
end pwmedit;

architecture Behavioral of pwmedit is
	signal cnt: integer:=0;
	signal num_int: integer:=0;
process(clk100,pwm_in)
	begin
		if rising_edge(clk100) 
		   then  num_int <= num_int + 1;
				if    pwm_in ='1'                  
						then  num_int<=0;
						      cnt<=cnt+1;
						else 
						    if num_int < (cnt+784) * mult  
						     then pwm_out <= '1'; 
							  else pwm_out <= '0'; cnt<=0;
				end if; 	end if;
		end if;										 
end process;
index.jpg
 
Last edited:

The oscilloscope waveform suggests that the circuit generates delayed pwm pulses of same frequency. Is that what you want? If not, please give a clear specification.
 

Dear All ,Thank you for suggestion, I spend two days to write it,because I am not good in vhdl and english,so this is working code:

Code:
entity pwmedit is
	PORT(       clk100    : IN std_logic;
			pwm_in  : IN std_logic; 
			mult       : IN integer:=1;	
			pwm_out: OUT std_logic);
end pwmedit;

architecture Behavioral of pwmedit is
	signal cnt: integer:=0;
	signal num_int: integer:=0;
process(clk100,pwm_in)
	begin
		if rising_edge(clk100) 
		   then  num_int <= num_int + 1;
				if    pwm_in ='1'                  
						then  num_int<=0;
						      cnt<=cnt+1;
						else 
						    if num_int < (cnt+784) * mult  
						     then pwm_out <= '1'; 
							  else pwm_out <= '0'; cnt<=0;
				end if; 	end if;
		end if;										 
end process;
View attachment 143875

Hello,

in purpose to generate PWM signal (with various PWM frequency) you can use such generic VHDL module:

Code:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;

ENTITY pwm IS
  GENERIC(
      sys_clk         : INTEGER := 1_000_000; --system clock frequency in Hz
      pwm_freq        : INTEGER := 60_000;    --PWM switching frequency in Hz
      bits_resolution : INTEGER := 8;          --bits of resolution setting the duty cycle
      phases          : INTEGER := 1);         --number of output pwms and phases
  PORT(
      clk       : IN  STD_LOGIC;                                    --system clock
      reset_n   : IN  STD_LOGIC;                                    --asynchronous reset
      ena       : IN  STD_LOGIC;                                    --latches in new duty cycle
      duty      : IN  STD_LOGIC_VECTOR(bits_resolution-1 DOWNTO 0); --duty cycle
      pwm_out   : OUT STD_LOGIC_VECTOR(phases-1 DOWNTO 0);          --pwm outputs
      pwm_n_out : OUT STD_LOGIC_VECTOR(phases-1 DOWNTO 0));         --pwm inverse outputs
END pwm;

ARCHITECTURE logic OF pwm IS
  CONSTANT  period     :  INTEGER := sys_clk/pwm_freq;                      --number of clocks in one pwm period
  TYPE counters IS ARRAY (0 TO phases-1) OF INTEGER RANGE 0 TO period - 1;  --data type for array of period counters
  SIGNAL  count        :  counters := (OTHERS => 0);                        --array of period counters
  SIGNAL   half_duty_new  :  INTEGER RANGE 0 TO period/2 := 0;              --number of clocks in 1/2 duty cycle
  TYPE half_duties IS ARRAY (0 TO phases-1) OF INTEGER RANGE 0 TO period/2; --data type for array of half duty values
  SIGNAL  half_duty    :  half_duties := (OTHERS => 0);                     --array of half duty values (for each phase)
BEGIN
  PROCESS(clk, reset_n)
  BEGIN
    IF(reset_n = '0') THEN                                                 --asynchronous reset
      count <= (OTHERS => 0);                                                --clear counter
      pwm_out <= (OTHERS => '0');                                            --clear pwm outputs
      pwm_n_out <= (OTHERS => '0');                                          --clear pwm inverse outputs
    ELSIF(clk'EVENT AND clk = '1') THEN                                      --rising system clock edge
      IF(ena = '1') THEN                                                   --latch in new duty cycle
        half_duty_new <= conv_integer(duty)*period/(2**bits_resolution)/2;   --determine clocks in 1/2 duty cycle
      END IF;
      FOR i IN 0 to phases-1 LOOP                                            --create a counter for each phase
        IF(count(0) = period - 1 - i*period/phases) THEN                       --end of period reached
          count(i) <= 0;                                                         --reset counter
          half_duty(i) <= half_duty_new;                                         --set most recent duty cycle value
        ELSE                                                                   --end of period not reached
          count(i) <= count(i) + 1;                                              --increment counter
        END IF;
      END LOOP;
      FOR i IN 0 to phases-1 LOOP                                            --control outputs for each phase
        IF(count(i) = half_duty(i)) THEN                                       --phase's falling edge reached
          pwm_out(i) <= '0';                                                     --deassert the pwm output
          pwm_n_out(i) <= '1';                                                   --assert the pwm inverse output
        ELSIF(count(i) = period - half_duty(i)) THEN                           --phase's rising edge reached
          pwm_out(i) <= '1';                                                     --assert the pwm output
          pwm_n_out(i) <= '0';                                                   --deassert the pwm inverse output
        END IF;
      END LOOP;
    END IF;
  END PROCESS;
END logic;

This is core downloaded from opencores.org. This is generic, multi-phase and phase correct PWM generator.I am using it extensively in my project Controller for roller-blinds DC motor You can see this project at link on this forum:

https://www.edaboard.com/showthread.php?t=373807

The entity: WEKTORY_WYPELNIEN and WEKTORY_REVERSE are used for generating varying PWM signals (soft-starter and soft-stop for 12 V DC Motor) . This proces is fully parametrized: PWM generation (clock frequency, PWM frequency, PWM timing, number of generated PWM phases) The in PWM vectors are read from ROM simulated in VHDL array.

If you want I can send you more code of this project -with some explanation (sorry for Polish comments in VHDL code;-) ).

Regards
 
Last edited:

pls send me to XXXXXXXXXX, is there tachometer also used to correct some speed or hertz or rpm ??
 
Last edited by a moderator:

pls send me to XXXXXXXXXX, is there tachometer also used to correct some speed or hertz or rpm ??


Hello,

no I don't use tachometer (or any sensor for measuring speed of DC Motor) I just needen't it. I am afraid that you choose bad atitiude for your problem.

Could you describe how parameters has input PWM signal ?

1) PWM frequency
2) How many bits resolution (for example : 8 bit PWM - the period is divided to 255 intervals)
3) I assumed that you have only one phase PWM signal

And after that what device you wanna to steer (output PWM signal). How the input PWM signal have to be processed to generate output PWM signal ?

What is final purpose of output PWM (what device it would be steering by tha signal)?

Your post is in many aspects unclear. Could you clarify it a bit ? I can send you all code of my project, but I am not sure if it will be useful for your needs?

BTW: I guess that you want to stabilize the speed (rpms) of DC motor using PWM signal ? In such case you have to use motors encoders (for measuring speed). Output of this encoder should be input signal to "PID Regulator" and output form PID regulator (error signal) should alter the process of generating PWM signal. This is much more complicated design, but can be achived by using that generic PWM generator (wchich code I attached). Of course you have to write much additional code by yourself. There are PID regulator free IP cores available on the net.

Regards
 
Last edited:

There are no any fixed data needed, just it need to modify incoming pwm signal from flight controller and send it out to motor and regulate motor speed by getting hertz or revolution per 20ms .. So problem is solved , by myself and i want if someone need this he can use above code,because googling dont give me result..and no one write this kind of code.
 

There are no any fixed data needed, just it need to modify incoming pwm signal from flight controller and send it out to motor and regulate motor speed by getting hertz or revolution per 20ms .. So problem is solved , by myself and i want if someone need this he can use above code,because googling dont give me result..and no one write this kind of code.

Hello abinam,

maybe I am not clever ehough to understand what problem you have.

So problem is solved , by myself and i want if someone need this he can use above code,because googling dont give me result..and no one write this kind of code.

Your code has serious issues, and do nothing (what I demonstrate in simulation).

First issue:

Code:
entity pwmedit is
	PORT(       clk100    : IN std_logic;
			pwm_in  : IN std_logic; 
			mult       : IN integer:=1;	
			pwm_out: OUT std_logic);
end pwmedit;

You are using integer as input signal to your entity: mult : IN integer:=1;
Are you aware what are you doing?

The integer is treated as 32-bit vector what causing that multiplaying by 1 is taking huge amount of LUTs (* operator is very non effective as general).

See link:

http://forums.xilinx.com/t5/Welcome-Join/Using-integers-as-input-ports/td-p/284364

You should use GENERIC construct in entity of pwmedit:

Code:
entity pwmedit is
   generic ( mult : integer := 1);  -- multiplayer
	PORT( clk100    : IN std_logic;
			pwm_in  : IN std_logic; 
			pwm_out: OUT std_logic);
end pwmedit;

Wthout that changes you wouldn't be able to make simulation of your code (test-bench). Your project without that change occupy about 700 LUTs (my much bigger project takes less). After changes your code looks like that:

Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity pwmedit is
   generic ( mult : integer := 1);  -- multiplayer
	PORT( clk100    : IN std_logic;
			pwm_in  : IN std_logic; 
			pwm_out: OUT std_logic);
end pwmedit;

architecture Behavioral of pwmedit is
	signal cnt: integer :=0;
	signal num_int: integer :=0;
begin	

process(clk100,pwm_in)
	begin
		if rising_edge(clk100) 
		   then  
			   num_int <= num_int + 1;
				if  (pwm_in = '1')                  
						then  
						  num_int<=0;
						  cnt<=cnt+1;
						else 
						    if (num_int < ((cnt+784) * mult))  
						     then pwm_out <= '1'; 
							  else pwm_out <= '0'; cnt<=0;
				end if; 	end if;
		end if;										 
end process;

end Behavioral;

I made a test bench for this code and try to simulate it (I was changing pwm_in signal with various period and pwm_out was staing unchanged). This is code of test bench for your entity:

Code:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY pwmedit_TB IS
END pwmedit_TB;
 
ARCHITECTURE behavior OF pwmedit_TB IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT pwmedit
	 generic ( mult : integer := 1);  -- multiplayer
    PORT(
         clk100 : IN  std_logic;
         pwm_in : IN  std_logic;
         pwm_out : OUT  std_logic
        );
    END COMPONENT;
    

   --Inputs
   signal clk100 : std_logic := '0';
   signal pwm_in : std_logic := '0';

 	--Outputs
   signal pwm_out : std_logic;

   -- Clock period definitions
   constant clk100_period : time := 100 ns;
 
BEGIN
 
	-- Instantiate the Unit Under Test (UUT)
   uut: pwmedit PORT MAP (
          clk100 => clk100,
          pwm_in => pwm_in,
          pwm_out => pwm_out
        );

   -- Clock process definitions
   clk100_process :process
   begin
		clk100 <= '0';
		wait for clk100_period/2;
		clk100 <= '1';
		wait for clk100_period/2;
   end process;
 

   -- Stimulus process
   stim_proc: process
   begin		
      -- hold reset state for 100 ns.
      wait for 100 ns;	

      wait for clk100_period*10;

      -- insert stimulus here 
			pwm_in <= '1';
		wait for clk100_period*100;
		
		pwm_in <= '0';
		wait for clk100_period*100;
		
		pwm_in <= '1';
		wait for clk100_period*100;
		
		pwm_in <= '0';
		wait for clk100_period*100;
		
		pwm_in <= '1';
		wait for clk100_period*400;
		
		pwm_in <= '0';
		wait for clk100_period*400;
		
		pwm_in <= '1';
		wait for clk100_period*1000;
		
		pwm_in <= '0';
		wait for clk100_period*1000;
		
		pwm_in <= '1';
		wait for clk100_period*4000;
		
		pwm_in <= '0';
		wait for clk100_period*4000;
		
		pwm_in <= '1';
		wait for clk100_period*4000;
		
		pwm_in <= '0';
		wait for clk100_period*4000;
		

      wait;
   end process;

END;

And here you can see results of simulation:

- - - Updated - - -

This is last part of my last answer:

Result of simulation:

ISIM_PWM.PNG

Maybe when coincedence of some clock frequency and incoming PWM signal frequency took place your code is doing something, you need.

Why do you think that someone wanna to use your buggy code - what purpose is unclear ? :laugh:

Regards
 
Last edited:

BTW: If you using integer as input ports, you should at least apply range to it:

Code:
entity pwmedit is
	PORT(       clk100    : IN std_logic;
			pwm_in  : IN std_logic; 
			mult       : IN integer:=1;	
			pwm_out: OUT std_logic);
end pwmedit;

in order to economize resources using in FPGA, but still it is bad habit in design.

Regards
 
This code working , I don't know how to make simulation, i am sure smth wrong with your simulation code..but i check it in real hardware and oscilloscope..I cannot find any other vhdl code which is reads PWM in , so...
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top