0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

FPGA学习系列:31. 基于FPGA的IIC的设计

FPGA学习交流 2018-08-20 13:40 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

设计背景:

IIC简单来说,就是一种串行通信协议,IIC 的通信协议和通信接口在很多工程中有广泛的应用,如数据采集领域的串行 AD,图像处理领域的摄像头配置,工业控制领域的 X 射线管配置等等。除此之外,由于 IIC协议占用的 IO 资源特别少,连接方便,所以工程中也常选用 IIC 接口做为不同芯片间的通信协议。

设计原理:

IIC电路原理图如下:

image.png



24LC64各引脚定义:

1、A0,A1,A2 为 24LC64 的片选信号,由于 IIC 总线可以挂载多个 IIC 接口器件,所以每个器件都应该有自己的“身份标识”,通过对 A0,A1,A2 输入不同的高低电平,就可以设置该 EEPROM 的片选信号。

2、WP 为读写使能信号,当 WP 悬空或者接地,EEPROM 可读可写,当 WP 接电源,EEPROM 只能读不能写。

3、SCL为 IIC 接口的时钟线。

4、SDA为 IIC 接口的数据线。


IIC 接口的读写时序:

IIC接口读写时序分为随机读写(单字节读写)和页面读写(多字节读写),先分析随机读写(Byte Write/Read)时序。


Byte Write 时序如下:

image.png



时序解读:如果我们要向 EEPROM 写入一个字节,那么必须经过以下步骤:

1. 发送启动信号

2. 发送控制字

3. 接收并检测 EEPROM 发来的应答信号 ACK

4. 发送高字节地址位

5. 接收并检测 EEPROM 发来的应答信号 ACK

6. 发送低字节地址位

7. 接收并检测 EEPROM 发来的应答信号 ACK

8. 发送 8bit 有效数据

9. 接收并检测 EEPROM 发来的应答信号 ACK

10.发送停止信号


Byte Read 时序如下:

image.png


时序解读:如果我们要从 EEPROM 读出一个字节,那么必须经过以下步骤:

1. 发送启动信号

2. 发送控制字 1010_A2A1A0_0

3. 接收并检测 EEPROM 发来的应答信号 ACK

4. 发送高字节地址位

5. 接收并检测 EEPROM 发来的应答信号 ACK

6. 发送低字节地址位

7. 接收并检测 EEPROM 发来的应答信号 ACK

8. 发送启动信号

9. 发送控制字 1010_A2A1A0_1

10. 接收并检测 EEPROM 发来的应答信号 ACK

11. 读取一个字节数据

12. 发送 NO ACK 信号

13. 发送停止信号


接下来则需要分析各步骤具体意义:

1.启动信号

image.png


SCL 保持高电平期间,如果 SDA 出现由高到低的跳变沿,代表启动信号。


2. 控制字

我们的控制字为 1010_0000,其中 1010 为 EEPROM 的型号标识,为一组固定的序列,紧接着 A2,A1,A0 就是我们的片选信号,最后一位为读写控制位,低电平代表写,高电平代表读,我们这里首先需要对 EEPROM 写入地址位,所以我们最后一位为 0。


3. 高/低位地址

由于 24LC64 有 64Kbit 的存储空间,所以我们需要 13 位的地址位宽才能寻址所有的存储空间,由于 IIC 协议规定只能以字节形式写入,所以必须将 13 位的地址扩展为 16 位的地址,分为高八位和低八位,多出来的前三位填充任意数据即可,对我们的寻址地址没有影响。


4. 停止信号

image.png


5. 应答信号 ACK

应答信号是由数据接收方发出的,当 SCL 为高电平期间,如果监测到 SDA为低电平,说明有应答信号。


6. 非应答信号 NO ACK

非应答信号也是由数据接收方发出的,当 SCL 为高电平期间,如果 SDA 为高电平,说明有非应答信号。

