常用IIC协议使用地方
熟悉一个协议一定要知道这个协议应该用到什么地方,IIC协议作为飞利浦公司定义的一个慢速传输协议,常用于:
1、芯片寄存器的配置;
2、eeprom的读写;
本次实验我们将使用eeprom来讲解IIC协议以及FPGA代码的编写,本次实验所用到的软硬件环境如下:
硬件:黑金A7102开发板
软件:vivado 19.1
黑金A7102开发板上eeprom的型号位:24LC04,是单字节地址的eeprom。再比如小梅哥AC620开发板上的eeprom为双字节地址的器件。为了让同学们了解两者,本次实验我们以24LC64为例进行实验,然后更改为单字节的24LC04并在板上验证。
常见IIC协议的注意点
1、总线空闲状态:SDA为高电平,SCL为高电平
2、起始位:SCL为高电平时,SDA产生一个下降沿
3、结束位:SCL为高电平时,SDA产生一个上升沿
IIC总线的三种模式如下:
标准模式:100Kbit/s
快速模式:400Kbit/s
高速模式:3.4Mbit/s
24LC64芯片读写命令的时序图
24LC64芯片的单字节写命令时序图如下:

连续字节写命令如下:

24LC64芯片的单字节读命令时序图如下:

连续字节读命令如下:

同理这里也给出24LC04命令的读写时序图,单字节写命令时序图如下:

连续字节写命令如下:

24LC04芯片的单字节读命令时序图如下:

连续字节读命令如下:

eeprom控制器的系统框图
该eeprom控制器的系统框图主要由以下四部分构成:
顶层模块:

详细大家从引脚的定义便可以明白该信号的作用,如果实在明白不了可以进群拿到现成的工程代码,进行仿真观察。
sclk:主时钟信号——50Mhz
rst_n:复位信号低电平有效
wr_reg:写请求信号,单时钟脉冲
rd_req:读请求信号,单时钟脉冲
wr_data:写数据
addr:读写eeprom地址
rd_valid:读数据有效信号,单时钟脉冲
rd_data:读出来的eeprom数据
busy:控制器内部忙信号,1为忙
iic_sck:IIC协议时钟线
iic_sda:IIC协议的数据线
该模块作为顶层模块,主要包括以下三种模块:
1、eeprom_read模块:eeprom的读模块
2、eeprom_write模块:eeprom的写模块
3、ctrl模块:eeprom的读写判决模块
eeprom_read模块的系统框图如下:

信号的含义如下:
rd_flag:读触发信号,高电平有效
rd_done:读操作结束信号
eeprom_write模块的系统框图如下:

信号的含义如下:
wr_flag:写触发信号,高电平有效
wr_done:写操作完成信号
ctrl模块的系统框图如下:

信号的含义如下::
wr_data_r:数据寄存信号
addr_r:地址寄存信号
时序图设计
eeprom_write模块的时序图设计如下:

该时序图知识近似设计,结合该时序图于代码可以直接理解该模块的编写。
eeprom_read模块的时序图设计如下:

ctrl模块的状态机为:

