qq_15424193 2015-01-13 04:54 采纳率: 0%
浏览 2064

求大神给一份PCF8591的基于FPGA的verilog的IIc控制程序

求大神给一份PCF8591的基于FPGA的verilog的IIc控制程序

  • 写回答

1条回答

  • qq_35523202 2018-11-20 13:30
    关注

    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

    评论

报告相同问题?

悬赏问题

  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作