FPGA的inout类型双向端口使用

基于 ZYNQ MINI开发板

一、文档实现功能介绍

本文档实现对如何使用inout双向端口进行学习,通过inout端口,可以实现数据接收和发送,通过一根信号线的分时复用。本教程不对IIC时序单独讲解,大家可以看源代码分析学习,本教程仅学习INOUT双向端口。工程新建方法请参考文档《开发软件安装 和介绍/VIVADO简介及软件下新建ZYNQ工程教程》。

二、ZYNQ 工程建立

起始页(或file->Project->New)创建新工程(CreateNew Project)
向导起始页面点击 Next- >
ProjectName(工程名)工程名:fpga_05_pl_iic_eeprom工程路径: (自己选择,不要有中文路径)勾选Create ProjectSubdirectory,点击Next- >
AddSource(添加设计源文件)点击 Next- >
AddExsixtingIP(添加已有的 IP)点击 Next- >
AddConstraints(添加已有约束文件)点击 Next- >
Default Part(默认配置,芯片选型)Family->Zynq-7000Package- >clg400Speed->7010选-1,7020选-27010版本选择目标器件:xc7z010clg400-17020版本选择目标器件:xc7z020clg400-2 点击 Next- >
NewProjectSummary(新建工程概况)确认工程信息,选型等,点击 Finish 完成

三、INOUT实现原理

当我们使用一个双向inout信号的时候,既要输入又要输出,怎么办呢?我们在verilog 学习的时候,有一种数值,叫做高阻态。一个比特的高阻态用1’bz表示。高阻态是一种可以   看做芯片内部断开的信号。我们知道,如果一个引脚为高阻态,那么,从外部驱动他,他的值  就取决于外部输入信号。所以,在input输入输出实现中,我们需要对外输出信号,则直接对   这个inout信号赋值,当需要切换为接收,则赋值为高阻态,然后把这个信号引脚的值读过来。 下面展示一个最简单的双向input实现:

reg inout_indicate_reg;//指示当前是输入还是输出
inout bi_derection_singnal;//双向输入输出信号
wire read_value;//从双向输入输出信号读的信号线
wire send_value;//需要发送,放到双向输入输出信号的信号线

//下面这行,当指示信号为1的时候,双向信号连接到发送数据信号线
assign bi_derection_singnal=(inout_indicate_reg==1’b1)?send_value:1’bz; 

//下面这行,当指示信号为0的时候,双向信号连接到接收数据信号线
assign read_value=(inout_indicate_reg==1’b0)?sbi_derection_singnal:1’bz;

以上代码仅供学习演示,没有实际运行,仅展示在什么情况下作为输入和输出的赋值  切换。上面可以看到,当作为输入,也就是指示信号判定为0,则赋值为高阻,这样外部信号 就不会受到影响,就可以输进来被内部接收信号使用,当判定信号为1, 则输入输出信号被内 部的发送信号驱动。

四、IIC的INOUT端口实例

fpga_05_pl_iic_eeprom的例程提供了一个完整的IIC收发的实例,其中IIC的SDA就是 一个INOUT双向端口。对于IIC通信协议我们不多讲解,大家可以查看24C02数据手册来对照 代码状态机学习。代码整个流程是:通过一个3秒周期计数,来触发状态机的读写。

关于定时触发的代码如下:

  1. //3秒周期中,第计数值到达1秒触发一次写操作
  2. assign write_start_flag_wire=(auto_read_write_cnt_reg==CNT_1SEC)?1'b1:1'b0; 
  3. //计数值到达3秒之后,触发一次读
  4. assign read_start_flag_wire=(auto_read_write_cnt_reg==CNT_3SEC)?1'b1:1'b0;
  5. always@(posedge clk or negedge rst_n)begin
  6. if(rst_n=='b0)begin
  7. auto_read_write_cnt_reg <='d0;
  8. end
  9. else begin
  10. if(auto_read_write_cnt_reg<CNT_3SEC)begin
  11. auto_read_write_cnt_reg <=auto_read_write_cnt_reg+'d1;
  12. end
  13. else begin
  14. auto_read_write_cnt_reg <='b0;
  15. end
  16. end
  17. end

代码第64行,表示当SDA使能为1, 也就是需要往外发送,则赋值SDAR寄存器,如果不为1, 则需要设置为高阻,以便外面的信号驱动他,然后被代码读进来外部的值判断。

assign SDA = SDAEN ? SDAR : 1'bz;

细心地朋友阅读了整个代码,可能会发现没有地方使用到了读取SDA值的代码。原则  上IIC的通信中,SDA外部在操作结束会有应答信号需要判断,但是我们FPGA可以不做判断, 也可以做,这里仅提供简单的驱动进行演示,仅限学习双向端口INOUT。

关于整个代码工程大家自行查阅对应例程即可。

五、在线调试验证

我们将例程生成bit文件下载到开发版进行在线调试。我们提供的例程请直接使用,因为我们设置了在线调试,大家不要从本教程拷贝代码自己新建工程,因为没有设置在线调试, 不支持抓波形。 关于在线调试的详细教程后面有专门的文档章节来学习,大家在这里请直接使 用例程。例程中,我们使用的管脚绑定如下,我们代码中在状态机转换过程还是用了LED指示当前状态。

FPGA的inout类型双向端口使用 - 第1张

生成bit文件之后我们打开硬件管理器,然后连接开发板 ,点击芯片xc7z020右键选择 program进行烧写,弹出的界面可以看到,烧写进去会有两个文件,上面的是bit文件,下面 的是我们抓取在线调试的文件:

FPGA的inout类型双向端口使用 - 第2张

点击

FPGA的inout类型双向端口使用 - 第3张

符号开始抓取,抓取波形如下:(不要修改任何设置,触发信号我们也设置 好了,更改了可能抓的不是这个波形)

FPGA的inout类型双向端口使用 - 第4张

从上面的抓取可以看到,INOUT信号实际在内部会被逻辑分成两个寄存器 ,一个SDA_IBUF,一个SDA_OBUF ,一个输入和一个输出。只不过共用一个管脚,输入输出到芯片, 都通过这两个BUF。高阻控制的就是输出寄存器 ,设置它输出为高阻态,不影响输入。从上面 看,实际上两个寄存器的值也是不一样的。

本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/9331.html

"愿我的文字能带给您一丝美好"

还没有人赞赏,支持一下

评论

A 为本文作者,G 为游客总数:0
加载中…

提交评论

游客,您好,欢迎参与讨论。

我的购物车

购物车为空

优惠券

没有优惠券