说明:由于 IIC 总线协议启动和停止信号都是在 SCL 高电平期间发生跳变,这就决定了我们其他数据的改变只能发生在 SCL 低电平期间,在 SCL 为高电平期间,数据必须保持稳定。即在 SCL 低电平改变数据,在 SCL 高电平采集数据。

相比于单字节读写,页面读写只是增加了几个状态,具体时序如下,这里和后面的设计代码不做详细论述。


Page Write 时序如下:

image.png


Page Read 时序如下:

image.png


设计架构图:

本设计用两个按键控制 EEPROM 读写,当写按键按下时,向 EEPROM 某一固定地址写入一个字节数据,当读按键按下时,将该地址数据读出,并显示到数码管LED 灯是一个标志信号,LED 亮说明数据写入完毕。设计架构如下:

image.png


设计代码:

iic_wr模块代码:负责进行IIC数据的读写

0moduleiic_wr (

1clk_sys,//系统时钟

2rst_n,//系统复位

3eeprom_scl,//eeprom 串行时钟信号

4eeprom_sda,//eeprom 串行数据信号

5key_wr,//外部写控制按键

6key_rd,//外部读控制按键

7result,//数据采集结果寄存器

8led //led指示灯

9);

10

11inputclk_sys;

12inputrst_n;

13inputkey_wr;

14inputkey_rd;

15

16outputregeeprom_scl;

17inouteeprom_sda;

18outputregled;

19regclk;

20reg[7:0]cnt;//分频计数器

21reg[7:0]state;//状态寄存器

22reg[3:0]counter;//数据移位计数器

23reglink_sda;//总线开关

24regwr;//写标志寄存器

25regrd;//读标志寄存器

26regsda_buf;//总线数据缓存器

27outputreg[7:0]result;

28reg[7:0]data;//待发送控制字、地址、数据寄存器

29assigneeprom_sda=(link_sda)?sda_buf:1'hz;

30

31//-----------------system clk----------------

32//系统时钟分频

33always@(posedgeclk_sys ornegedgerst_n)

34begin

35if(!rst_n)

36begin

37clk<=0;

38cnt<=0;

39end

40else

41begin

42if(cnt<250)

43cnt<=cnt+1'b1;

44else

45begin

46clk<=~clk;

47cnt<=0;

48end

49end

50end

51

52//-----------------eeprom scl-----------------

53//产生eeprom scl信号

54always@(negedgeclk ornegedgerst_n)

55begin

56if(!rst_n)

57begin

58eeprom_scl<=0;

59end

60else

61eeprom_scl<=~eeprom_scl;

62end

63

64//----------------- eeprom contral-----------

65always@(posedgeclk ornegedgerst_n)

66begin

67if(!rst_n)//所有寄存器复位

68begin

69state<=0;

70link_sda<=0;

71sda_buf<=0;

72counter<=0;

73wr<=0;

74led<=1;

75rd<=0;

76result<=0;

77data<=0;

78end

79else

80begin

81case(state)

82//--------------send start singial-------------

830:begin

84if(!key_wr)//检测外部写控制按键是否按下

85wr<=1;

86if(!key_rd)//检测外部读控制按键是否按下

87rd<=1;

88

89if(((rd==1)||(wr==1))&&(!eeprom_scl))

90begin

91link_sda<=1;

92sda_buf<=1;

93state<=1;

94end

95end

961:begin

97if(eeprom_scl)//高电平期间,使sda由高变低,启动串行传输

98begin

99sda_buf<=0;

100state<=2;

101data<=8'b10100000;//写控制字准备

102end

103end

104//--------------send countral word--------------

1052:begin

106if((counter<8)&&(!eeprom_scl))//scl低电平期间,完成并串转换,发出写控制字

107begin

108counter<=counter+1'b1;

109data<={data[6:0],data[7]};

110sda_buf<=data[7];

111end

112elseif((counter==8)&&(!eeprom_scl))

