协议——IIC
I²C即Inter-Integrated Circuit(集成电路总线),它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代设计出来的一种简单、双向、二线制总线标准。多用于主机和从机在数据量不大且传输距离短的场合下的主从通信。主机启动总线,并产生时钟用于传送数据,此时任何接收数据的器件均被认为是从机。I²C总线由数据线SDA和时钟线SCL构成通信线路,既可用于发送数据,也可接收数据。在主控与被控IC之间可进行双向数据传送,数据的传输速率在标准模式下可达100kbit/s,在快速模式下可达400kbit/s,在高速模式下可达3.4Mbit/s,各种被控器件均并联在总线上,通过器件地址(SLAVE ADDR,具体可查器件手册)识别。I²C总线物理拓扑结构图如下所示:
//**************************************************************************
// *** 名称 : iic.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2019-08-10
// *** 描述 : IIC控制器
//************************************************************************** module iic
//========================< 参数 >==========================================
#(
parameter DEVICE_ID = 'b1010000 , //器件ID
parameter CLK = 'd50_000_000 , //本模块的时钟频率
parameter SCL = 'd250_000 //输出的SCL时钟频率
)
//========================< 端口 >==========================================
(
input clk , //时钟
input rst_n , //复位,低电平有效
//IIC control ---------------------------------------
input iic_en , //IIC触发信号
input addr16_en , //16位地址使能
input addr8_en , //8位地址使能
input write_en , //IIC写使能
input read_en , //IIC读使能
input [:] iic_addr , //IIC器件内地址
input [ :] iic_data_wr , //IIC要写的数据
//IIC output ----------------------------------------
output reg [ :] iic_data_rd , //IIC读出的数据
output reg iic_done , //IIC一次操作完成
output reg iic_scl , //IIC的SCL时钟信号
inout iic_sda , //IIC的SDA数据信号
//dri_clk -------------------------------------------
output reg iic_dri_clk //驱动IIC操作的驱动时钟,1Mhz
);
//========================< 参数 >==========================================
localparam IDLE = 'b0000_0001 ; //空闲状态
localparam DEVICE = 'b0000_0010 ; //写器件地址
localparam ADDR_16 = 'b0000_0100 ; //写字地址高8位
localparam ADDR_8 = 'b0000_1000 ; //写字地址低8位
localparam DATA_WR = 'b0001_0000 ; //写数据
localparam DEVICE_RD = 'b0010_0000 ; //虚写器件地址
localparam DATA_RD = 'b0100_0000 ; //读数据
localparam STOP = 'b1000_0000 ; //结束
//========================< 信号 >==========================================
reg sda_dir ; //IIC数据(SDA)方向控制
reg sda_out ; //SDA输出信号
wire sda_in ; //SDA输入信号
reg state_done ; //状态结束
reg [ :] cnt ; //计数
reg [ :] state_c ; //状态机当前状态
reg [ :] state_n ; //状态机下一状态
reg [:] iic_addr_t ; //地址
reg [ :] iic_data_rd_t ; //读取的数据
reg [ :] iic_data_wr_t ; //IIC需写的数据的临时寄存
reg [ :] clk_cnt ; //分频时钟计数
wire [ :] clk_divide ; //模块驱动时钟的分频系数 //==========================================================================
//== sda控制
//==========================================================================
assign iic_sda = sda_dir ? sda_out : 'bz; //SDA数据输出或高阻
assign sda_in = iic_sda ; //SDA数据输入 //==========================================================================
//== 生成SCL的4倍时钟来驱动后面IIC的操作,生成1Mhz的iic_dri_clk
//==========================================================================
assign clk_divide = (CLK/SCL) >> ; // >>3即除以8 always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
iic_dri_clk <= 'b1;
clk_cnt <= 'd0;
end
else if(clk_cnt == clk_divide - 'd1) begin
clk_cnt <= 'd0;
iic_dri_clk <= ~iic_dri_clk;
end
else
clk_cnt <= clk_cnt + 'b1;
end //==========================================================================
//== 状态机
//==========================================================================
always @(posedge iic_dri_clk or negedge rst_n) begin
if(!rst_n)
state_c <= IDLE;
else
state_c <= state_n;
end always @(*) begin
case(state_c)
IDLE: begin //空闲状态
if(iic_en) begin
state_n = DEVICE;
end
else
state_n = IDLE;
end
DEVICE: begin //写器件ID
if(state_done) begin
if(addr16_en)
state_n = ADDR_16;
else if(addr8_en)
state_n = ADDR_8 ;
end
else
state_n = DEVICE;
end
ADDR_16: begin //写地址高8位
if(state_done)
state_n = ADDR_8;
else
state_n = ADDR_16;
end
ADDR_8: begin //写地址低8位
if(state_done) begin
if(write_en)
state_n = DATA_WR;
else if(read_en)
state_n = DEVICE_RD;
end
else
state_n = ADDR_8;
end
DATA_WR: begin //写数据
if(state_done)
state_n = STOP;
else
state_n = DATA_WR;
end
DEVICE_RD: begin //虚写器件ID
if(state_done)
state_n = DATA_RD;
else
state_n = DEVICE_RD;
end
DATA_RD: begin //读数据
if(state_done)
state_n = STOP;
else
state_n = DATA_RD;
end
STOP: begin //结束
if(state_done)
state_n = IDLE;
else
state_n = STOP ;
end
default:state_n= IDLE;
endcase
end //==========================================================================
//== 设计各路信号
//==========================================================================
always @(posedge iic_dri_clk or negedge rst_n) begin
if(!rst_n) begin
iic_scl <= 'b1;
sda_out <= 'b1;
sda_dir <= 'b1;
iic_done <= 'b0;
cnt <= 'b0;
state_done <= 'b0;
iic_addr_t <= 'b0;
iic_data_rd <= 'b0;
iic_data_rd_t <= 'b0;
iic_data_wr_t <= 'b0;
end
else begin
state_done <= 'b0 ;
cnt <= cnt +'b1 ;
case(state_c)
//--------------------------------------------------- 空闲状态
IDLE: begin
iic_scl <= 'b1;
sda_out <= 'b1;
sda_dir <= 'b1;
iic_done <= 'b0;
cnt <= 'b0;
if(iic_en) begin
iic_addr_t <= iic_addr;
iic_data_wr_t <= iic_data_wr;
end
end
//--------------------------------------------------- 写器件ID
DEVICE: begin
case(cnt)
'd1 : sda_out <= 1'b0;
'd3 : iic_scl <= 1'b0;
'd4 : sda_out <= DEVICE_ID[6];
'd5 : iic_scl <= 1'b1;
'd7 : iic_scl <= 1'b0;
'd8 : sda_out <= DEVICE_ID[5];
'd9 : iic_scl <= 1'b1;
'd11: iic_scl <= 1'b0;
'd12: sda_out <= DEVICE_ID[4];
'd13: iic_scl <= 1'b1;
'd15: iic_scl <= 1'b0;
'd16: sda_out <= DEVICE_ID[3];
'd17: iic_scl <= 1'b1;
'd19: iic_scl <= 1'b0;
'd20: sda_out <= DEVICE_ID[2];
'd21: iic_scl <= 1'b1;
'd23: iic_scl <= 1'b0;
'd24: sda_out <= DEVICE_ID[1];
'd25: iic_scl <= 1'b1;
'd27: iic_scl <= 1'b0;
'd28: sda_out <= DEVICE_ID[0];
'd29: iic_scl <= 1'b1;
'd31: iic_scl <= 1'b0;
'd32: sda_out <= 1'b0; //0:写
'd33: iic_scl <= 1'b1;
'd35: iic_scl <= 1'b0;
'd36: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd37: iic_scl <= 1'b1;
'd38: state_done <= 1'b1; //状态结束
'd39: begin
iic_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 写字地址高8位
ADDR_16: begin
case(cnt)
'd0 : begin
sda_dir <= 'b1 ;
sda_out <= iic_addr_t[];
end
'd1 : iic_scl <= 1'b1;
'd3 : iic_scl <= 1'b0;
'd4 : sda_out <= iic_addr_t[14];
'd5 : iic_scl <= 1'b1;
'd7 : iic_scl <= 1'b0;
'd8 : sda_out <= iic_addr_t[13];
'd9 : iic_scl <= 1'b1;
'd11: iic_scl <= 1'b0;
'd12: sda_out <= iic_addr_t[12];
'd13: iic_scl <= 1'b1;
'd15: iic_scl <= 1'b0;
'd16: sda_out <= iic_addr_t[11];
'd17: iic_scl <= 1'b1;
'd19: iic_scl <= 1'b0;
'd20: sda_out <= iic_addr_t[10];
'd21: iic_scl <= 1'b1;
'd23: iic_scl <= 1'b0;
'd24: sda_out <= iic_addr_t[9];
'd25: iic_scl <= 1'b1;
'd27: iic_scl <= 1'b0;
'd28: sda_out <= iic_addr_t[8];
'd29: iic_scl <= 1'b1;
'd31: iic_scl <= 1'b0;
'd32: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd33: iic_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
iic_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 写字地址低8位
ADDR_8: begin
case(cnt)
'd0: begin
sda_dir <= 'b1 ;
sda_out <= iic_addr_t[];
end
'd1 : iic_scl <= 1'b1;
'd3 : iic_scl <= 1'b0;
'd4 : sda_out <= iic_addr_t[6];
'd5 : iic_scl <= 1'b1;
'd7 : iic_scl <= 1'b0;
'd8 : sda_out <= iic_addr_t[5];
'd9 : iic_scl <= 1'b1;
'd11: iic_scl <= 1'b0;
'd12: sda_out <= iic_addr_t[4];
'd13: iic_scl <= 1'b1;
'd15: iic_scl <= 1'b0;
'd16: sda_out <= iic_addr_t[3];
'd17: iic_scl <= 1'b1;
'd19: iic_scl <= 1'b0;
'd20: sda_out <= iic_addr_t[2];
'd21: iic_scl <= 1'b1;
'd23: iic_scl <= 1'b0;
'd24: sda_out <= iic_addr_t[1];
'd25: iic_scl <= 1'b1;
'd27: iic_scl <= 1'b0;
'd28: sda_out <= iic_addr_t[0];
'd29: iic_scl <= 1'b1;
'd31: iic_scl <= 1'b0;
'd32: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd33: iic_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
iic_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 写数据
DATA_WR: begin
case(cnt)
'd0: begin
sda_out <= iic_data_wr_t[];
sda_dir <= 'b1;
end
'd1 : iic_scl <= 1'b1;
'd3 : iic_scl <= 1'b0;
'd4 : sda_out <= iic_data_wr_t[6];
'd5 : iic_scl <= 1'b1;
'd7 : iic_scl <= 1'b0;
'd8 : sda_out <= iic_data_wr_t[5];
'd9 : iic_scl <= 1'b1;
'd11: iic_scl <= 1'b0;
'd12: sda_out <= iic_data_wr_t[4];
'd13: iic_scl <= 1'b1;
'd15: iic_scl <= 1'b0;
'd16: sda_out <= iic_data_wr_t[3];
'd17: iic_scl <= 1'b1;
'd19: iic_scl <= 1'b0;
'd20: sda_out <= iic_data_wr_t[2];
'd21: iic_scl <= 1'b1;
'd23: iic_scl <= 1'b0;
'd24: sda_out <= iic_data_wr_t[1];
'd25: iic_scl <= 1'b1;
'd27: iic_scl <= 1'b0;
'd28: sda_out <= iic_data_wr_t[0];
'd29: iic_scl <= 1'b1;
'd31: iic_scl <= 1'b0;
'd32: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd33: iic_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
iic_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 虚写器件ID
DEVICE_RD: begin
case(cnt)
'd0 : begin
sda_dir <= 'b1;
sda_out <= 'b1;
end
'd1 : iic_scl <= 1'b1;
'd2 : sda_out <= 1'b0; //重新开始
'd3 : iic_scl <= 1'b0;
'd4 : sda_out <= DEVICE_ID[6];
'd5 : iic_scl <= 1'b1;
'd7 : iic_scl <= 1'b0;
'd8 : sda_out <= DEVICE_ID[5];
'd9 : iic_scl <= 1'b1;
'd11: iic_scl <= 1'b0;
'd12: sda_out <= DEVICE_ID[4];
'd13: iic_scl <= 1'b1;
'd15: iic_scl <= 1'b0;
'd16: sda_out <= DEVICE_ID[3];
'd17: iic_scl <= 1'b1;
'd19: iic_scl <= 1'b0;
'd20: sda_out <= DEVICE_ID[2];
'd21: iic_scl <= 1'b1;
'd23: iic_scl <= 1'b0;
'd24: sda_out <= DEVICE_ID[1];
'd25: iic_scl <= 1'b1;
'd27: iic_scl <= 1'b0;
'd28: sda_out <= DEVICE_ID[0];
'd29: iic_scl <= 1'b1;
'd31: iic_scl <= 1'b0;
'd32: sda_out <= 1'b1; //1:读
'd33: iic_scl <= 1'b1;
'd35: iic_scl <= 1'b0;
'd36: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd37: iic_scl <= 1'b1;
'd38: state_done <= 1'b1; //状态结束
'd39: begin
iic_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 读数据
DATA_RD: begin
case(cnt)
'd0 : sda_dir <= 1'b0;
'd1 : begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd3 : iic_scl <= 1'b0;
'd5 : begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd7 : iic_scl <= 1'b0;
'd9 : begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd11: iic_scl <= 1'b0;
'd13: begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd15: iic_scl <= 1'b0;
'd17: begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd19: iic_scl <= 1'b0;
'd21: begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd23: iic_scl <= 1'b0;
'd25: begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd27: iic_scl <= 1'b0;
'd29: begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1 ;
end
'd31: iic_scl <= 1'b0;
'd32: begin
sda_dir <= 'b1; //非应答
sda_out <= 'b1;
end
'd33: iic_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
iic_scl <= 'b0;
cnt <= 'b0;
iic_data_rd <= iic_data_rd_t;
end
default : ;
endcase
end
//--------------------------------------------------- 结束
STOP: begin
case(cnt)
'd0 : begin
sda_dir <= 'b1;
sda_out <= 'b0;
end
'd1 : iic_scl <= 1'b1;
'd3 : sda_out <= 1'b1;
'd15: state_done <= 1'b1; //状态结束
'd16: begin
cnt <= 'b0;
iic_done <= 'b1; //IIC配置完成
end
default : ;
endcase
end
endcase
end
end endmodule
协议——IIC的更多相关文章
- 协议—IIC
I2C总线支持任何IC生产过程NMOS CMOS双极性,两线――串行数据 SDA 和串行时钟SCL线在连接到总线的器件间传递信息,每个器件都有一个唯一的地址识别,无论是微控制器.LCD 驱动器.存储器 ...
- FPGA基础设计(四):IIC协议
很多数字传感器.数字控制的芯片(DDS.串行ADC.串行DAC)都是通过IIC总线来和控制器通信的.不过IIC协议仍然是一种慢速的通信方式,标准IIC速率为100kbit/s,快速模式速率为400kb ...
- 九、IIC驱动原理分析
学习目标:学习IIC驱动原理: 一.IIC总线协议 IIC串行总线包括一条数据线(SDA)和一条时钟线(SCL),支持“一主多从”和“多主机”模式:每个从机设备都有唯一的地址来识别. 图 1 IIC ...
- 【STM32】IIC的基本原理(实例:普通IO口模拟IIC时序读取24C02)(转载)
版权声明:本文为博主原创文章,允许转载,但希望标注转载来源. https://blog.csdn.net/qq_38410730/article/details/80312357 IIC的基本介绍 ...
- IIC通信控制的AD5259------在调试过程中遇到的奇葩问题
首先说一下的遇到的问题: 1.AD5259按照SCL是100KHz的情况下,可以正常接收上位机的数据,但是一段时间后,就不能正确的按照时序来走了 原因在于AD5259在接收到上位机的数据后需要一定的响 ...
- 51单片机下实现软件模拟IIC通信
1.IIC协议简易概述 IIC全称Inter-Integrated Circuit (集成电路总线),是由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备.IIC属于半双 ...
- 嵌入式LINUX入门到实践(一)
MINI2440 IIC协议 IIC协议在工程中应用广泛,在我看来,此协议的优势就在于其硬件及其简单,结构清晰. 首先来解读一下S3C2440A这款芯片的IIC协议. 一.一个协议的解读从如上结构图中 ...
- OLED屏幕详细使用
IC扩展-OLED屏的点亮,模拟IIC功能实现C代码点亮OLED屏,只要是可以C编程且有两个GPIO口的单片机均可更改小部分代码使用.OLED屏为像素自发光,其尺寸多为128*64,表示横轴上有128 ...
- 基于STM32F429的ADS1115驱动程序
1.ADS1115中文资料:https://wenku.baidu.com/view/8bab101feef9aef8941ea76e58fafab069dc44e7.html?rec_flag=de ...
随机推荐
- Cogs 739. [网络流24题] 运输问题(费用流)
[网络流24题] 运输问题 ★★ 输入文件:tran.in 输出文件:tran.out 简单对比 时间限制:1 s 内存限制:128 MB «问题描述: «编程任务: 对于给定的m 个仓库和n 个零售 ...
- 【loj2985】【WC2019】I君的商店
题目 交互题: 有\(n\)个物品,每个物品的价格为0或者1; 给出为1的物品的个数奇偶性k,并保证至少有一个价格为1: 每次可以询问一个集合S的另一个集合T的价值和的大小,交互库会返回>=或者 ...
- javascript之数组的全部排列组合
javascript代码如下: var arr = [1, 2, 3]; // 临时变量,用于输出 var temp = []; function n(arr) { for (var i = 0; i ...
- rust-vmm 学习
V0.1.0 feature base knowledge: Architecture of the Kernel-based Virtual Machine (KVM) 用rust-vmm打造未来的 ...
- 前端微信小程序仿菜谱精灵
需求描述及交互分析 设计思路和相关知识点 底部标签导航设计 幻灯片轮播效果设计 菜谱专题列表显示设计 菜谱专题详情设计 菜谱分类设计 幻灯片轮播效果动态切换展示一些美食图片 若本号内容有做得不到位的地 ...
- struct tcphdr
包含在/usr/src/linux/include/linux/tcp.h struct tcphdr { __be16 source; __be16 dest; __be32 seq; __be32 ...
- Win7下安装VS2017、安装Qt5.10.1以及在VS2017添加qt插件
一.安装VS2017 1.下载VS2017 进入vs下载官网https://www.visualstudio.com/zh-hans/downloads/,选择所需要的vs版本,进行在线安装. 2.安 ...
- 刷题记录:Shrine
目录 刷题记录:Shrine 刷题记录:Shrine 题目复现链接:https://buuoj.cn/challenges 参考链接:Shrine 解此题总结一下flask的SSTI:CTF SSTI ...
- 2015-2016-2《Java程序设计》团队博客5
一.项目进展 本周将所有的项目代码全部进行了汇总总结,归纳在了一起,进行整体的测试.虽然在编写的时候很顺利,也就是片段代码问题不大,但是汇总到一起时还是产生了冲突与不对等的问题,所以我们只能仔细地从细 ...
- epoll 或者 kqueue 的原理是什么?
来自知乎:http://www.zhihu.com/question/20122137 epoll 或者 kqueue 的原理是什么? 为什么epoll和kqueue可以用基于事件的方式,单线程的实现 ...