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.

VHDL- Help with creating functioning constraints for FPGA con3 Pmod

Status
Not open for further replies.

Wolfgang94

Newbie level 4
Joined
Mar 22, 2013
Messages
6
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,330
I am trying to connect a servo motor to my Basys2 using the con3 Pmod sold by Digilent. I have been attempting to use two different methods for this and am unable to cause my servo to move with the PWM Signal they generate. I believe this has something to do with the constraints file I write. I have tried assigning the the servo's connection pin on the con3 Pmod's boardbut to no avail. Any assistance or troubleshooting tips that could be offered would be greatly appreciated.

Digilent Con3 (has project for servo motor I have been unable to make function)
http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,401,497&Prod=PMOD-CON3

Digilent Basys2
http://www.digilentinc.com/Products/Detail.cfm?Prod=BASYS2

servomotor I've been using
**broken link removed**

Other code I have been attempting to use (W/o test bench using a button setup as he describes in the comments)
http://www.codeproject.com/Articles/513169/Servomotor-Control-with-PWM-and-VHDL

Any help at all is very welcome, I am just learning how to program in VHDL and don't have much support to draw on at my University.
 

Have you connected an O-scope to the pin you are intending to use for your PWM signal. I would think your issue is more than likely your signal and not just identifying a pin in the constraint file.

My suggestion would be to set up a counter from (0 to Period) where period is the value (which depends on you clock rate) that equates to 20 ms. Next set up a duty that has an initial value that equates to 1.5 ms, with a process that adjusts the duty under appropriate conditions. Lastly have your output signal connected to whichever pin you want in your constraint file <= 1 when your counter is less than your duty.

hope this helps
 

I tried to implement what you said but am seeing no results and am without an oscope for a bit Is this a reasonable implementation of what you meant given a 50MHz clock? Sorry if there are some big mistakes still really new, and thanks for the help so far.


Code:
use IEE.STD_LOGIC_1164.ALL;
use IEE.NUMERIC_STD.ALL;

entity TEST is
    Port ( clk : in  STD_LOGIC;
           clk_out : out  STD_LOGIC
			  );
end TEST;

architecture Behavioral of TEST is
signal counter : integer range 0 to 999999 := 0;
signal duty : integer := 100000;

begin
test_freq: process (clk) begin
	if rising_edge(clk) then
		if (counter = 999999) then
			counter <= 0;
			else
				counter <= counter + 1;
		end if;
	end if;	
end process;

clk_out <= '1' when (counter < duty);


end Behavioral;
 

I am not seeing any obvious reason why that wouldn't work other than possibly your duty is always set to 2 ms which should make it turn completely to the left and stay there assuming you are using the 120 degree servo and not the 360 degree version of the GWservo. Here is the code I know works using your same setup except using a nexys2 rather than basys which shouldn't matter in this case:

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


entity ServoTester is
    Port ( clr : in STD_LOGIC;
			  Clk : in  STD_LOGIC;
			  ButtonLeft1 : in  STD_LOGIC;
			  ButtonRight1 : in  STD_LOGIC;
			  pwm : out  STD_LOGIC
			 );
end ServoTester;

architecture Behavioral of ServoTester is
				signal count : STD_LOGIC_VECTOR(19 downto 0);
				signal duty :  STD_LOGIC_VECTOR (19 downto 0) := "00000000000000000000";
            signal period :  STD_LOGIC_VECTOR (19 downto 0) := "11110100001001000000";
begin																				-- Period set to 20 ms

proc_clk: process(clk, clr)
	begin	-- Count increments from zero to period, then resets to zero
				if clr = '1' then
					count <= (others => '0');
				elsif rising_edge(clk) then
					if count = period - 1 then
						count <= (others => '0');
					else
						count <= count+1;
					end if;
				end if;
end process;

process(clk)
	begin	-- Duty set to user specifications
	if rising_edge(clk) then
		if ButtonLeft1 = '1' then	-- Button Number 3
			duty <= "00011001101000101000";	-- 2.1 ms
		elsif ButtonRight1 = '1' then	-- Button Number 2
			duty <= "00001010111111001000";	-- 0.9 ms
		else
			duty <= "00010010010011111000";	-- 1.5 ms
		end if;
	end if;
end process;

process(clk)
	begin	-- Sets Servo signal "High" for all values of count less then duty
	if rising_edge(clk) then
		if count < duty then
			pwm <= '1';
		else 
			pwm <= '0';
		end if;
	end if;
end process;



