用户工具

站点工具


icore4tx_fpga_19
银杏科技有限公司旗下技术文档发布平台
技术支持电话0379-69926675-801
技术支持邮件Gingko@vip.163.com
版本 日期 作者 修改内容
V1.0 2020-07-01 gingko 初次建立

实验十九:I2C实验——基于I2C的ARM与FPGA通信

一、 实验目的与意义

  1. 掌握I2C通信协议。
  2. 掌握I2C时序及通信流程。
  3. 掌握ISE软件的使用方法。

二、 实验设备及平台

  1. iCore4TX 双核心板点击购买
  2. USB-CABLE(或相同功能)仿真器。
  3. JLINK(或相同功能)仿真器点击购买
  4. Micro USB线缆。
  5. Keil MDK 开发平台。
  6. ISE开发平台。
  7. 电脑一台。

三、 实验原理

  • I2C是Inter-Integrated Circuit的缩写,是由Philips公司开发的一种简单的双向二线制同步串行总线。I2C通信的总线信号是双向的,但是对于通信的设备来说,有主从之分,支持一主多从货多主连接模式,这是由通信协议内部的设备地址所决定的。
  • I2C的两条总线:一条SDA(Serial Data Line),另一条SCL(Serial Clock)。其中,SCL总线方向总是由主机输向从机,在每个时钟上升沿到来时将数据写入每个从机设备中;SDA总线的方向是双向的,由主向从或由从向主,其数据的传输方向取决于命令内部的读写标志。其通信时序如图19.1所示:

图19-1  I2C通信时序

  • 如图19-1,SCL一般由主机驱动发向从机。下面对开始标志(START)后的第一个字节进行解析:该字节主要包含器件专用地址码(高7位)和数据方向标志位(低1位),其中,专用地址码的高4位为器件类型,由厂家制定,低3位位器件引脚定义,由使用者定义。数据方向标志位,‘0’表示数据方向由主向从,‘1’表示数据方向由从向主。
  • 本实验是将FPGA自身仿真成一个容量为256Byte的eeprom,按照标准eeprom的标准通信时序进行通信,其写时序如图19-2所示,读时序如图19-3所示。

图19-2 写时序 图19-3 读时序

四、 代码讲解

1、正常情况下,数据的变化都发生在SCL的低电平,只有起始标志时,SDA的变化发生在SCL的高电平。根据这个特点,提取每次命令交互的开始标志,其代码如下:

always@(negedge i2c_sda or negedge rst_n or posedge cmd_over)
    begin
        if(!rst_n)
            begin
                rx_start_r <= 1'd0;
            end 
        else if(cmd_over)
            begin
                rx_start_r <= 1'd0;
            end
        else if(i2c_scl)
            begin
                rx_start_r <= 1'd1;
            end 
    end

2、在每个SDL的上升沿锁存数据并将数据拼接成完整的字节,其代码如下:

always@(posedge i2c_scl or negedge rst_n or posedge rx_start)
    begin
        if((!rst_n)||(rx_start))
            begin
                receive_byte_r <= 8'd0;
                rx_state <= 8'd0;
                rx_over <= 1'd0;
                data_over <= 1'd0;
            end
        else
            begin
                case(rx_state)
                    8'd0:begin
                        rx_state <= rx_state + 1'd1;
                        receive_byte_r[7] <= i2c_sda;                       
                    end
                    8'd1:begin
                        rx_state <= rx_state + 1'd1;
                        receive_byte_r[6] <= i2c_sda;
                    end
                    8'd2:begin
                        rx_state <= rx_state + 1'd1;
                        receive_byte_r[5] <= i2c_sda;
                    end
                    8'd3:begin
                        rx_over <= 1'd0;
                        rx_state <= rx_state + 1'd1;
                        receive_byte_r[4] <= i2c_sda;
                    end   
                   8'd4:begin
                        rx_state <= rx_state + 1'd1;
                        receive_byte_r[3] <= i2c_sda;
                    end
                    8'd5:begin
                        rx_state <= rx_state + 1'd1;
                        receive_byte_r[2] <= i2c_sda;
                    end
                    8'd6:begin
                        rx_state <= rx_state + 1'd1;
                        receive_byte_r[1] <= i2c_sda;
                    end
                    8'd7:begin
                        rx_state <= rx_state + 1'd1;
                        receive_byte_r[0] <= i2c_sda;
                        data_over <= 1'd1;
                    end
                    8'd8:begin
                        rx_state <= 8'd0;
                        rx_over <= 1'd1;
                        data_over <= 1'd0;
                    end
                    default:begin
                    end
                endcase
            end 
    end

