module servo_cntr (
input clk, reset_p,
input [4:0] servo_mode,
input servo_start,
input [7:0] servo_angle,
output servo,
output reg [7:0] step,
output [15:0] led
);
localparam IDLE = 5'b00001;
localparam ROUND = 5'b00010;
localparam ROUND_D = 5'b00100;
localparam ONEWAY_D = 5'b01000;
localparam ONETIME = 5'b10000;
assign led[0] = servo_start;
assign led[5:1] = servo_mode;
integer cnt_servo;
reg [3:0] cnt_delay;
reg servo_dir = 1;
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin
step <= 40;
servo_dir <= 1;
cnt_servo <= 0;
cnt_delay <= 0;
end
else begin
if (servo_start) begin
if (cnt_servo >= 3_000_000) begin
cnt_servo <= 0;
case (servo_mode)
IDLE : begin
if (step <= 40) servo_dir <= 1;
else step <= step - 1;
end
ROUND : begin
if (servo_dir) begin
if (step >= (40 + servo_angle)) servo_dir <= 0;
else step <= step + 1;
end
else if (servo_dir == 0) begin
if (step <= 40) servo_dir <= 1;
else step <= step - 1;
end
end
ROUND_D : begin
if (servo_dir) begin
if (step >= (40 + servo_angle)) servo_dir <= 0;
else if (step % 10 == 0) begin
if (cnt_delay >= 10) begin
cnt_delay <= 0;
step <= step + 1;
end
else cnt_delay <= cnt_delay + 1;
end
else step <= step + 1;
end
else if (servo_dir == 0) begin
if (step <= 40) servo_dir <= 1;
else if (step % 10 == 0) begin
if (cnt_delay >= 10) begin
cnt_delay <= 0;
step <= step - 1;
end
else cnt_delay <= cnt_delay + 1;
end
else step <= step - 1;
end
end
ONEWAY_D : begin
if (servo_dir) begin
if (step >= (40 + servo_angle)) servo_dir <= 0;
else if (step % 10 == 0) begin
if (cnt_delay >= 10) begin
cnt_delay <= 0;
step <= step + 1;
end
else cnt_delay <= cnt_delay + 1;
end
else step <= step + 1;
end
else if (servo_dir == 0) begin
if (step <= 40) servo_dir <= 1;
else step <= step - 1;
end
end
ONETIME : begin
if (step < (40 + servo_angle)) step <= step + 1;
else if (step > (40 + servo_angle)) step <= step - 1;
end
default : begin
if (step <= 40) servo_dir <= 1;
else step <= step - 1;
end
endcase
end
else begin
cnt_servo <= cnt_servo + 1;
end
end
else if (!servo_start && servo_mode == ONETIME) begin
if (cnt_servo >= 3_000_000) begin
cnt_servo <= 0;
if (step > 40) step <= step - 1;
end
else begin
cnt_servo <= cnt_servo + 1;
end
end
end
end
pwm_Nstep #(.pwm_freq(50), .duty_step_N(1800)) pwm_servo (clk, reset_p, step, servo);
endmodule
module pwm_Nstep (
input clk, reset_p,
input [31:0] duty, // PWM Duty Rate, CCR Capture Compare Register
output reg pwm // PWM Duty Applied Pulse
);
parameter sys_clk_freq = 100_000_000; // System Clock Frequency
parameter pwm_freq = 10_000; // PWM Frequency
parameter duty_step_N = 256; // Duty Step, ARR Auto Reload Register
parameter temp = sys_clk_freq / pwm_freq / duty_step_N / 2; // Half of Cycle
integer cnt_sysclk; // System Clock Count
reg pwm_freqXn; // PWM Frequency
always @(posedge clk, posedge reset_p) begin
if (reset_p) begin
cnt_sysclk = 0; // System Clock Count Reset
pwm_freqXn = 0; // PWM Frequency Reset
end
else begin
if (cnt_sysclk >= temp - 1) begin // when Half of Cycle
cnt_sysclk = 0; // System Clock Count Reset
pwm_freqXn = ~pwm_freqXn; // PWM Frequency Generation
end
else cnt_sysclk = cnt_sysclk + 1; // Count System Clock
end
end
// Edge Detection of PWM Frequency
wire pwm_freqXn_nedge; // PWM Frequency Negative Edge
edge_detector_pos pwm_freqXn_ed (.clk(clk), .reset_p(reset_p),
.cp(pwm_freqXn), .n_edge(pwm_freqXn_nedge));
integer cnt_duty; // PWM Frequency Count
always @(posedge clk, posedge reset_p) begin
if (reset_p) begin
cnt_duty = 0; // PWM Frequency Count Reset
pwm = 0; // Pulse Reset
end
else if (pwm_freqXn_nedge) begin
if (cnt_duty >= duty_step_N) cnt_duty = 0; // Count to End of Duty
else cnt_duty = cnt_duty + 1; // Count PWM Frequency
if (cnt_duty < duty) pwm = 1; // Pulse High Until Duty
else pwm = 0; // Pulse Low After Duty
end
end
endmodule