Question

Recommended Posts

  • 0

Hi, must be your lucky day - I'll take it nice and slow.

 

First of - how PWM works.

---------------------------------

If you connect a motor to a power supply it will spin at full speed/power.

 

If you switch the power supply on for 5 seconds and off for 5 seconds, it will spend half the time at full power, and half the time at zero power, and it will have an average power of 50%.

 

If you switch the power supply on for 1 seconds and off for 9 seconds, it will have an average power of 10%

 

The really important bit often overlooked is that the motor has full power while it is switched on, and so has nearly full torque. If you were to run it at a lower voltage the motor won't have nearly as much torque, making speed control impossible.

 

However, with a cycle time of 10 seconds, unless it is a very big and heavy motor (which takes a long time to spin up and down) it won't be too smooth. It is usual to use a PWM frequency of about 100Hz or 200HZ or so. (An aside - this is why cordless drills "hum" at low speed).

 

PWM is efficient, as the power is always on/always off - even with huge motors the electronics stay colde.If you "lower the voltage" using a linear voltage regulator the unused power is dissipated by the power supply, making it hot and a waste of power.

 

What is a H-Bridge?

================

When you connect a battery to the wires of a DC motor it will spin one way, when you flip the motor over it will spin the other.

 

A H-bridge is an arrangement of power transistors acting as switches that allows the "flipping" of connections without physically changing anything, The arrangement looks like an ''H', hence the name,

 

Usually the H-bridge is powered from a different power source from the control signals - this is why the PMOD-HB3 has the GND and VM connections - these supply power to the motor.

 

Putting them both together

=====================

Using a PWM with a H-Bridge allows you to control both the power and direction of the motor. It is important to note that we can't directly control the speed, as the speed of the motor depends on the load it is under.

 

Next - getting the FPGA design started.

Share this post


Link to post
Share on other sites
  • 0

Hi,

 

You really haven't provided enough information for anybody to give you a sensible answer - what sort of motor? Do you need speed control? Forward and reverse?....

 

Mike

Share this post


Link to post
Share on other sites
  • 0

Hello Gustavo, 

 

Mike is correct, your question is extremely vague. It looks like you are trying to find a place to start?

If so, we had a design project that used stepper motors-- http://www.digilentinc.com/showcase/projects/shootinggallery.cfm

The project uses a Nexys2 and uses stepper motors for the targets. 

That may be helpful as a starting point.

Share this post


Link to post
Share on other sites
  • 0

One other option if you need to drive high power motors, is to use a RC plane speed controller to drive the motor. Something like http://www.dx.com/p/flying-30a-bec-electronic-speed-controller-for-brushless-motors-esc-11981 costs under $12 and will drive up to 360W. If you need to drive in reverse as well, then get a RC car speed controller, some models can also drive brushed (standard DC) motors.

 

That then reduces the FPGA engineering to generating a 50Hz signal with duty cycle of between 5% and 10% (i.e. a pulse between 1ms and 2ms, every 20ms) - have a look at http://www.fpga4fun.com/RCServos.html

 

If you really want to avoid soldering, then using http://www.digilentinc.com/Products/Detail.cfm?Prod=PMOD-CON3 would allow you to connect up to four motors.

 

As a bonus it also gives the option for extra isolation between the FPGA and motors - if you are building your own PCB you could even put an opto-coupler in the signal path, which could completely electrically isolate the FPGA from the (noisy) motor and battery.

 

Mike

Share this post


Link to post
Share on other sites
  • 0

(Argh! Why when I post does the edit window remain open with txt in it, so I click "Save Changes" again and double-post???)

Not to hijack the topic, but thanks for bringing this to attention, I'll look into it.

Share this post


Link to post
Share on other sites
  • 0

Hi,

 

Assuming you have wired up everything correctly, and you want to use four push buttons to drive a motor at one of four speeds (backwards fuil power, backwards half power, forwards half power,   forwards full power)

 

