`timescale 1 ns / 1 ps module breath_gen# ( parameter CLK_PERIOD = 10 ) ( input clk , input rst_n , input enable , output pwm ); //***************************************************************************** // localparam definition //***************************************************************************** localparam PWM_PERIOD = 200000/CLK_PERIOD; localparam T_MS = 1000000/CLK_PERIOD; localparam IDLE = 4'd0; localparam UP_ST = 4'd1; localparam PEAK_ST = 4'd2; localparam DOWN_ST = 4'd3; localparam REST_ST = 4'd4; localparam T_UP_MS = 2000;//2000 localparam T_PEAK_MS = 1;//500 localparam T_DOWN_MS = 2000;//2000 localparam T_REST_MS = 200;//200 localparam STRENGTH = PWM_PERIOD; localparam T_UP_STEP = STRENGTH/T_UP_MS; localparam T_UP_MAX = T_UP_STEP*T_UP_MS; localparam T_DOWN_STEP = T_UP_MAX/T_DOWN_MS; localparam T_DOWN_MAX = T_DOWN_STEP*T_DOWN_MS; //***************************************************************************** // Internal register and wire declarations //***************************************************************************** reg [ 4-1:0] cstate ; reg [ 4-1:0] nstate ; reg [28-1:0] clk_cnt ; reg pulse_ms ; reg [16-1:0] ms_cnt ; reg [16-1:0] breath_data ; //***************************************************************************** // Instantiation //***************************************************************************** pwm_gen# ( .DATA_WIDTH ( 16 ) ) u_pwm_gen ( .clk ( clk ), .rst_n ( rst_n ), .enable ( enable ), .period ( PWM_PERIOD ), .duty ( breath_data ), .pwm ( pwm ) ); //***************************************************************************** always @ ( posedge clk or negedge rst_n ) begin if( !rst_n ) clk_cnt <= 0; else if ( ~enable ) clk_cnt <= 0; else if ( clk_cnt != T_MS - 1 ) clk_cnt <= clk_cnt + 1'b1; else clk_cnt <= 0; end always @ ( posedge clk or negedge rst_n ) begin if( !rst_n ) pulse_ms <= 1'b0; else if ( clk_cnt == T_MS - 1 ) pulse_ms <= 1'b1; else pulse_ms <= 1'b0; end always@( posedge clk or negedge rst_n ) begin if( !rst_n ) cstate <= IDLE; else if (~enable) cstate <= IDLE; else cstate <= nstate; end always@( * ) begin case ( cstate ) IDLE: if ( enable ) nstate <= UP_ST; else nstate <= IDLE; UP_ST: if( ms_cnt == T_UP_MS ) nstate <= PEAK_ST; else nstate <= UP_ST; PEAK_ST: if( ms_cnt == T_PEAK_MS ) nstate <= DOWN_ST; else nstate <= PEAK_ST; DOWN_ST: if( ms_cnt == T_DOWN_MS ) nstate <= REST_ST; else nstate <= DOWN_ST; REST_ST: if( ms_cnt == T_REST_MS ) nstate <= UP_ST; else nstate <= REST_ST; default: nstate <= IDLE; endcase end always @ ( posedge clk or negedge rst_n ) begin if( !rst_n ) ms_cnt <= 0; else if ( cstate != nstate ) ms_cnt <= 0; else if ( pulse_ms ) ms_cnt <= ms_cnt + 1'b1; end always @ ( posedge clk or negedge rst_n ) begin if( !rst_n ) breath_data <= 0; else if (cstate == IDLE) breath_data <= 0; else if ( pulse_ms && cstate == UP_ST ) breath_data <= breath_data + T_UP_STEP; else if ( pulse_ms && cstate == PEAK_ST ) breath_data <= breath_data; else if ( pulse_ms && cstate == DOWN_ST ) breath_data <= breath_data - T_DOWN_STEP; else if ( pulse_ms ) breath_data <= 0; end //***************************************************************************** // Wire assignment //***************************************************************************** endmodule