Click here to Skip to main content
15,891,777 members
Articles / VHDL
Article

Servomotor Control with PWM and VHDL

Rate me:
Please Sign up or sign in to vote.
4.73/5 (11 votes)
20 Dec 2012LGPL32 min read 126.3K   1.7K   6   26
Generate a PWM signal for servomotor control with VHDL.

Simulation of the PWM for servomotor

Introduction

In this brief article we generate a pulse width modulation signal for a servomotor control with VHDL.

Background

First of all, a servomotor is nothing more than a direct current motor with an electronic circuit attached in order to achieve better control. For such control, we need to generate a waveform like the one shown below:

PWM signal for servomotor control

The time, or frequency, of the pulse determines the position of the servo. Each servo has its own range of frequencies, given by the manufacturer in the data sheet. The figure shows values within 1 and 2 ms.

Design of the control

The control signal for the servomotor is made out of two frequencies:

  • Refresh frequency, of 20ms.
  • Pulse width range, provided by the manufacturer. For this article, we are going to assume such frequency goes from 0.5ms to 2.5ms.

First of all, we need to find our range of operation, given by:

Range of operation

Now we need to know the resolution for the servo, which is the quantity of position it can take. Therefore, the minimum needed frequency is equivalent to:

Minimum needed frequency

If our servomotor can take up to 128 position, we yield:

Minimum needed frequency, substitution

We now need a frequency divider of 64kHz. Although we can do one following the process described at frequency divider with VHDL, here we have the full code of the divider from 50MHz to 64kHz:

vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity clk64kHz is
    Port (
        clk    : in  STD_LOGIC;
        reset  : in  STD_LOGIC;
        clk_out: out STD_LOGIC
    );
end clk64kHz;
 
architecture Behavioral of clk64kHz is
    signal temporal: STD_LOGIC;
    signal counter : integer range 0 to 780 := 0;
begin
    freq_divider: process (reset, clk) begin
        if (reset = '1') then
            temporal <= '0';
            counter  <= 0;
        elsif rising_edge(clk) then
            if (counter = 780) then
                temporal <= NOT(temporal);
                counter  <= 0;
            else
                counter <= counter + 1;
            end if;
        end if;
    end process;
 
    clk_out <= temporal;
end Behavioral;

Finally, we know that with a 64kHz clock we will have 1ms each 64 iterations. So, in order to have a frequency of 20ms, we only need to multiply 20 * 64, which will be implemented with a counter from 0 to 1279.

Implementation in VHDL

For the VHDL implementation we have three inputs: 64 kHz clock, reset, and a vector that an take the values from 0 to 127. The only output is the servomotor control signal. The code is shown below.
vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity servo_pwm is
    PORT (
        clk   : IN  STD_LOGIC;
        reset : IN  STD_LOGIC;
        pos   : IN  STD_LOGIC_VECTOR(6 downto 0);
        servo : OUT STD_LOGIC
    );
end servo_pwm;

architecture Behavioral of servo_pwm is
    -- Counter, from 0 to 1279.
    signal cnt : unsigned(10 downto 0);
    -- Temporal signal used to generate the PWM pulse.
    signal pwmi: unsigned(7 downto 0);
begin
    -- Minimum value should be 0.5ms.
    pwmi <= unsigned('0' & pos) + 32;
    -- Counter process, from 0 to 1279.
    counter: process (reset, clk) begin
        if (reset = '1') then
            cnt <= (others => '0');
        elsif rising_edge(clk) then
            if (cnt = 1279) then
                cnt <= (others => '0');
            else
                cnt <= cnt + 1;
            end if;
        end if;
    end process;
    -- Output signal for the servomotor.
    servo <= '1' when (cnt < pwmi) else '0';
end Behavioral;

The signal cnt is used to implement the counter from 0 to 1279, which is described from lines 22 to 33.

The input signal pos is a vector that can take any value from 0 to 127, which yield the range of 0ms to 2ms. Since we need a signal that goes from 0.5ms to 2.5ms, we need to add an offset of 32 equivalent to the 0.5ms.

The listing 3, shown below, describes the PORT MAP needed to glue together the frequency divider and the servomotor control component.

vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity servo_pwm_clk64kHz is
    PORT(
        clk  : IN  STD_LOGIC;
        reset: IN  STD_LOGIC;
        pos  : IN  STD_LOGIC_VECTOR(6 downto 0);
        servo: OUT STD_LOGIC
    );
end servo_pwm_clk64kHz;

architecture Behavioral of servo_pwm_clk64kHz is
    COMPONENT clk64kHz
        PORT(
            clk    : in  STD_LOGIC;
            reset  : in  STD_LOGIC;
            clk_out: out STD_LOGIC
        );
    END COMPONENT;
    
    COMPONENT servo_pwm
        PORT (
            clk   : IN  STD_LOGIC;
            reset : IN  STD_LOGIC;
            pos   : IN  STD_LOGIC_VECTOR(6 downto 0);
            servo : OUT STD_LOGIC
        );
    END COMPONENT;
    
    signal clk_out : STD_LOGIC := '0';
begin
    clk64kHz_map: clk64kHz PORT MAP(
        clk, reset, clk_out
    );
    
    servo_pwm_map: servo_pwm PORT MAP(
        clk_out, reset, pos, servo
    );
end Behavioral;

Test bench and simulation

For the test bench, we use five different values for pos, described from lines 43 to 59.

vhdl
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
 
ENTITY servo_pwm_clk64kHz_tb IS
END servo_pwm_clk64kHz_tb;
 