In sort of VHDL psuedo-code you want to do do something like this. I haven't read the PMOD's reference manual, so I might have the logic level the wrong way around (active low vs active high for the PMOD's enable signal).

  ...
     signal counter : unsigned (17 downto 0) := 0;
     signal pwn_50_percent : std_logic := '0';
  ...
process(clk)
  begin
  if rising_edge(clk) then
     case buttons is
        when "1000" =>  -- Backwards full speed
           pmod_dir = '1';
           pmod_enable = '1';
 
        when "0100" => - Backwards half speed
           pmod_dir = '1';
           pmod_enable = pwn_50_percent;
 
        when "0010" => - Forward half speed
           pmod_dir = '0';
           pmod_enable = pwn_50_percent;
 

        when "0001" => - Forward half speed
           pmod_dir = '0';
           pmod_enable = pwn_50_percent;
 

        when others => -- no buttons, or multiple buttons so do nothing
           pmod_dir = '0';
           pmod_enable = '0';
      end case;
 
      -- Using a counter to make a 50% PWM signal
      counter <= counter + 1;
      pwn_50_percent = counter(17);  -- PWM Freq = clk / (256*1024), 50% duty cycle.
  end if;;
end process;

Share this post


Link to post
Share on other sites
  • 0

Here is a design that on the Basys2 will drive LD0 at either 99%, 50%, 25% or 5% drive, depending on what push button is pressed,

 

Captures:

 

Driving at 25%:duty cycle:

post-35-0-56405900-1415695846_thumb.jpg

 

Driving at 50% duty cycle:

post-35-0-73340600-1415695847_thumb.jpg

 

Driving at 100% duty cycle:

post-35-0-11410000-1415695849_thumb.jpg

 

############################
# BASYS2.UCF - Constraints
############################
NET "clk" LOC = "B8"; # Bank = 0, Signal name = MCLK
NET "clk" CLOCK_DEDICATED_ROUTE = FALSE;
 
NET "btn<3>" LOC = "A7";  # Bank = 1, Signal name = BTN3
NET "btn<2>" LOC = "M4";  # Bank = 0, Signal name = BTN2
NET "btn<1>" LOC = "C11"; # Bank = 2, Signal name = BTN1
NET "btn<0>" LOC = "G12"; # Bank = 0, Signal name = BTN0
 
NET "pwm" LOC = "M5"; # Bank = 1, Signal name = LD0
 
-----------------------------------------------------
-- PWM_TEST.VHD - A PWM driver for an LED.
-----------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pwm_test is
    Port ( clk : in  STD_LOGIC;
           btn : in  STD_LOGIC_VECTOR (3 downto 0);
           pwm : out  STD_LOGIC);
end pwm_test;
 
architecture Behavioral of pwm_test is
  signal divider   : unsigned ( 8 downto 0) := (others => '0');
  signal percent   : unsigned ( 6 downto 0) := (others => '0');
  signal pwm_level : unsigned ( 6 downto 0) := (others => '0');
begin
 
process(clk)
   begin
      if rising_edge(clk) then
         -- Set the output when percent is less than the drive level
         if percent < pwm_level then
            pwm <= '1';
         else
            pwm <= '0';
         end if;
         
         -- decide what the drive level should be
         case btn is
            when "1000" =>  -- 99% Drive
               pwm_level <= to_unsigned(99, 7);
                 
            when "0100" => -- 50% Drive
               pwm_level <= to_unsigned(50, 7);
       
            when "0010" => -- 25% drive
               pwm_level <= to_unsigned(25, 7);
       
            when "0001" => -- 5% drive
               pwm_level <= to_unsigned(5, 7);
 
            when others => -- no buttons, or multiple buttons so do nothing
               pwm_level <= to_unsigned(0, 7);
         end case;
       
         -- Make each percent equivilent to 500 cycles
         if divider = 499 then
            divider <= (others => '0');
            if percent = 99 then
               percent  <= (others => '0');
            else
               percent <= percent +1;
            end if;
         else
            divider <= divider + 1;
         end if;
      end if;
   end process;
 
end Behavioral;

Share this post


Link to post
Share on other sites
  • 0

hi hamster... I have a problem  with the program you sent me, the error is                   WARNING:Cpld - Unable to retrieve the path to the iSE Project Repository. Will

   use the default filename of 'pwm_test.ise'.     and would not generate the bit file.....

Share this post


Link to post
Share on other sites
  • 0

Getting stated with FPGAs is a very steep learning curve - quite a bit of base knowledge is required to get even the simple projects working, but with a little bit of study you should be able to get something working.

 

However, I think you have a much bigger problem. If you do not have a detailed understanding of what you need to design, then how can you expect that you will end up with a design that will meet your needs?

 

I am over 12,000km away from Digilent and have no ties to them at all, so it makes no difference to me if you finish your project or not.,, Are you sure you are not just wanting somebody to do your homework for you?

Share this post


Link to post
Share on other sites
  • 0
I'm glad you have good people like you..... in the school told us to do motor control in vhdl but almost no information so I am newbie in this .... and I have 12v motor I need to control the rotation forward or backward. and a PWM control your speed ...... why buy pmod h bridge to control pan, but do not understand anything ..... you really appreciate your support,,,,,,,

Share this post


Link to post
Share on other sites
  • 0

So let's build a motor driver using the Basys2 and a PMOD-HB3.

 

First of - we need to just do something simple. Switch on two LEDs using two switches.

 

If you put these two files into a project, build it, and download it using Adept to the FPGA board then you should be able to turn LD0 and LD1 off and on using SW0 and SW1 

 

Here is the constraints:

#################################
# basys2.ucf constraints file
#################################
NET "led1" LOC = "M11" ; # Bank = 2, Signal name = LD1
NET "led0" LOC = "M5" ;  # Bank = 2, Signal name = LD0
 
NET "sw1" LOC = "L3";  # Bank = 3, Signal name = SW1
NET "sw0" LOC = "P11";  # Bank = 2, Signal name = SW0
#################################

And here is a simple VHDL design - it just connects the LEDs to the switches.

---------------
-- pwm_test.vhd
----------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pwm_test is
    Port ( sw0, sw1  : in  STD_LOGIC;
           led0,led1 : out STD_LOGIC
         );
end pwm_test;
 
architecture Behavioral of pwm_test is
begin
   led0 <= sw0;
   led1 <= sw1;
end Behavioral;

Share this post


Link to post
Share on other sites
  • 0

Great! So now you can switch lights off and on! Wahoo!

 

Yeah, well, lets see if we can get a motor spinning.

 

With the motor power supply switched off, connect the PMOD-HB3 to connector JA (on the top left of the board). Connect the motor to the M+ / M- terminals. Connect the motor powers to the Vm and GND terminals. That should be all the wiring needed.

 

Now on to the FPGA design....

 

First we need the extra constraints that match the PMOD.

 

#################################
# Basys2 constriants file
#################################
NET "led1" LOC = "M11" ; # Bank = 2, Signal name = LD1
NET "led0" LOC = "M5" ;  # Bank = 2, Signal name = LD0
 
NET "ja0" LOC = "B2"  | DRIVE = 2; # Bank = 1, Signal name = JA1
NET "ja1" LOC = "A3"  | DRIVE = 2; # Bank = 1, Signal name = JA2
 
NET "sw1" LOC = "L3";  # Bank = 3, Signal name = SW1
NET "sw0" LOC = "P11";  # Bank = 2, Signal name = SW0
#################################

 

Now update the VHDL to also send the switches to the PMOD as well as the LEDs:

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pwm_test is
    Port ( sw0, sw1  : in  STD_LOGIC;
           ja0, ja1 :  out STD_LOGIC;
           led0,led1 : out STD_LOGIC
         );
end pwm_test;
 
architecture Behavioral of pwm_test is
begin
   -- show the switches
   led0 <= sw0;
   led1 <= sw1;
   -- Drive the pmod
   ja0  <= sw0;
   ja1  <= sw1;
end Behavioral;

 

Build the design, download it, turn sw0 and sw1 off, turn the motor power supply on, and if you now turn sw1 on, LD1 should turn on, and because the PMOD's EN signal is driven the motor should spin at full speed.

 

If you turn sw1 off, then turn sw0 the H-bridge is flipped over to drive the motor in the other direction. Turning sw1 will drive the motor in reverse.

 

If you want, you can test out a manual PWM by flipping sw1 off and on relatively quickly.

Share this post


Link to post
Share on other sites
  • 0

Great, Manual PWM isn't that effective. So now lets generate the PWM signal using the FPGA.

 

To make things visible, we will drive the signal at about 0.5Hz, and at 50%. To do this we'll need a clock. 

 

So add the Basys2's clock signal to your constraints file:

 

  NET "clk" LOC = "B8"; # Bank = 0, Signal name = MCLK
 
And we now need to update the code to use this clock. In this case we run a counter, which counts to 100,000,000 (which takes two seconds at 50MHz). This is then used to generate a signal called 'pwm'. This can then be 'AND'ed with the enable switch to drive it at half power when it is switched on.
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pwm_test is
    Port ( clk       : in  STD_LOGIC;
           sw0, sw1  : in  STD_LOGIC;
           ja0, ja1  : out STD_LOGIC;
           led0,led1 : out STD_LOGIC
         );
end pwm_test;
 
architecture Behavioral of pwm_test is
   signal pwm            : std_logic := '0';
   signal counter        : unsigned(26 downto 0) := (others => '0');
begin
   -- show the switches on the leds
   led0 <= sw0;
   led1 <= sw1 and pwm;
   -- Drive the pmod-hb3 signals
   ja0  <= sw0;
   ja1  <= sw1 and pwm;
 
clk_proc: process(clk)
   begin
      if rising_edge(clk) then
         pwm <= '0';
         if counter < 50000000 then
            pwm <= '1';
         end if;
         
         if counter = 99999999 then
            counter <= (others => '0');
         else
            counter <= counter+1;
         end if;
      end if;
   end process;
end Behavioral;
 
Great - because of the 0.5Hz PWM frequency the motor should go Whirrrr... weeee, Whirrrr... weeee - On for a second, off for a second.
 
Next step, have more than one PWM setting....
 

Share this post


Link to post
Share on other sites
  • 0

Now let's add different PWM Duty cycles - 0% (off) 25%, 50% 75% and 100%.

 

To do this we will need to use the pushbuttons, so we need to set the constraints:

NET "btn3" LOC = "A7";  # Bank = 1, Signal name = BTN3
NET "btn2" LOC = "M4";  # Bank = 0, Signal name = BTN2
NET "btn1" LOC = "C11"; # Bank = 2, Signal name = BTN1
NET "btn0" LOC = "G12"; # Bank = 0, Signal name = BTN0

And update the VHDL to change the PWM duty cycle:

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pwm_test is
    Port ( clk       : in  STD_LOGIC;
           sw0, sw1  : in  STD_LOGIC;
           btn0, btn1, btn2, btn3 : in STD_LOGIC;
           ja0, ja1  : out STD_LOGIC;
           led0,led1 : out STD_LOGIC
         );
end pwm_test;
 
architecture Behavioral of pwm_test is
   signal pwm            : std_logic := '0';
   signal counter        : unsigned(26 downto 0) := (others => '0');
begin
   -- show the switches on the leds
   led0 <= sw0;
   led1 <= sw1 and pwm;
   -- Drive the pmod-hb3 signals
   ja0  <= sw0;
   ja1  <= sw1 and pwm;
 
clk_proc: process(clk)
   begin
      if rising_edge(clk) then
         pwm <= '0';
         
         if counter < 25000000 and btn0 = '1' then
            pwm <= '1';
         end if;
         
         if counter < 50000000 and btn1 = '1' then
            pwm <= '1';
         end if;
 
         if counter < 75000000 and btn2 = '1' then
            pwm <= '1';
         end if;
 
         if btn3 = '1' then
            pwm <= '1';
         end if;
         
         if counter = 99999999 then
            counter <= (others => '0');
         else
            counter <= counter+1;
         end if;
      end if;
   end process;
end Behavioral;
 
So now switch on SW1, and push the pushbuttons!

Share this post


Link to post
Share on other sites
  • 0

So all that is left is to get rid of the Whirrrr, Weee, Whirr, Weee....

 

To do this we speed up the PWM frequency from 0.5Hz to 50Hz. This is pretty easy to do, just remove the last two digits of the counter constants:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pwm_test is
    Port ( clk       : in  STD_LOGIC;
           sw0, sw1  : in  STD_LOGIC;
           btn0, btn1, btn2, btn3 : in STD_LOGIC;
           ja0, ja1  : out STD_LOGIC;
           led0,led1 : out STD_LOGIC
         );
end pwm_test;
 
architecture Behavioral of pwm_test is
   signal pwm            : std_logic := '0';
   signal counter        : unsigned(19 downto 0) := (others => '0');
begin
   -- show the switches on the leds
   led0 <= sw0;
   led1 <= sw1 and pwm;
   -- Drive the pmod-hb3 signals
   ja0  <= sw0;
   ja1  <= sw1 and pwm;
 
clk_proc: process(clk)
   begin
      if rising_edge(clk) then
         pwm <= '0';
         
         if counter < 250000 and btn0 = '1' then
            pwm <= '1';
         end if;
         
         if counter < 500000 and btn1 = '1' then
            pwm <= '1';
         end if;
 
         if counter < 750000 and btn2 = '1' then
            pwm <= '1';
         end if;
 
         if btn3 = '1' then
            pwm <= '1';
         end if;
         
         if counter = 999999 then
            counter <= (others => '0');
         else
            counter <= counter+1;
         end if;
      end if;
   end process;
end Behavioral;

(Note that the size of counter has been reduced to 20 bits, as we only need to count to 999,999)

 

And finished - a PWM controller that will drive a motor at four different power levels, in two directions, depending on the switches and buttons.(and me most probably in trouble with many tutors!)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now