3、在给个数据拼接完成后,对该数据进行二级存储,并根据接收的自己数目产生RAM的读写时钟信号和命令完成标志,其代码下:

always@(posedge rx_over or negedge rst_n or posedge rx_start)
    begin
        if(!rst_n)
            begin
                ack_state <= 4'd0;
                address_r <= 8'd0;
                rx_data <= 8'd0;
                wr_clk_r <= 1'd0;
                rd_clk_r <= 1'd0;
                cmd_over_r <= 1'd1;
            end
        else if(rx_start)
            begin
                ack_state <= 4'd0;
                wr_clk_r <= 1'd0;
                cmd_over_r <= 1'd0;
            end
        else
            begin
                case(ack_state)
                    4'd0:begin
                        if(receive_byte_r==8'ha0)
                            begin
                                ack_state <= ack_state + 1'd1;
                            end
                        else if(receive_byte_r==8'ha1)
                            begin
                                rd_clk_r <= 1'd1;
                                ack_state <= 4'd3;
                            end
                        else
                            begin
                                ack_state <= ack_state;
                            end
                    end
                    4'd1:begin//锁存地址信息
                        address_r <= receive_byte_r;
                        ack_state <= ack_state + 1'd1;
                        cmd_over_r <= 1'd1;
                    end
                    4'd2:begin//接收写入RAM的数据
                        rx_data <= receive_byte_r;
                        wr_clk_r <= 1'd1;
                    end
                    4'd3:begin
                        rd_clk_r <= 1'd0;
                        cmd_over_r <= 1'd1;
                    end
                    default:begin
                    end
                endcase
            end
    end

4、在每个读命令到来时发送,读取的数据,其代码如下:

always@(negedge i2c_scl or negedge rst_n or posedge rx_start)
    begin
        if((!rst_n)||(rx_start))
            begin
                sda_r <= 1'hz;
                send_state <= 8'd0;
            end
        else
            begin
                case(send_state)
                    8'd0:begin
                        if(data_over)
                            begin
                                if(receive_byte_r==8'ha0)
                                    begin
                                        sda_r <= 1'd0;
                                    end
                                else if(receive_byte_r==8'ha1)
                                    begin
                                        sda_r <= 1'd0;
                                        send_state <= 8'd3;
                                    end
                                else
                                    begin
                                        sda_r <= 1'hz;
                                    end
                            end
                        else
                            begin
                                send_state <= send_state;
                            end
                    end
                    8'd1:begin
                        if(data_over)
                            begin
                                sda_r <= 1'd0;
                                send_state <= send_state + 1'd1;
                            end
                        else
                            begin
                                sda_r <= 1'hz;
                            end
                    end
                    8'd2:begin
                        if(data_over)
                            begin
                                sda_r <= 1'd0;
                            end
                        else
                            begin
                                sda_r <= 1'hz;
                            end
                    end
                    8'd3:begin
                        {sda_r,send_data[7:1]} <= data_out;
                        send_state <= send_state + 1'd1;
                    end     
                    8'd4,8'd5,8'd6,8'd7,8'd8,8'd9,8'd10,:begin
                        {sda_r,send_data[7:1]} <= send_data;
                        send_state <= send_state + 1'd1;
                    end
                    8'd11:begin
                        sda_r <= 1'hz;
                    end
                    default:begin
                    end
                endcase
            end
    end

五、 实验步骤及实验结果

图19-4

  1. 将硬件正确连接,如图19-4所示。
  2. 打开putty串口调试工具,打开设备管理器查看对应的端口信息,在putty中打开对应的端口,设置波特率115200,用于打印串口信息;
  3. 将编写好的FPGA代码进行编译,并下载到开发板中;
  4. 将编写好的ARM代码编译,并下载到开发板中,在putty串口调试工具中输入“test”,开始执行读写操作;
  5. 观察现象及putty终端打印信息——FPGA_LED闪烁,putty终端打印如下图所示:

图19-5

六、 拓展实验

1.通过chipscope观察I2C通信时序是否和参考时序一致。

icore4tx_fpga_19.txt · 最后更改: 2022/04/01 11:39 由 sean