ADS7830 FPGA实现
ADS7830是TI的一款8bit,8channel AD转换芯片,对应通过I2c接口进行配置和读;以下是我用verilog编写的程序,已经验证过了,完全ok,输入的时钟是125MHz。经过分频成200Khz,采用的I2c接口时钟是100Khz模式;这里为了给上层模块应用,将inout类型的Sda在上层模块处理了;
module I2c_ADS7830 #(parameter DIV_PARA = 625)( input clk, input rst_n, input AD_req, input[2:0] AD_channel, output reg dout_valid, output reg [7:0] dout, // output reg flag0, output reg scl, input sda_in, output reg sda_out, output reg en ); localparam HARD_ADDR = 8'b1001_0000; localparam I2C_IDLE = 4'd0,I2C_START = 4'd1,I2C_HADDR = 4'd2,I2C_HADDR_ACK = 4'd3, I2C_CMD = 4'd4,I2C_CMD_ACK = 4'd5,I2C_RESTART = 4'd6,I2C_WRADDR = 4'd7, I2C_WRADDR_ACK = 4'd8,I2C_RDATA = 4'd9,I2C_NACK = 4'd10,I2C_STOP = 4'd11;
reg[3:0] current_state; reg[2:0] AD_channel_buf; reg[7:0] databuf; reg[7:0] doutbuf;
reg i2c_clk; reg[9:0] div_cnt; reg[3:0] i2c_cnt;
reg start_AD; reg ack_AD; reg finish_AD; reg finish_AD_reg0,finish_AD_reg1;
//always@(posedge clk or negedge rst_n) //if(~rst_n) // flag0 <= 1'b0; //else if(finish_AD) // flag0 <= 1'b1; //reg en; //reg sda_reg; // //assign sda = en ? sda_reg : 1'bz;
always@(posedge clk or negedge rst_n) if(~rst_n) i2c_clk <= 1'b0; else if(div_cnt==DIV_PARA-1) i2c_clk <= ~i2c_clk;
always@(posedge clk or negedge rst_n) if(~rst_n) div_cnt <= 10'd0; else if(div_cnt==DIV_PARA-1) div_cnt <= 10'd0; else div_cnt <= div_cnt + 10'd1;
always@(posedge clk or negedge rst_n) if(~rst_n) AD_channel_buf <= 3'd0; else if(AD_req) AD_channel_buf <= AD_channel;
always@(posedge clk or negedge rst_n) if(~rst_n) start_AD <= 1'b0; else if(AD_req) start_AD <= 1'b1; else if(ack_AD) start_AD <= 1'b0;
always@(posedge clk or negedge rst_n) if(~rst_n) begin finish_AD_reg0 <= 1'b0; finish_AD_reg1 <= 1'b0; end else begin finish_AD_reg0 <= finish_AD; finish_AD_reg1 <= finish_AD_reg0; end
always@(posedge clk or negedge rst_n) if(~rst_n) dout_valid <= 1'b0; else if(finish_AD_reg0 & !finish_AD_reg1) dout_valid <= 1'b1; else dout_valid <= 1'b0;
always@(posedge clk or negedge rst_n) if(~rst_n) dout <= 8'd0; else if(dout_valid) dout <= doutbuf;
always@(posedge i2c_clk or negedge rst_n) if(~rst_n) ack_AD <= 1'b0; else if(start_AD) ack_AD <= 1'b1; else ack_AD <= 1'b0; always@(posedge i2c_clk or negedge rst_n) if(~rst_n) finish_AD <= 1'b0; else if(current_state == I2C_STOP) finish_AD <= 1'b1; else finish_AD <= 1'b0; always@(posedge i2c_clk or negedge rst_n) if(~rst_n) i2c_cnt <= 4'd0; else
case(current_state) I2C_HADDR,I2C_CMD, I2C_WRADDR,I2C_RDATA: begin if(i2c_cnt==4'd15) i2c_cnt <= 4'd0; else i2c_cnt <= i2c_cnt + 4'd1; end I2C_START,I2C_HADDR_ACK,I2C_CMD_ACK, I2C_WRADDR_ACK,I2C_NACK,I2C_STOP: begin if(i2c_cnt==4'd1) i2c_cnt <= 4'd0; else i2c_cnt <= i2c_cnt + 4'd1; end I2C_RESTART: begin if(i2c_cnt==4'd2) i2c_cnt <= 4'd0; else i2c_cnt <= i2c_cnt + 4'd1; end default:i2c_cnt <= 4'd0; endcase
always@(posedge i2c_clk or negedge rst_n) if(~rst_n) current_state <= I2C_IDLE; else case(current_state) I2C_IDLE: begin if(start_AD) current_state <= I2C_START; end I2C_START: begin if(i2c_cnt==4'd1) current_state <= I2C_HADDR; end I2C_HADDR: begin if(i2c_cnt==4'd15) current_state <= I2C_HADDR_ACK; end I2C_HADDR_ACK: begin if(scl && !sda_in) current_state <= I2C_CMD; else if(scl && sda_in) current_state <= I2C_IDLE; // if(scl) // current_state <= I2C_CMD; end I2C_CMD: begin if(i2c_cnt==4'd15) current_state <= I2C_CMD_ACK; end I2C_CMD_ACK: begin if(scl && !sda_in) current_state <= I2C_RESTART; else if(scl && sda_in) current_state <= I2C_IDLE; // if(scl) // current_state <= I2C_RESTART; end I2C_RESTART: begin if(i2c_cnt==4'd2) current_state <= I2C_WRADDR; end I2C_WRADDR: begin if(i2c_cnt==4'd15) current_state <= I2C_WRADDR_ACK; end I2C_WRADDR_ACK: begin if(scl && !sda_in) current_state <= I2C_RDATA; else if(scl && sda_in) current_state <= I2C_IDLE; // if(scl) // current_state <= I2C_RDATA; end I2C_RDATA: begin if(i2c_cnt==4'd15) current_state <= I2C_NACK; end I2C_NACK: begin if(i2c_cnt==4'd1) current_state <= I2C_STOP; end I2C_STOP: begin if(i2c_cnt==4'd1) current_state <= I2C_IDLE; end default:current_state <= I2C_IDLE; endcase always@(posedge i2c_clk or negedge rst_n) if(~rst_n) begin scl <= 1'b0; en <= 1'b0; sda_out <= 1'b0; databuf <= 8'd0; doutbuf <= 8'd0; end else case(current_state) I2C_IDLE: begin scl <= 1'b1; sda_out <= 1'b1; en <= 1'b1; end I2C_START: begin if(i2c_cnt==4'd0) begin scl <= 1'b1; sda_out <= 1'b0; end else scl <= 1'b0; databuf <= HARD_ADDR; end I2C_HADDR: begin scl <= ~scl; if(!scl) begin sda_out <= databuf[7]; databuf <= {databuf[6:0],1'b0}; end end I2C_HADDR_ACK: begin en <= 1'b0; scl <= ~scl; databuf <= {1'b1,AD_channel_buf,4'b0100}; end I2C_CMD: begin en <= 1'b1; scl <= ~scl; if(!scl) begin sda_out <= databuf[7]; databuf <= {databuf[6:0],1'b0}; end end I2C_CMD_ACK: begin en <= 1'b0; scl <= ~scl; databuf <= HARD_ADDR + 1'b1; end I2C_RESTART: begin en <= 1'b1; if(i2c_cnt==4'd0) begin scl <= 1'b1; sda_out <= 1'b1; end else if(i2c_cnt==4'd1) begin sda_out <= 1'b0; scl <= 1'b1; end else scl <= 1'b0; databuf <= HARD_ADDR + 1'b1; end I2C_WRADDR: begin scl <= ~scl; if(!scl) begin sda_out <= databuf[7]; databuf <= {databuf[6:0],1'b0}; end end I2C_WRADDR_ACK: begin en <= 1'b0; scl <= ~scl; end I2C_RDATA: begin en <= 1'b0; scl <= ~scl; if(!scl) doutbuf <= {doutbuf[6:0],sda_in}; end I2C_NACK: begin en <= 1'b0; scl <= ~scl; end I2C_STOP: begin en <= 1'b1; scl <= 1'b1; if(i2c_cnt==4'd0) sda_out <= 1'b0; else sda_out <= 1'b1; end default:; endcase
endmodule