end Behavioral;

so the COM3 has the option for providing power to the servo from an external source I would check to make sure you are drawing the power from the board for testing purposes, which you can change later for implementation of whatever design you are working to. Also I would set your board to 5 v output rather than the 3.3

COM3 Setup.jpg
 
The Con3 is set to draw power from my board and every time I turn on my board without it being programmed the servo moves just a little or tries to. How would I set my board to output 5 volts though? also according to what info I have the servo has around a 215 degree range. I'm going to try your code now though and see how that works, thanks again man you're a real life-saver here.
 

also what do you map your clear signal to? I've heard it should all be mapped to the same clock but I feel as though this is incorrect. And I tried to use your code but It's trimming all of your duty values and throwing all kinds of different errors in the constraints file. It does not seem to enjoy how I have set up my constraints saying:

Attribute value "LVTLL" is not an accepted value for
attribute "IOSTANDARD" on "ButtonLeft1".

this is what my constraints file looks like:
Code:
NET clr LOC ="B8";
NET Clk LOC ="B8";
NET ButtonLeft1 LOC ="C11" | IOSTANDARD = LVTLL;
NET ButtonRight1 LOC ="G12" | IOSTANDARD = LVTLL;
NET pwm LOC ="P1" | IOSTANDARD = LVTLL;
 

so your pin assignments should be in line with page 11 of the basys2 manual referenced above.

Code:
NET "Clk" LOC="B8"; 		 # 50MHz clock

NET servo(0) LOC="K13";
NET servo(1) LOC="L16";
NET servo(2) LOC="M14";

NET Button(3) LOC="H13"; 	
NET Button(2) LOC="E18";
NET Button(1) LOC="D18"; 	
NET Button(0) LOC="B18";

NET SwitchOne LOC="G18";

Above is my constraint file, my project contains atop level and a control module so it had a few more pins then the code I had posted would need. It is also for the Nexys2 so the pins I have will not work for your board it is for reference purposes only. I am not an expert, others here could probably give more insight into the specifics of the IO standards and linking clr to clk. However I dont declare clr at all. And looking through your manual I guess you dont have a 5 v output option. So you can probably run 1 servo from the 3.3 but I dont know about two and for sure you cant run more than that. So depending on the project you are working to you will need to line up an external source for the servos.
 
I've got the servo to turn now. But it will only turn to the right despite my attempts to get it to use a different duty with each button press. It turns to the right only which I suppose means that it's receiving a 1ms pwm signal.

Code:
ctrl_move1 : process (btn, counter) begin
		if ((btn(2) = '1') AND (counter < duty1)) then
				clk_out <= '1';
		else
			if ((btn(1) = '1') AND (counter < duty2)) then
				clk_out <= '1';
			else
				if ((btn(0) = '1') AND (counter < duty3)) then
					clk_out <= '1';
				else
			clk_out <= '0';
				end if;
			end if;
		end if;	
			
end process;

my duty's are as follows:
Code:
signal counter : integer range 0 to 999999 := 0;
constant duty1 : integer := 2499;
constant duty2 : integer := 3749;
constant duty3 : integer := 4999;

I've tried multiple permutations in an attempt to get the servo to move in the other direction but cannot am I doing something horribly wrong?
 

So if I am understanding your code above, you are sending out a PWM pulse equal to duty if you are holding down the button. what you want to do is send out a PWM pulse every 20 ms no mater what. The width of that PWM determines the position the servo goes to. I should mention here that my servos have 360 degree motion.

So the thing about the servo angular freedom is that if it is 360 degrees the PWM only controls the direction and speed, which means that if I want the servo to turn I send out a pulse greater than or less than 1.5 ms and if I dont want it to turn I send out 1.5 ms. If it has a limited freedom then the PWM controls the point at which the servo will travel to then stop. To keep the servo at that point the PWM would need to be sent at whatever modulation is appropriate for that point every 20 ms. So if you have a 215 degree of motion servo (which is a weird range I believe) then what you will ultimately need to control is the rate your duty is shifting within the range of 1.0 to 2.0 ms, if you want it to spin.


so if you are working with 50 MHz that is a 20 ns clock cycle, 1,000,000 of those creates the 20 ms period which we have at this point. a duty of 100,000 clock cycle creates a duty of 2 ms which I believe turns the servo completely to the left 1 ms would be 50,000 clock cycles should turn all the way to the right.
 

Turns out it was my values I used the wrong number from the beginning my servo now functions perfectly, thank you so much for your help.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top