代码设计
这里将给出整个控制器的逻辑代码,如下:
top模块的代码如下:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : top.v
// Create Time : 2020-01-14 11:23:02
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module top(
input sclk ,
input rst_n ,
input wr_req ,
input rd_req ,
input [15:0] addr ,
output wire [ 7:0] rd_data ,
output wire rd_valid ,
input [ 7:0] wr_data ,
output wire busy ,
output wire iic_sck ,
inout iic_sda
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
wire rd_done ;
wire wr_done ;
wire wr_flag ;
wire rd_flag ;
wire [15:0] addr_r ;
wire [ 7:0] wr_data_r ;
wire iic_sck_wr ;
wire iic_sck_rd ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
ctrl ctrl_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.wr_req (wr_req ),
.rd_req (rd_req ),
.rd_done (rd_done ),
.wr_done (wr_done ),
.addr (addr ),
.iic_sck_wr (iic_sck_wr ),
.iic_sck_rd (iic_sck_rd ),
.wr_data (wr_data ),
.wr_flag (wr_flag ),
.rd_flag (rd_flag ),
.addr_r (addr_r ),
.wr_data_r (wr_data_r ),
.busy (busy ),
.iic_sck (iic_sck )
);
eeprom_write eeprom_write_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.wr_flag (wr_flag ),
.wr_data (wr_data_r ),
.addr (addr_r ),
.wr_done (wr_done ),
.iic_sck (iic_sck_wr ),
.iic_sda (iic_sda )
);
eeprom_read eeprom_read_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.rd_flag (rd_flag ),
.rd_data (rd_data ),
.rd_valid (rd_valid ),
.addr (addr_r ),
.rd_done (rd_done ),
.iic_sck (iic_sck_rd ),
.iic_sda (iic_sda )
);
endmodule
eeprom_write模块的代码如下:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : eeprom_write.v
// Create Time : 2020-01-14 09:51:46
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module eeprom_write(
input sclk ,
input rst_n ,
input wr_flag ,
input [ 7:0] wr_data ,
input [15:0] addr ,
output reg wr_done ,
output reg iic_sck ,
inout iic_sda
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter DIV_CNT = 249 ;
parameter DEVICE_ADDR = 8'hA0 ;
reg wr_busy ;
reg [ 7:0] cnt_250 ;
reg [ 5:0] cnt_bit ;
reg sda_oe ;
reg iic_sda_r ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
assign iic_sda = (sda_oe && !iic_sda_r) ? 1'b0:1'bz;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
wr_busy <= 1'b0;
else if(wr_flag == 1'b1)
wr_busy <= 1'b1;
else if(wr_done == 1'b1)
wr_busy <= 1'b0;
always @(posedge sclk)
if(rst_n == 1'b0)
cnt_250 <= 8'd0;
else if(cnt_250 == DIV_CNT || wr_done == 1'b1)
cnt_250 <= 8'd0;
else if(wr_busy == 1'b1)
cnt_250 <= cnt_250 + 1'b1;
else
cnt_250 <= cnt_250;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
cnt_bit <= 5'd0;
else if(wr_done == 1'b1)
cnt_bit <= 5'd0;
else if(cnt_250 == DIV_CNT)
cnt_bit <= cnt_bit + 1'b1;
else
cnt_bit <= cnt_bit;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
iic_sck <= 1'b1;
else if(cnt_bit != 'd37 && cnt_250 == DIV_CNT/2)
iic_sck <= 1'b0;
else if(cnt_250 == 'd0)
iic_sck <= 1'b1;
else
iic_sck <= iic_sck;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
sda_oe <= 1'b1;
else if((cnt_bit == 8 || cnt_bit == 17 || cnt_bit == 26 || cnt_bit == 35) && cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
sda_oe <= 1'b0;
else if((cnt_bit == 9 || cnt_bit == 18 || cnt_bit == 27|| cnt_bit == 36) && cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
sda_oe <= 1'b1;
else
sda_oe <= sda_oe;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
iic_sda_r <= 1'b1;
else case(cnt_bit)
0 : if(cnt_250 == (DIV_CNT/4))
iic_sda_r <= 1'b0;
else if(cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
iic_sda_r <= DEVICE_ADDR[7-cnt_bit];
else
iic_sda_r <= iic_sda_r;
1,2,3,4,5,6 : if(cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
iic_sda_r <= DEVICE_ADDR[7-cnt_bit];
else
iic_sda_r <= iic_sda_r;
7 : if(cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
iic_sda_r <= 1'b0;
else
iic_sda_r <= iic_sda_r;
8 : if(cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
iic_sda_r <= 1'b0;
else
iic_sda_r <= iic_sda_r;
12,13,14,15,16 : if(cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
iic_sda_r <= addr[24-cnt_bit];
else
iic_sda_r <= iic_sda_r;
17 : if(cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
iic_sda_r <= 1'b0;
else
iic_sda_r <= iic_sda_r;
18,19,20,21,22,23,24,25 :
if(cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
iic_sda_r <= addr[25-cnt_bit];
else
iic_sda_r <= iic_sda_r;
26 : if(cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
iic_sda_r <= 1'b0;
else
iic_sda_r <= iic_sda_r;
27,28,29,30,31,32,33,34 :
if(cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
iic_sda_r <= wr_data[34-cnt_bit];
else
iic_sda_r <= iic_sda_r;
35 : if(cnt_250 == (DIV_CNT/2 + DIV_CNT/4))
iic_sda_r <= 1'b0;
else
iic_sda_r <= iic_sda_r;
36 : iic_sda_r <= iic_sda_r;
37 : if(cnt_250 == (DIV_CNT/4))
iic_sda_r <= 1'b1;
default : iic_sda_r <= 1'b1;
endcase
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
wr_done <= 1'b0;
else if(cnt_bit == 'd37 && cnt_250 == (DIV_CNT/2))
wr_done <= 1'b1;
else
wr_

最低0.47元/天 解锁文章
1573

被折叠的 条评论
为什么被折叠?



