求大神给一份PCF8591的基于FPGA的verilog的IIc控制程序
module DAC_I2C
(
input clk_in, // system clock
input rst_n_in, // system reset, active low
input [7:0] dac_data, // dac data input
output reg dac_done, // dac transfer done
output scl_out, // I2C CLK
inout sda_out // I2C SDA
);
parameter CNT_NUM = 30;
localparam IDLE = 3'd0;
localparam MAIN = 3'd1;
localparam START = 3'd2;
localparam WRITE = 3'd3;
localparam ACK = 3'd4;
localparam STOP = 3'd5;
//generate clk_200khz clock
reg clk_200khz;
reg [5:0] cnt_200khz;
always@(posedge clk_in or negedge rst_n_in) begin
if(!rst_n_in) begin
cnt_200khz <= 5'd0;
clk_200khz <= 1'b0;
end else if(cnt_200khz >= CNT_NUM-1) begin
cnt_200khz <= 5'd0;
clk_200khz <= ~clk_200khz;
end else begin
cnt_200khz <= cnt_200khz + 1'b1;
end
end
//reg [7:0] cnt_wave;
reg scl_out_r;
reg sda_out_r;
reg [3:0] cnt_main;
reg [7:0] data_wr;
reg [1:0] cnt_start;
reg [4:0] cnt_write;
reg [1:0] cnt_ack;
reg [1:0] cnt_stop;
reg [2:0] state = IDLE;
reg [2:0] state_back = IDLE;
always@(posedge clk_200khz or negedge rst_n_in) begin
if(!rst_n_in) begin
//cnt_wave <= 8'd0;
scl_out_r <= 1'd1;
sda_out_r <= 1'd1;
cnt_main <= 4'd0;
cnt_start <= 2'd0;
cnt_write <= 5'd0;
cnt_ack <= 2'd0;
cnt_stop <= 2'd0;
state <= IDLE;
state_back <= IDLE;
end else begin
case(state)
IDLE:begin
scl_out_r <= 1'd1;
sda_out_r <= 1'd1;
cnt_main <= 4'd0;
cnt_start <= 2'd0;
cnt_write <= 5'd0;
cnt_ack <= 2'd0;
cnt_stop <= 2'd0;
state <= MAIN;
state_back <= MAIN;
end
MAIN:begin
//if(cnt_main >= 4'd8) cnt_main <= 4'd0; //write in byte mode
if(cnt_main >= 4'd6) cnt_main <= 4'd5; //write in chain mode
else cnt_main <= cnt_main + 1'b1;
case(cnt_main)
4'd0: begin state <= START; end
4'd1: begin data_wr <= 8'h90; state <= WRITE; end
4'd2: begin state <= ACK; end
4'd3: begin data_wr <= 8'h40; state <= WRITE; end
4'd4: begin state <= ACK; end
//4'd5: begin data_wr <= cnt_wave; cnt_wave <= cnt_wave+8'd8; state <= WRITE; end
4'd5: begin data_wr <= dac_data; state <= WRITE; dac_done <= 1'b0;end
4'd6: begin state <= ACK; dac_done <= 1'b1; end
4'd7: begin state <= STOP; end
4'd8: begin state <= IDLE; end
default: state <= IDLE;
endcase
end
START:begin
if(cnt_start >= 2'd2) cnt_start <= 1'b0;
else cnt_start <= cnt_start + 1'b1;
case(cnt_start)
2'd0: begin sda_out_r <= 1'b1; scl_out_r <= 1'b1; end
2'd1: begin sda_out_r <= 1'b0; end
2'd2: begin scl_out_r <= 1'b0; state <= MAIN; end
default: state <= IDLE;
endcase
end
WRITE:begin
if(cnt_write >= 5'd16) cnt_write <= 1'b0;
else cnt_write <= cnt_write + 1'b1;
case(cnt_write)
//transfer data with i2c
5'd0: begin sda_out_r <= data_wr[7]; scl_out_r <= 1'b0; end
5'd1: begin scl_out_r <= 1'b1; end
5'd2: begin sda_out_r <= data_wr[6]; scl_out_r <= 1'b0; end
5'd3: begin scl_out_r <= 1'b1; end
5'd4: begin sda_out_r <= data_wr[5]; scl_out_r <= 1'b0; end
5'd5: begin scl_out_r <= 1'b1; end
5'd6: begin sda_out_r <= data_wr[4]; scl_out_r <= 1'b0; end
5'd7: begin scl_out_r <= 1'b1; end
5'd8: begin sda_out_r <= data_wr[3]; scl_out_r <= 1'b0; end
5'd9: begin scl_out_r <= 1'b1; end
5'd10: begin sda_out_r <= data_wr[2]; scl_out_r <= 1'b0; end
5'd11: begin scl_out_r <= 1'b1; end
5'd12: begin sda_out_r <= data_wr[1]; scl_out_r <= 1'b0; end
5'd13: begin scl_out_r <= 1'b1; end
5'd14: begin sda_out_r <= data_wr[0]; scl_out_r <= 1'b0; end
5'd15: begin scl_out_r <= 1'b1; end
5'd16: begin scl_out_r <= 1'b0; state <= MAIN; end
default: state <= IDLE;
endcase
end
ACK:begin
if(cnt_ack >= 2'd3) cnt_ack <= 1'b0;
else cnt_ack <= cnt_ack + 1'b1;
case(cnt_ack)
//read bit 0
2'd0: begin sda_out_r <= 1'bz; end
2'd1: begin scl_out_r <= 1'b1; end
2'd2: begin if(sda_out) state <= IDLE; else state <= state; end
2'd3: begin scl_out_r <= 1'b0; state <= MAIN; end
default: state <= IDLE;
endcase
end
STOP:begin
if(cnt_stop >= 2'd2) cnt_stop <= 1'b0;
else cnt_stop <= cnt_stop + 1'b1;
case(cnt_stop)
2'd0: begin sda_out_r <= 1'b0; end
2'd1: begin scl_out_r <= 1'b1; end
2'd2: begin sda_out_r <= 1'b1; state <= MAIN; end
default: state <= IDLE;
endcase
end
endcase
end
end
assign scl_out = scl_out_r;
assign sda_out = sda_out_r;
endmodule