113begin

114counter<=0;

115state<=3;

116link_sda<=0;//FPGA释放总线控制权

117end

118end

119//--------------receive ack singial--------------

1203:begin

121if(eeprom_scl)//scl高电平期间,检测是否有应答信号

122begin

123if(!eeprom_sda)

124begin

125state<=4;//有应答则状态继续跳转

126data<=8'b00000000;//高字节地址准备

127end

128end

129end

130//--------------send high Byte address--------------

1314:begin

132link_sda<=1;//FPGA控制总线

133if((counter<8)&&(!eeprom_scl))//scl低电平期间,完成并串转换,发出高字节地址

134begin

135counter<=counter+1'b1;

136data<={data[6:0],data[7]};

137sda_buf<=data[7];

138end

139elseif((counter==8)&&(!eeprom_scl))

140begin

141counter<=0;

142state<=5;

143link_sda<=0;//FPGA释放总线控制权

144end

145end

146//--------------receive ack singial--------------

1475:begin

148if(eeprom_scl)//scl高电平期间,检测是否有应答信号

149begin

150if(!eeprom_sda)

151begin

152state<=6;//有应答则状态继续跳转

153data<=8'b00000011;//低字节地址准备

154end

155end

156end

157//--------------send low Byte address--------------

1586:begin

159link_sda<=1;//FPGA控制总线

160if((counter<8)&&(!eeprom_scl))//scl低电平期间,完成并串转换,发出低字节地址

161begin

162counter<=counter+1'b1;

163data<={data[6:0],data[7]};

164sda_buf<=data[7];

165end

166elseif((counter==8)&&(!eeprom_scl))

167begin

168counter<=0;

169state<=7;

170sda_buf<=1;

171link_sda<=0;//FPGA释放总线控制权

172end

173end

174//--------------receive ack singial--------------

1757:begin

176if(eeprom_scl)//scl高电平期间,检测是否有应答信号

177begin

178if(!eeprom_sda)

179begin

180if(wr==1)//如果是写的话,跳到状态8,遵循随机写时序

181state<=8;

182if(rd==1)//如果是读的话,跳到状态11,遵循随机读时序

183begin

184state<=11;

185sda_buf<=1;//准备再次发启动信号

186end

187data<=8'b00001111;//准备想要写入的数据

188end

189end

190end

191//--------------send active data-------------

1928:begin

193link_sda<=1;//FPGA控制总线

194if((counter<8)&&(!eeprom_scl))//scl低电平期间,完成并串转换,发出有效数据

195begin

196counter<=counter+1'b1;

197data<={data[6:0],data[7]};

198sda_buf<=data[7];

199end

200elseif((counter==8)&&(!eeprom_scl))

201begin

202counter<=0;

203state<=9;

204link_sda<=0;//FPGA释放总线控制权

205end

206end

207//--------------receive ack singial--------------

2089:begin

209if(eeprom_scl)//scl高电平期间,检测是否有应答信号

210begin

211if(!eeprom_sda)//有应答则状态继续跳转

212state<=10;

213end

214end

215//--------------send stop singial-------------

21610:begin

217link_sda<=1;//FPGA控制总线

218sda_buf<=0;//拉低sda,准备发出停止信号

219if(eeprom_scl)//scl高电平期间,拉高sda,终止串行传输

220begin

221led<=0;//点亮led,说明写操作完毕

222sda_buf<=1;

223if(key_wr &&key_rd)//在按键放开以后才跳转回空闲状态,避免不断循环写入

224state<=0;//状态跳回

225wr<=0;//清除写控制标志

226end

227end

228//------------send start singial-----------

22911:begin

230link_sda<=1;//FPGA控制总线

231if(eeprom_scl)//scl高电平期间拉低sda,发送启动信号

232begin

233sda_buf<=0;

234state<=12;

235data<=8'b10100001;//读控制字准备

