主机IIC的FPGA实现

代码很完善,很适合大家学习IIC协议的FPGA实现

`timescale 1ns / 1ps
//
module i2c_master
#(
parameter   CLK_DIV = 30
)
(
    input           i_clk,
    input           i_rst_n,
    input           i_start,
    input           wr,//1:read 0:write
    input  [6:0]    dev_addr,
    input  [7:0]    reg_addr,
    input  [7:0]    write_data,
    output reg [7:0]read_data,
    output reg      o_bsy,
    output reg      o_read_valid,
    //debug
    output reg [3:0]   state,
    output reg      sda_enable,
    //
    inout  tri      o_sda,
    output          o_scl
);

localparam [3:0] 
    S_IDLE = 0,
    S_START = 1,
    S_DEVICE = 3,
    S_CMD = 4,
    S_WAIT_CMD_ACK = 5,
    S_REGADDR = 6,
    S_WAIT_REGADDR_ACK = 7,
    S_WRITE_DATA = 8,
    S_WAIT_WRITE_ACK = 9,
    S_READ_DATA = 10,
    S_WRITE_ACK = 11,
    S_STOP = 12;

reg [15:0]  clk_cnt;
reg         clk_posedge;
reg         clk_negedge;
reg [3:0]   bit_cnt;
//reg         sda_enable;
reg         sda;
reg         scl;

//state machine
//reg [3:0]   state;
reg [3:0]   next_state;
reg         ack;
reg         read_cycle_en;
reg         start;
reg         wr_lock;
reg [6:0]   dev_addr_lock;
reg [7:0]   reg_addr_lock;
reg [7:0]   write_data_lock;

always @(posedge i_clk or negedge i_rst_n) begin
    if(!i_rst_n)
        clk_cnt <= 'd0;
    else if(clk_cnt < CLK_DIV - 1)
        clk_cnt <= clk_cnt + 1'b1;
    else clk_cnt <= 'd0;
end

always @(posedge i_clk or negedge i_rst_n) begin
    if(!i_rst_n)
        clk_posedge <= 1'b0;
    else if(clk_cnt==CLK_DIV/2 - 1)
        clk_posedge <= 1'b1;
    else clk_posedge <= 1'b0;
end

always @(posedge i_clk or negedge i_rst_n) begin
    if(!i_rst_n)
        clk_negedge <= 1'b0;
    else if(clk_cnt==CLK_DIV - 1)
        clk_negedge <= 1'b1;
    else clk_negedge <= 1'b0;
end

always @(posedge i_clk) begin
    if(state == S_IDLE)begin
        if(i_start)
            start <= 1'b1;
        else 
            start <= 1'b0; 
    end
    else 
        start <= 1'b0;
end

always @(posedge i_clk) begin
    if(state == S_IDLE && i_start)begin
        wr_lock         <= wr;     
        dev_addr_lock   <= dev_addr;
        reg_addr_lock   <= reg_addr;
        write_data_lock <= write_data;
    end
end

always @(posedge i_clk) begin
    if(state == S_WAIT_CMD_ACK || state == S_WAIT_REGADDR_ACK || state == S_WAIT_WRITE_ACK)
        ack <= o_sda;
    else
        ack <= 1'b1;
end

always @(posedge i_clk) begin
    if(state == S_IDLE)
        read_cycle_en <= 1'b0;
    else if(state == S_WAIT_REGADDR_ACK && wr_lock && clk_posedge)
        read_cycle_en <= 1'b1;
end

always @(posedge i_clk or negedge i_rst_n) begin
    if(!i_rst_n)
        state <= S_IDLE;
    else 
        state <= next_state;
end

always @(*)begin
    if(!i_rst_n)
        next_state = S_IDLE;
    else begin
        case(state)
            S_IDLE :begin
                if(start && clk_posedge)
                    next_state = S_START; 
                else 
                    next_state = S_IDLE;
            end
            S_START :begin
                if(clk_posedge)
                    next_state = S_DEVICE;
                else 
                    next_state = S_START; 
            end
            S_DEVICE :begin
                if(bit_cnt == 'd6 && clk_posedge)
                    next_state = S_CMD;
                else
                    next_state = S_DEVICE; 
            end
            S_CMD :begin
                if(clk_posedge)
                    next_state = S_WAIT_CMD_ACK;
                else
                    next_state = S_CMD; 
            end
            S_WAIT_CMD_ACK :begin
                if(clk_posedge)begin
                    if(ack)
                        next_state = S_IDLE;
                    else begin
                        if(read_cycle_en)
                            next_state = S_READ_DATA;
                        else
                            next_state = S_REGADDR; 
                    end     
                end
                else 
                    next_state = S_WAIT_CMD_ACK;
            end
            S_REGADDR :begin
                if(clk_posedge && bit_cnt == 'd7)
                    next_state = S_WAIT_REGADDR_ACK;
                else
                    next_state = S_REGADDR;
            end
            S_WAIT_REGADDR_ACK :begin
                if(clk_posedge)begin
                    if(ack)
                        next_state = S_IDLE;
                    else if(wr_lock)
                        next_state = S_START;
                    else
                        next_state = S_WRITE_DATA; 
                end
                else
                    next_state = S_WAIT_REGADDR_ACK;
            end
            S_WRITE_DATA :begin
                if(clk_posedge && bit_cnt == 'd7)
                    next_state = S_WAIT_WRITE_ACK;
                else
                    next_state = S_WRITE_DATA;
            end
            S_WAIT_WRITE_ACK :begin
                if(clk_posedge)begin
                    if(ack)
                        next_state = S_IDLE;
                    else 
                        next_state = S_STOP;      
                end
                else 
                    next_state = S_WAIT_WRITE_ACK;
            end
            S_READ_DATA :begin
                if(clk_posedge && bit_cnt == 'd7)
                    next_state = S_WRITE_ACK;
                else
                    next_state = S_READ_DATA;
            end
            S_WRITE_ACK :begin
                if(clk_posedge)
                    next_state = S_STOP;
                else 
                    next_state = S_WRITE_ACK;
            end
            S_STOP :begin 
                if(clk_posedge && bit_cnt == 1)
                    next_state = S_IDLE;
                else
                    next_state = S_STOP;
            end
        default:;
        endcase
    end 
end

always @(posedge i_clk) begin
    if(state == S_IDLE)
        scl <= 1'b1;
    else if(state == S_STOP)begin
        if(clk_negedge)
            scl <= 1'b1; 
    end
    else if(clk_posedge)
        scl <= 1'b0;
    else if(clk_negedge)
        scl <= 1'b1;
end

assign o_sda = (sda_enable)?sda:1'hz;
assign o_scl = scl;

always @(posedge i_clk) begin
    if(state == S_WAIT_CMD_ACK || state == S_WAIT_WRITE_ACK || state == S_WAIT_REGADDR_ACK || state == S_READ_DATA)
        sda_enable <= 1'b0;
    else 
        sda_enable <= 1'b1;
end

always @(posedge i_clk) begin
    if(state == S_IDLE)
        bit_cnt <= 'd0;
    else if(state != next_state)
        bit_cnt <= 'd0;
    else if(clk_posedge)
        bit_cnt <= bit_cnt + 1'b1;
end

always @(posedge i_clk ) begin
    case(state)
        S_IDLE :begin
            sda <= 1'b1;
        end
        S_START :begin
            if(!o_scl)
                sda <= 1'b1;
            else if(clk_cnt > CLK_DIV/4)
                sda <= 1'b0; 
        end
        S_DEVICE :begin
            if(bit_cnt < 'd7)
                sda <= dev_addr_lock >> (6 - bit_cnt); 
        end
        S_CMD :begin
            sda <= wr_lock;
        end
        S_REGADDR :begin
            if(bit_cnt < 'd8)
                sda <= reg_addr_lock >> (7 - bit_cnt); 
        end
        S_WRITE_DATA :begin
            if(bit_cnt < 'd8)
                sda <= write_data_lock >> (7 - bit_cnt); 
        end
        S_WRITE_ACK :begin
            sda <= 1'b1;
        end
        S_STOP :begin 
            if(o_scl)begin
                if(clk_posedge)
                    sda <= 1'b1;
            end
            else
                sda <= 1'b0;
        end
    endcase
end

always @(posedge i_clk) begin
    if(state == S_IDLE)
        read_data <= 8'hff;
    else if(state == S_READ_DATA && clk_posedge)
        read_data <= {o_sda,read_data[7:1]};
end

always @(posedge i_clk) begin
    if(o_read_valid)
        o_read_valid <= 1'b0;
    else if(state == S_READ_DATA && bit_cnt == 7 && clk_posedge)
        o_read_valid <= 1'b1;
end

always @(posedge i_clk) begin
    if(state == S_IDLE)
        o_bsy <= 1'b0;
    else 
        o_bsy <= 1'b1;
end

endmodule

IIC总线的FPGA实现是指使用FPGA芯片来实现IIC总线通信协议的功能。FPGA是一种可编程逻辑器件,可以根据需要进行配置和重新编程,因此可以用来实现各种数字电路和通信协议。在实现IIC总线时,FPGA可以通过配置其内部逻辑电路来模拟IIC总线的时序和通信协议。 具体实现IIC总线的FPGA设计需要考虑以下几个方面: 1. 配置FPGA的IO引脚:需要将FPGA的IO引脚连接到IIC总线的SDA和SCL信号线上,以实现数据和时钟的传输。 2. 实现IIC总线的时序:根据IIC总线的时序要求,FPGA需要在适当的时机产生时钟信号和数据信号的变化,以实现数据的传输和通信的控制。 3. 实现IIC总线的协议:FPGA需要根据IIC总线的协议规范,实现主机和从机之间的数据传输和通信控制。这包括发送起始信号、地址和数据的传输、接收应答信号等操作。 4. 实现主机和从机的功能:FPGA可以实现主机和从机的功能,可以作为主机发送数据或作为从机接收数据,也可以同时兼具主机和从机的功能。 总的来说,通过配置FPGA的内部逻辑电路,可以实现IIC总线的时序和通信协议,从而实现IIC总线的功能。具体的实现方式和细节可以根据具体的应用需求和FPGA芯片的特性来确定。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *3* [FPGA实现IIC协议(二)----IIC总线的FPGA实现(单次读写驱动)](https://blog.csdn.net/wuzhikaidetb/article/details/120752864)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [IIC总线的FPGA实现](https://blog.csdn.net/qq_43416206/article/details/129678657)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值