ARCHITECTURE behavior OF servo_pwm_clk64kHz_tb IS
    -- Unit under test.
    COMPONENT servo_pwm_clk64kHz
        PORT(
            clk   : IN  std_logic;
            reset : IN  std_logic;
            pos   : IN  std_logic_vector(6 downto 0);
            servo : OUT std_logic
        );
    END COMPONENT;

    -- Inputs.
    signal clk  : std_logic := '0';
    signal reset: std_logic := '0';
    signal pos  : std_logic_vector(6 downto 0) := (others => '0');
    -- Outputs.
    signal servo : std_logic;
    -- Clock definition.
    constant clk_period : time := 10 ns;
BEGIN
    -- Instance of the unit under test.
    uut: servo_pwm_clk64kHz PORT MAP (
        clk => clk,
        reset => reset,
        pos => pos,
        servo => servo
    );

   -- Definition of the clock process.
   clk_process :process begin
        clk <= '0';
        wait for clk_period/2;
        clk <= '1';
        wait for clk_period/2;
   end process;
 
    -- Stimuli process.
    stimuli: process begin
        reset <= '1';
        wait for 50 ns;
        reset <= '0';
        wait for 50 ns;
        pos <= "0000000";
        wait for 20 ms;
        pos <= "0101000";
        wait for 20 ms;
        pos <= "1010000";
        wait for 20 ms;
        pos <= "1111000";
        wait for 20 ms;
        pos <= "1111111";
        wait;
    end process;
END;

The result of the simulation is shown below. The following frequencies were obtained:

  • A refresh frequency of 19.9936 ms.
  • A minimum frequency of 0.4920 ms.
  • A maximum frequency of 2.4835 ms.

Simulation of the PWM for servomotor

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Engineer Estado Finito
Mexico Mexico
Mechatronics Engineer, with a biased interest in digital systems design and development. Currently studying Master's degree in Electrical Engineering and running a blog about digital design at Estado Finito.

Comments and Discussions

 
Questiondivisor de frecuencias Pin
Member 1413644731-Jan-19 19:19
Member 1413644731-Jan-19 19:19 
QuestionMultiple servos-VHDL Pin
Member 1406710925-Nov-18 21:17
Member 1406710925-Nov-18 21:17 
Questionservo Pin
Serge21-Jun-16 23:47
Serge21-Jun-16 23:47 
hello, this is very useful indeed, but have you actually tried it with a real servo?

and do you think it would matter that duty cycle is often a little too much or too little due to multiplying binary number by the clock cycle period?
Questionclocking and 2 channels Pin
Member 125005145-May-16 1:14
Member 125005145-May-16 1:14 
QuestionWant to understand some variables in the code Pin
Member 121258819-Nov-15 14:46
Member 121258819-Nov-15 14:46 
Question.xdc file(controlling servo) Pin
EyyubBaskent1-Nov-15 4:40
EyyubBaskent1-Nov-15 4:40 
AnswerRe: .xdc file(controlling servo) Pin
EyyubBaskent8-Nov-15 8:04
EyyubBaskent8-Nov-15 8:04 
QuestionRe: .xdc file(controlling servo) Pin
Arman Dundar4-Dec-23 9:51
Arman Dundar4-Dec-23 9:51 
Questionhow to interface servomotor with spartan 6 Pin
Member 114326251-Apr-15 19:36
Member 114326251-Apr-15 19:36 
GeneralMy vote of 3 Pin
Member 106529092-May-14 0:03
Member 106529092-May-14 0:03 
GeneralRe: My vote of 3 Pin
Carlos A. Ramos2-May-14 6:34
Carlos A. Ramos2-May-14 6:34 
GeneralGood article Pin
HoshiKata25-Nov-13 15:37
HoshiKata25-Nov-13 15:37 
GeneralRe: Good article Pin
Carlos A. Ramos2-May-14 9:10
Carlos A. Ramos2-May-14 9:10 
Questioncalculation for hbridge chip Pin
Member 1022559622-Aug-13 5:00
professionalMember 1022559622-Aug-13 5:00 
AnswerRe: calculation for hbridge chip Pin
Carlos A. Ramos2-May-14 9:12
Carlos A. Ramos2-May-14 9:12 
GeneralThanx Pin
urman ratneshwar27-Mar-13 0:38
urman ratneshwar27-Mar-13 0:38 
Generalservomotor and inputs Pin
Wolfagang9417-Mar-13 13:24
Wolfagang9417-Mar-13 13:24 
AnswerRe: servomotor and inputs Pin
Carlos A. Ramos17-Mar-13 16:45
Carlos A. Ramos17-Mar-13 16:45 
Questionrefresh freq. Pin
urman ratneshwar10-Mar-13 23:10
urman ratneshwar10-Mar-13 23:10 
AnswerRe: refresh freq. Pin
Carlos A. Ramos11-Mar-13 9:30
Carlos A. Ramos11-Mar-13 9:30 
GeneralRe: refresh freq. Pin
urman ratneshwar11-Mar-13 21:38
urman ratneshwar11-Mar-13 21:38 
AnswerRe: refresh freq. Pin
Carlos A. Ramos17-Mar-13 16:38
Carlos A. Ramos17-Mar-13 16:38 
GeneralRe: refresh freq. Pin
tbkh29-Jun-13 4:34
tbkh29-Jun-13 4:34 
GeneralRe: refresh freq. Pin
Carlos A. Ramos2-May-14 9:14
Carlos A. Ramos2-May-14 9:14 
QuestionMessage Closed Pin
20-Dec-12 11:02
_beauw_20-Dec-12 11:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.