236end

237end

238//------------send countral word------------

23912:begin

240if((counter<8)&&(!eeprom_scl))//scl低电平期间,完成并串转换,发出读控制字

241begin

242counter<=counter+1'b1;

243data<={data[6:0],data[7]};

244sda_buf<=data[7];

245end

246elseif((counter==8)&&(!eeprom_scl))

247begin

248counter<=0;

249state<=13;

250link_sda<=0;//FPGA释放总线控制权

251end

252end

253//--------------receive ack singial--------------

25413:begin

255if(eeprom_scl)//scl高电平期间,检测是否有应答信号

256begin

257if(!eeprom_sda)//有应答则状态继续跳转

258state<=14;

259end

260end

261//--------------receive input active data--------------

26214:begin

263if((counter<8)&&(eeprom_scl))//scl高电平期间,完成串并转换,存储接收数据

264begin

265counter<=counter+1'b1;

266result[7-counter]<=eeprom_sda;

267end

268elseif(counter==8)

269begin

270counter<=0;

271state<=15;

272sda_buf<=1;

273link_sda<=1;//接收完毕以后FPGA继续控制总线

274end

275end

276//--------------send NO ACK singial--------------

27715:begin

278if(eeprom_scl)//scl高电平期间,将sda总线拉高,发出非应答信号

279begin

280sda_buf<=1;

281state<=16;

282end

283end

284//--------------send stop singial-------------

28516:begin

286if(!eeprom_scl)//scl低电平期间,将sda总线拉低,准备发送停止信号

287sda_buf<=0;

288if(eeprom_scl)//scl高电平期间,将sda总线拉高,发出停止信号

289begin

290sda_buf<=1;//拉高sda

291state<=0;//状态回转

292rd<=0;//清除读标志信号

293end

294end

295default:state<=0;

296endcase

297end

298end

299endmodule


seg7_lut模块代码,负责数码管显示

0moduleseg7_lut (

1oseg,//数码管段选

2idig,//驱动数据

3clk_sys,//系统时钟

4sel,//数码管位选

5rst_n //系统复位

6);

7//--------输入信号--------

8input[7:0]idig;

9inputclk_sys;

10inputrst_n;

11//--------输出信号--------

12outputreg[7:0]oseg;

13outputreg[2:0]sel;

14//--------中间变量--------

15reg[3:0]cnt;

16//-----------------系统时钟分频-----------------

17always@(posedgeclk_sys ornegedgerst_n)

18begin

19if(!rst_n)

20begin

21sel<=3'd0;//数码管段选定位

22end

23end

24

25//--------数码管显示译码--------

26always@(*)

27case(idig)

288'h0:oseg<=8'hC0;

298'h1:oseg<=8'hF9;

308'h2:oseg<=8'hA4;

318'h3:oseg<=8'hB0;

328'h4:oseg<=8'h99;

338'h5:oseg<=8'h92;

348'h6:oseg<=8'h82;

358'h7:oseg<=8'hF8;

368'h8:oseg<=8'h80;

378'h9:oseg<=8'h90;

388'hA:oseg<=8'h88;

398'hB:oseg<=8'h83;

408'hC:oseg<=8'hC6;

418'hD:oseg<=8'hA1;

428'hE:oseg<=8'h86;

438'hF:oseg<=8'h8E;

44endcase

45

46endmodule


IIC顶层模块代码

0moduleIIC (

1clk_sys,

2rst_n,

3eeprom_scl,

4eeprom_sda,

5key_wr,

6key_rd,

7oseg,

8sel,

9led

10);

11//--------输入端口--------

12inputclk_sys;

13inputrst_n;

14inputkey_wr;

15inputkey_rd;

16//--------输出端口--------

17outputeeprom_scl;

18output[7:0]oseg;

19output[2:0]sel;

20outputled;

21//--------双向总线--------

22inouteeprom_sda;

23//--------内部连线--------

