Jump to content
  • 0

gustavo345

Question

Recommended Posts

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

Link to comment
Share on other sites

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;
Link to comment
Share on other sites

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!
Link to comment
Share on other sites

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;
Link to comment
Share on other sites

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.....
Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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,,,,,,,
Link to comment
Share on other sites

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;
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...