FPGA实现IIC驱动模块设计

(附源码)FPGA实现IIC通信,看完你就懂了!!!

1.前言

本次主要学习IIC通信协议的FPGA实现,并使用modelsim仿真,由于手中没有IIC相关的外设,所以本次暂时不进行板载验证,只进行时序逻辑仿真。本次源码工程地址如下:FPGA实现IIC通信quartus工程,纯verliog,可进行移植资源-优快云文库

2.IIC协议简介

IIC通信协议是一种串行通信总线,但其只有一根数据线,属于半双工通信协议,适用于传输距离较短的场景下使用。IIC由数据线SDA和时钟线SCL组成,数据线既可以用来发送数据,也可以用来接收数据,数据传输速率在标准模式下可以达到100kbit/s,在快速模式下可以达到400kbit/s,在高速模式下可以达到3.4Mbit/s,IIC的数据线和时钟线可以都会接上拉电阻,保证在没有进行数据传输时引脚电平处于高电平状态。

IIC支持多主和主从两种工作方式,其通常工作在主从工作模式,在主从工作模式下,系统只有一个主机,其他期间都是IIC总线的从机,在该工作模式下,主机产生时钟信号并启动数据发送和停止。IIC工作总线时序如下图所示。空闲状态数据线和时钟线均处于高电平,当相进行数据传输时,需要先把SDA数据线拉低,产生一个起始信号,当想停止数据传输时,将SDA数据线拉高,产生一个停止信号,此时再次回到空闲状态,有没有发现看到这里数据传输格式和串口通信有点像呢?不过这个可比串口通信复杂。

IIC通信包括读和写,这两个功能都是在同一条数据线上完成的,通过不同的读写位来控制。IIC通信开始后,会首先发送一个8位数据来选择器件以及读写控制,具体格式如下:

开始位-x6-x5-x4-x3-x2-x1-x0-R/W-ACK应答位

其中x0-x6位器件地址,这跟使用的具体器件有关,R/W为读写控制位,为1时表示主机对从机进行读操作,为0时表示主机对从机进行写操作,每发送一帧8位数据都需要从机应答,相反,进行读操作时,每读完8位数据,需要主机给予相应的应答信号。

IIC单次写时序图如下图所示。首先SDA数据线拉低发送起始信号,SCL时钟开启,SDA数据线首先发送期间地址和写命令,器件地址位变化只能在SCL电平为低电平时变化,因为SCL电平为高电平时从机会从SDA读取数据,当发送完一帧数据之后,从机会发送应答信号,主机接收到应答信号之后会继续发送下一帧数据,下面就是进行“虚写”,之所以称之为“虚写”是因为当我们需要向从机某个地址写数据时,需要先发送该地址,即“虚写”,之后发送要写的地址的高8位和低8位,分贝得到从机应答之后就可以将需要写的数据发送过去,写完之后如果不需要写数据了,就将电平拉高并且停止产生时钟,即发送停止信号,一次写操作完成。

一次写操作可以在指定地址写一个8位数据,当我们需要在连续的地址写多个8位数据时,是不是每次都需要发送器件地址和写地址再发送要写的数据呢?答案是否定的,当我们需要写的地址是连续的时,可以采用连续写的方式,即只发送一次器件地址和起始写地址就可以了,时序图如下图所示。在一次写数据完成之后,不发送停止信号,继续发送数据,这是会自动向开始地址的下一个地址写数据,直到发送停止信号。

同理,IIC读操作也是相同的操作。其时序图如下图所示。读操作同样首先是发送器件地址和要读的地址(此时处于写操作模式),之后重新发送起始信号、器件地址和读信号,就可以在指定的地址进行读数据了,读完一帧8位数据之后,需要主机房应答信号,从机收到应答信号之后才会继续发送数据,结束之后主机发送停止信号结束。同理,连续读同样是主机不发送停止信号继续读下一个地址的数据,直到发送停止信号。

至此,IIC协议时序部分就介绍到这里。

3.程序设计