24wire[7:0]result;

25//--------实例化eeprom控制模块--------

26iic_wr iic_wr (

27.clk_sys(clk_sys),

28.rst_n(rst_n),

29.eeprom_scl(eeprom_scl),

30.eeprom_sda(eeprom_sda),

31.key_wr(key_wr),

32.key_rd(key_rd),

33.result(result),

34.led(led)

35);

36//--------实例化数码管显示驱动模块--------

37seg7_lut seg7_lut (

38.oseg(oseg),

39.idig(result),

40.clk_sys(clk_sys),

41.sel(sel),

42 .rst_n(rst_n)

43);

44

45endmodule


tb顶层测试模块代码

0`timescale1ns/1ns

1

2moduletb;

3

4regclk_sys;

5regrst_n;

6regkey_wr;

7regkey_rd;

8

9wireeeprom_scl;

10

11wireeeprom_sda;

12wire[7:0]oseg;

13wire[2:0]sel;

14wireled;

15

16initial

17begin

18clk_sys=0;

19key_rd=1;

20rst_n=0;

21#1000rst_n=1;

22#500key_wr=0;

23#3000key_wr=1;

24#400000key_rd=0;

25#300key_rd=1;

26end

27

28always#10clk_sys=~clk_sys;

29

30IIC IIC(

31.clk_sys(clk_sys),

32.rst_n(rst_n),

33.eeprom_scl(eeprom_scl),

34.eeprom_sda(eeprom_sda),

35.key_wr(key_wr),

36.key_rd(key_rd),

37.oseg(oseg),

38.sel(sel),

39.led(led)

40);

41

42endmodule


仿真:

随机读写,仿真写时序:



随机读写,仿真读时序:


在仿真时,需要将检测应答的状态跳过,直接向下一状态跳转,观察读写时序,当读写按键按下时,都会产生对应的动作。




声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1655

    文章

    22287

    浏览量

    630308
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Altera Agilex 5 D系列FPGA和SoC家族全面升级

    Agilex 5 D 系列 FPGA 和 SoC 家族全面升级,为中端 FPGA 应用能力带来巨大飞跃——逻辑单元、内存、DSP/AI 算力提升高达 2.5 倍,外存带宽提升高达 2 倍,轻松驾驭功耗和空间受限环境中的高计算性能
    的头像 发表于 11-25 14:42 1062次阅读

    基于hbirdv2-sdk的iic 0.96寸lcd调试

    一.前言 简介: 基于hbird-sdk的硬件IIC控制 0.96寸lcd. 二.工程结构 硬件: mcu200t fpga开发板 软件结构: 主要由Makefile main.c
    发表于 10-30 06:20

    Altera Agilex™ 3 FPGA和SoC FPGA

    3器件将Altera Hyperlex FPGA架构集成到这些较小器件中,与以前的成本优化型系列Cyclone V以及更高速收发器相比,性能提高了1.9倍,并为LPDDR4增加了内存支持。小尺寸对于
    的头像 发表于 08-06 11:41 3671次阅读
    Altera Agilex™ 3 <b class='flag-5'>FPGA</b>和SoC <b class='flag-5'>FPGA</b>

    FPGA在机器学习中的具体应用

    随着机器学习和人工智能技术的迅猛发展,传统的中央处理单元(CPU)和图形处理单元(GPU)已经无法满足高效处理大规模数据和复杂模型的需求。FPGA(现场可编程门阵列)作为一种灵活且高效的硬件加速平台
    的头像 发表于 07-16 15:34 2634次阅读

    智多晶FPGA设计工具HqFpga接入DeepSeek大模型

    在 AI 赋能工程设计的时代浪潮中,智多晶率先迈出关键一步——智多晶正式宣布旗下 FPGA 设计工具 HqFpga 接入 DeepSeek 大模型,并推出 FPGA 设计专属 AI 助手——晶小助!这是
    的头像 发表于 06-06 17:06 1131次阅读

    ZYNQ FPGA的PS端IIC设备接口使用

    zynq系列中的FPGA,都会自带两个iic设备,我们直接调用其接口函数即可运用。使用xilinx官方提供的库函数,开发起来方便快捷。
    的头像 发表于 04-17 11:26 1752次阅读
    ZYNQ <b class='flag-5'>FPGA</b>的PS端<b class='flag-5'>IIC</b>设备接口使用

    Altera Agilex 7 M系列FPGA正式量产出货

    近日,全球 FPGA 创新技术领导者 Altera 宣布, Agilex 7 M 系列 FPGA 正式量产出货,这是现阶段业界领先的集成高带宽存储器,并支持 DDR5 和 LPDDR5 存储器技术
    的头像 发表于 04-10 11:00 1188次阅读

    进群免费领FPGA学习资料!数字信号处理、傅里叶变换与FPGA开发等

    进群免费领FPGA学习资料啦!小编整理了数字信号处理、傅里叶变换与FPGA开发等FPGA必看资料,需要的小伙伴可以加小助手(微信:elecfans123)或进 QQ 群:9135011
    发表于 04-07 16:41

    在APP FPGA 中通过IIC接口对DLPC910寄存器进行配置遇到的两个问题求解

    在APP FPGA 中通过IIC接口对DLPC910寄存器进行配置,有两个问题想要请教: 1、DLPC910被封装成了FPGA,通过IIC改变它的寄存器的值,掉电后,该值会被保留还是
    发表于 02-25 06:47

    使用FPGA控制DLPC3438,采用IIC协议进行读写操作,读取的数据存在错误,无法正确从寄存器中读取数据怎么解决?

    我使用FPGA控制DLPC3438,采用IIC协议进行读写操作,主要存在如下问题: (1)当写入8个字节到0x2E地址时,通过Xilinx工具ChipScope抓取IIC信号,发现DLPC3438
    发表于 02-24 07:47

    【国产FPGA入学必备】刀剑在鞘,兵器先藏 | 盘古676系列国产FPGA开发板

    刀剑在鞘,兵器先藏 ,AI时代如何立足,首先有过硬的本领和趁手的兵器,给FPGA工程师安利一款趁手的国产FPGA开发板盘古676系列...... 盘古676系列开发板共有2款板卡:盘古
    发表于 02-20 15:38

    【国产FPGA入学必备】国产FPGA权威设计指南+配套FPGA图像视频教程

    》。 本书系统地介绍紫光同创FPGA的开发与应用,详细阐述FPGA开发的各个方面,从基础原理到实际应用,从设计流程到开发工具的使用,力求为读者提供一套完整的学习和参考体系。通过阅读本书,读者不仅可以掌握紫光
    发表于 02-20 15:08

    【国产FPGA必备教程】——紫光同创FPGA图像视频教程,适用于小眼睛FPGA盘古全系列开发板

    案例、时序约束及收敛方法等,教程内容丰富,从入门到应用提高,覆盖紫光同创FPGA开发全流程,教程适用于小眼睛科技盘古系列、泰坦系列全开发套件。目前,小眼睛科技基于FPGA赛事配套紫光同
    发表于 02-19 15:44

    基于FPGA的电子琴设计

    在之前也出了几篇源码系列,基本上都是一些小设计,源码系列主要就会想通过实操训练让各位学习者,尤其是初学者去更好的理解学习FPGA,或者给要的
    的头像 发表于 01-20 14:07 1248次阅读
    基于<b class='flag-5'>FPGA</b>的电子琴设计

    FPGA在AI方面有哪些应用

    提供了强有力的支持。 一、FPGA 在深度学习中的应用 深度学习是 AI 的重要分支,涉及海量的数据运算。FPGA 能够针对深度学习算法中的
    的头像 发表于 01-06 17:37 2102次阅读