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秒周期计数,来触发状态机的读写。
关于定时触发的代码如下:
//3秒周期中,第计数值到达1秒触发一次写操作
assign write_start_flag_wire=(auto_read_write_cnt_reg==CNT_1SEC)?1'b1:1'b0;
//计数值到达3秒之后,触发一次读
assign read_start_flag_wire=(auto_read_write_cnt_reg==CNT_3SEC)?1'b1:1'b0;
always@(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
auto_read_write_cnt_reg <='d0;
end
else begin
if(auto_read_write_cnt_reg<CNT_3SEC)begin
auto_read_write_cnt_reg <=auto_read_write_cnt_reg+'d1;
end
else begin
auto_read_write_cnt_reg <='b0;
end
end
end
代码第64行,表示当SDA使能为1, 也就是需要往外发送,则赋值SDAR寄存器,如果不为1, 则需要设置为高阻,以便外面的信号驱动他,然后被代码读进来外部的值判断。
assign SDA = SDAEN ? SDAR : 1'bz;
细心地朋友阅读了整个代码,可能会发现没有地方使用到了读取SDA值的代码。原则 上IIC的通信中,SDA外部在操作结束会有应答信号需要判断,但是我们FPGA可以不做判断, 也可以做,这里仅提供简单的驱动进行演示,仅限学习双向端口INOUT。
关于整个代码工程大家自行查阅对应例程即可。
五、在线调试验证
我们将例程生成bit文件下载到开发版进行在线调试。我们提供的例程请直接使用,因为我们设置了在线调试,大家不要从本教程拷贝代码自己新建工程,因为没有设置在线调试, 不支持抓波形。 关于在线调试的详细教程后面有专门的文档章节来学习,大家在这里请直接使 用例程。例程中,我们使用的管脚绑定如下,我们代码中在状态机转换过程还是用了LED指示当前状态。

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

点击

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

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

FPGA的inout类型双向端口使用
基于 ZYNQMINI开发板一、文档实现功能介绍本文档实现对如何使用in…
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
FPGA在线学习平台
评论
A 为本文作者,G 为游客总数:0