安德鲁

[笔记].小练Verilog版本PWM驱动步进电机

0
阅读(10918)

硬件:MAX II EPM240T100C5
软件:Quartus II 10.0

step_motor.v

module step_motor
	//#(parameter RPM50 = 40, RPM300 = 6)
	#(parameter RPM50 = 1000, RPM300 = 3)
	(
	    // global clock and asyn  reset
	    input CLOCK_50,
	    input RST_N,
	    // step motor interface
	    output wire ENA,
	    output wire PUL,
	    output wire DIR,
	    //test
	    output wire PIN_64
	);
	//assign PIN_64 = pwm_out;
	 
	localparam SUBDIVISION = 64;
	 
	function integer log2(input integer n);
	    integer i;
	    for(i=0; 2**i <=n; i=i+1) log2=i+1;
	endfunction
	 
	// generate 6KHz tick
	localparam DIV_50M_INTO_6K = 8333 / SUBDIVISION;
	reg [log2(DIV_50M_INTO_6K):1] cnt0; // 0~8332
	 
	always@(posedge CLOCK_50)
	    if(DIV_50M_INTO_6K-1 == cnt0) cnt0 <= 0;
	    else cnt0 <= cnt0 + 1'b1;
	   
	wire tick_6KHz = (DIV_50M_INTO_6K-1 == cnt0) ? 1 : 0;
	 
	// generate pulse signal at low frequency
	localparam DIV_1SEC = 50_000_000; // 10Hz
	reg [log2(DIV_1SEC):1] cnt1;
	always@(posedge CLOCK_50, negedge RST_N)
	        if(!RST_N) cnt1 <= 0;
               else if (cnt1 == DIV_1SEC - 1) cnt1 <= 0;
	        else cnt1 <= cnt1 + 1;
	  
	 
	reg [log2(RPM50):1] period;
	reg acc_dec;
	always@(posedge CLOCK_50, negedge RST_N)
	    if(!RST_N)  begin
	        period <= RPM50;
	        //acc_dec <= 0;
	    end
	    else if(cnt1 == DIV_1SEC - 1)  begin
	        //if(period == RPM300) acc_dec <= ~acc_dec;
	         
	        //if(acc_dec)  begin
	            if(period == RPM300) period <= RPM50;
	            else period <= period - 1;
	        //end  
	        //period <= RPM50;
	        //else  period <= period - 1;
	    end
	 
	wire adjust_enable = (cnt1 == DIV_1SEC - 1)  ? 1 : 0;
	   
	/* PWM */
	wire pwm_out;
	pwm_generator #(.N(log2(RPM50)), .START_SPEED(RPM50)) pwm_generator_inst
	(
	    // global clock and asyn reset
            .CLOCK_50(CLOCK_50),
	    .RST_N(RST_N),
	    // clock enable tick
	    .clock_enable(tick_6KHz),
	    // PWM interface
	    .adjust_enable(adjust_enable),
	    .period(period),
	    .pwm_out(pwm_out)
	);
	 
	assign PUL = pwm_out;
	assign ENA = 1;
	assign DIR = 0;
	 
	endmodule

pwm_generator.v

module pwm_generator
	#(parameter N=10, START_SPEED = 100)
	(
	    // global clock and asyn reset
	    input CLOCK_50,
	    input RST_N,
	    // clock enable tick
	    input clock_enable,
	    // PWM interface
	    input adjust_enable,
	    input [N:1] period,
	    output reg pwm_out
	);
	 
	reg [N:1] period_r;
        reg [N:1] pulse_width_r;
	 
	// pass the parameter
	always@(posedge CLOCK_50, negedge RST_N)
	    if(!RST_N)    begin
	        period_r <= START_SPEED;
	        pulse_width_r <= START_SPEED >> 1;
	    end
	    else if(adjust_enable) begin
	        period_r <= period;
	        pulse_width_r <= period >> 1;
	    end
	 
	// counter
	reg [N:1] cnt;   
	always@(posedge CLOCK_50, negedge RST_N)
	    if(!RST_N) cnt <= 0;
	    else if(clock_enable) begin
	        if(cnt == period_r) cnt <= 0;
	        else cnt <= cnt + 1'b1;
	    end
	 
	// generate pulse   
	always@(posedge    CLOCK_50, negedge RST_N)
	    if(!RST_N) pwm_out <= 0;
	    else if(clock_enable) begin
	        if(cnt < pulse_width_r) pwm_out <= 1;
	        else pwm_out <= 0;
	    end
	     
	endmodule