Files
2024-10-28 13:14:49 +08:00

161 lines
3.6 KiB
Verilog

`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