Search code examples
verilogfpgapwmservo

Servo on an FPGA


I'm trying to make a servo work on my Spartan-6 based FPGA.

my code is as follows:

`timescale 1ns / 1ps


/*
 1 pin for servo--ORANGE CABLE
 red cable-- 5V, brown cable-- GND. 
 Position "0" (1.5 ms pulse) is middle, 
 "90" (~2ms pulse) is all the way to the right,
 "-90" (~1 ms pulse) is all the way to the left.  
 servo stuff:
 http://www.micropik.com/PDF/SG90Servo.pdf
 */


 //All i need to do is set SERVOPWM to 1 and 0 with delays i think
module ServoTestNShit(input M_CLOCK,
                             output [7:0] IO_LED, // IO Board LEDs
                             output reg SERVOPWM);    

    assign IO_LED = 7'b1010101; // stagger led lights just cause

   reg [15:0] counter;

    //use counter to have a 1ms or 2ms or 1.5ms duty cycle for a while inorder to actually run
    //because run it this way is asking the servo to move for 1.5ms so it cant atually move that fast
    always @* 
    begin

        for(counter = 0; counter < 3000; counter = counter + 1)
        begin
        SERVOPWM = 1; 
        #2;
        SERVOPWM = 0;
        #2;
        SERVOPWM = 1; 
        #2;
        SERVOPWM = 0;
        #2;
        SERVOPWM = 1; 
        #2;
        SERVOPWM = 0;
        #2;
        end

        for(counter = 0; counter < 3000; counter = counter + 1)
        begin
        SERVOPWM = 1; 
        #1;
        SERVOPWM = 0;
        #2;
        SERVOPWM = 1; 
        #1;
        SERVOPWM = 0;
        #2;
        SERVOPWM = 1; 
        #1;
        SERVOPWM = 0;
        #2;
        end

    end


endmodule

and my ucf file is pretty much just:

# Clock signal 

NET "M_CLOCK" LOC = P123;


NET "SERVOPWM" LOC = P121 ;//0P1

So in my head, my code will be creating a pulse wave first all the way to the right, by setting high for 2ms, then low, then high for 2ms, etc and repeating. Then, all the way to the left with high for 1ms, etc. I thought this problem would be relatively simple, as all I'm doing is sending a 1 or a 0 to an IO pin and I have my servo hooked to 5v, ground, and the IO pin in question.

Is there something stupid/obvious/easy that I'm missing? Or is there some part of the concept I'm missing?

Thanks for any help in advance! Cody


Solution

  • Delay (#) statements are not synthesized in verilog. This way it will output only the final value. You should synchronize your outputs with clock.

    The way I would do is

    always @ (posedge clk)
    begin
       counter <= counter+1;
    end
    
    always @ (negedge clk)
    begin
       SERVOPWM <= (counter <= pwm_value);
    end