|  **银杏科技有限公司旗下技术文档发布平台**  ||||
|技术支持电话|**0379-69926675-801**|||
|技术支持邮件|Gingko@vip.163.com|||
^  版本  ^  日期  ^  作者  ^  修改内容  ^
|  V1.0  |  2020-07-03 |  gingko  |  初次建立  | 
===== 实验十四:I2C实验——基于I2C的ARM与FPGA通信 =====
==== 一、 实验目的与意义 ====
  - 掌握I2C通信协议。
  - 掌握I2C时序及使用方法。
  - 掌握QuartusII的使用方法。
==== 二、 实验设备及平台 ====
  - iCore4 双核心板[[https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22598974120.15.5923532fsFrHiE&id=551864196684|点击购买]]。
  - Blaster(或相同功能)仿真器[[https://item.taobao.com/item.htm?id=554869837940|点击购买]]。
  - JLINK(或相同功能)仿真器。
  - Micro USB线缆。
  - Keil MDK 开发平台。
  - Quartus开发平台。
  - 电脑一台。
==== 三、 实验原理 ====
  * I2C是Inter-Integrated Circuit的缩写,是由Philips公司开发的一种简单的双向二线制同步串行总线。I2C通信的总线信号是双向的,但是对于通信的设备来说,有主从之分,支持一主多从或多主连接模式,这是由通信协议内部的设备地址所决定的。
  * I2C的两条总线:一条SDA(Serial Data Line),另一条SCL(Serial Clock)。其中,SCL总线方向总是由主机输向从机,在每个时钟上升沿到来时将数据写入每个从机设备中;SDA总线的方向是双向的,由主向从或由从向主,其数据的传输方向取决于命令内部的读写标志。其通信时序如图14-1所示:
{{ :icore4:icore4_fpga_14_1.png?direct |图14-1 I2C通信时序}}
  * 如图14-1,SCL一般由主机驱动发向从机。下面对开始标志(START)后的第一个字节进行解析:该字节主要包含器件专用地址码(高7位)和数据方向标志位(低1位),其中,专用地址码的高4位为器件类型,由厂家制定,低3位为器件引脚定义,由使用者定义。数据方向标志位,‘0’表示数据方向由主向从,‘1’表示数据方向由从向主。
  * 本实验通过FPGA建立的I2C模块对外提供SCL、SDA接口,与STM32的I2C总线相连接,Commix与STM32通过串口连接,实现三者之间的通信。本实验中,Commix向STM32发送数据STM32的RXD端口接收数据,然后通过I2C的数据总线(SDA)把数据发送至FPGA,STM32起到一个桥梁作用。程序运行后,FPGA收到数据后向STM32发送数据,经过STM32发送至Commix显示出来。下为实验原理图:
{{ :icore4:icore4_fpga_14_2.png?direct |图14-2 实验原理图}}
==== 四、 代码讲解 ====
1、在每个SCL的上升沿锁存数据并将数据拼接成完整的字节,其代码如下:
always@(posedge scl or negedge rst_n)
	if(!rst_n)
	    begin
		i <= 5'd0;
		data <= 64'd0;
		data_in <= 64'd0;
		rx_ack <= 1'd0;
	    end
	else if(rx_en)
		begin
		    case(i)
			5'd0,5'd1,5'd2,5'd3,5'd4,5'd5,5'd6,5'd7;//移位完成数据接收
				begin
					i <= i + 1'd1;
					rx_ack <= 1'd0;
					data_in <= {data_in[62:0],sda};
				end
			5'd8:
				begin
					if(data_in[7:0] == 8'h0d)
						begin
							i <= 5'd9;
							rx_ack <= 1'd1;
							data <= data_in;
						end
					else
						begin
							i <= 5'd0;
						end
				end
			5'd9:begin
				rx_ack <= 1'd0;
				i <= 5'd0;
				end
			default:i <= 5'd0;
		endcase
	end	
2、在每个读命令到来时发送GINGKO,其代码如下:
always@(negedge scl or negedge rst_n)
	if(!rst_n)
	    begin
		j <= 4'd0;
		send_data <= 1'd1;
		tx_ack <= 1'd0;
		tx_cnt <= 3'd0;
		data_out <= GINGKO;
	    end
	else case(j)
		4'd0,4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7:	//移位输出数据
		    begin
			if(tx_en)
			    begin
				j <= j + 1'd1;
				{send_data,data_out[47:1]} <= data_out;
				tx_ack <= 1'd0;
				end
			    end
		4'd8:begin
			if(tx_cnt == 3'd5)		//判断最后一个字节,停止发送
			    begin
				j <= j + 1'd1;
				tx_ack <= 1'd1;
				tx_cnt <= 3'd0;
			    end
			else 
			    begin
				j <= 4'd0;
				tx_ack <= 1'd0;	
				tx_cnt <= tx_cnt + 1'd1;
				end
			    end 
		4'd9:begin
				j <= 4'd0;
				tx_ack <= 1'd0;
				data_out <= GINGKO;
			     end
		4'd10:begin
				j <= 4'd0;
				tx_ack <= 1'd0;
		      end
	endcase	
==== 五、 实验步骤 ====
图14-3
  - 将硬件正确连接,如图14-3所示。
  - 打开Commix串口精灵,找到对应的COM口打开。
  - 打开Keil MDK开发环境,并打开实验工程。
  - 烧写ARM程序到iCore4上。
  - 打开QuartusII开发环境,并打开实验工程。
  - 烧写FPGA程序到iCore4上。
  - 输入串口命令,观察实验现象。
六、实验现象
  * 在Commix上发送命令后,对应的ARM和FPGA的LED灯亮,同时接收显示GINGKO。
|串口命令发送格式	|ARM_LED现象	|FPGA_LED灯现象|
|LEDR\CR\LF	|红灯亮	|红灯亮|
|LEDG\CR\LF	|绿灯亮	|绿灯亮|
|LEDB\CR\LF	|蓝灯亮	|蓝灯亮|