FPGA程序设计主要在一个iic_driver模块中实现IIC在指定地址读和写一帧8位数据。程序中需要注意一个点就是inout引脚SDA,当读数据的时候读到8位数据需要输出一个应答信号,当写数据的时候,写完8位数据需要等待接收应答信号。inout数据只能通过assign赋值,一般通过三态门实现,当需要发送数据的时候为输出状态,当需要接收数据的时候为高阻态,这具体用法在程序中有体现。仿真发送一个8位数据如下图所示。

仿真接收一个8位数据如下图所示,可以看到接收完数据之后才更新8位数据。

下面贴一下部分代码供大家参考一下。

iic_driver.v

/*
	功能:IIC驱动模块设计
	作者:王志川
	时间:2024.7.5
*/
/*
	进度时间戳:
	2024.7.4 晚上实现发送器件地址+起始地址
	2024.7.5早上实现发送1个8位数据,并成功发送停止位。
	2024.7.5下午实现读取指定地址1个8位数据,并成功发送停止位。
*/
module iic_driver(
	input CLK,                      //50MHZ时钟信号
	input RST,                      //复位信号
	inout SDA,                      //IIC数据引脚
	input iic_rw,                   //IIC读写控制信号
	input iic_start,                //IIC起始信号,为1有效
	input [15:0]iic_data_addr,      //IIC要写数据的地址
	input [7:0]iic_data_w,          //IIC要写的数据
	output reg [7:0]iic_data_r,     //IIC读出的数据
	output reg [3:0]read_flag,           //读数据状态标志
	output reg iic_stop,            //IIC停止信号
	output reg write_done,          //IIC一次8位数据写完成标志位
	output reg SCL                  //IIC时钟引脚
);

//IIC时钟信号产生
parameter [8:0]scl_max=9'd250;//标准模式,100kbit/s
//parameter [8:0]scl_max=9'd63;//快速模式,400kbit/s
//parameter [8:0]scl_max=9'd7;//高速模式,3.4Mbit/s
reg [8:0]scl_cnt;//时钟计数周期
reg scl_en = 1'd0;//时钟使能信号
reg [3:0]sda_state;//数据发送状态
reg [3:0]cnt;//发送数据的位数
always@(posedge CLK or negedge RST)
begin
	if(!RST)begin
		SCL <= 1'd1;
		scl_cnt <= 9'd0;
	end
	else if(scl_en == 1'd1 && iic_start == 1'd1 && (iic_rw != 1'd1 || sda_state != 4'd3 || cnt != 4'd0 || scl_cnt != 9'd0))begin
		if(scl_cnt == scl_max-1)begin//计数到最大值
			SCL <= ~SCL;//时钟翻转
			scl_cnt <= 9'd0;//计数清零
		end
		else
			scl_cnt <= scl_cnt + 1'd1;
	end
	else begin
		SCL = 1'd1;
		scl_cnt <= 9'd0;
	end
end

iic_driver_tb.v

/*
	功能:IIC驱动模块设计
	作者:王志川
	时间:2024.7.5
*/
`timescale 1ns/1ps
module iic_driver_tb();

reg clk;
reg rst;
reg iic_rw;
reg iic_start;
reg [15:0]iic_data_addr;
reg [7:0]iic_data_w;
wire [7:0]iic_data_r;
wire [3:0]read_flag;
wire iic_stop;
wire write_done;
wire sda;
wire scl;

iic_driver iic_driver(
	.CLK(clk),                      //50MHZ时钟信号
	.RST(rst),                      //复位信号
	.SDA(sda),                      //IIC数据引脚
	.iic_rw(iic_rw),                //IIC读写控制信号,1为读,0为写
	.iic_start(iic_start),          //IIC起始信号,为1有效
	.iic_data_addr(iic_data_addr),  //IIC要写数据的地址
	.iic_data_w(iic_data_w),        //IIC要写的数据
	.iic_data_r(iic_data_r),        //IIC读出的数据
	.read_flag(read_flag),          //读数据状态标志
	.iic_stop(iic_stop),            //IIC停止信号
	.write_done(write_done),        //IIC一次8位数据写完成标志位
	.SCL(scl)                       //IIC时钟引脚
);

initial clk=1;
always #10 clk=!clk;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

得之坦然,失之淡然。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值