ZYNQ学习——将读秒数据通过串口发送


之前对ZYNQ不是很了解,仅有一些Verilog和8051单片机的基础,近日学习有所得,故将完成过程记录下来。所用板子为搭载xc7z20clg484的Zedboard,Vivado版本为2016。
本次工程为PS与PL的协同开发,读秒数据产生部分将使用PL实现,使用Zedboard板载的100MHzPL时钟接入以及EMIO按键作为复位信号输入;发送数据为ARM核通过AXI4总线读取数据,并通过板载UART发送,通过串口调试助手观察。

读秒数据产生

使用Verilog编写读秒数据产生模块的.v文件(已使用Modelsim仿真通过),并将其封装为IP核,以供之后BlockDesign工程使用。

代码

读秒数据产生(二进制)

module second_data_generator(
  clk,
  rst, 
  data_out,
);

  input        clk;
  input        rst;
  
  output [7:0] data_out;

  reg [31:0]   div = 32'd0;
  reg [7:0]    cnt = 8'd0;
  
  parameter factor = 32'd99999999; //clk = 12MHz, factor = 24'd11999999
                             //clk = 100MHz.factor = 24'd99999999

  always @ ( posedge clk ) begin
    if (div == factor)
      div <= 32'd0;
    else
      div = div + 32'd1;
  end
  
  assign clk_1hz = ( div == factor ) ? 1'b1 : 1'b0;
  
  always @ ( posedge clk_1hz ) begin
    if ( rst )
      cnt <= 8'd0;
    else begin 
      if ( cnt == 8'd99 )
        cnt <= 8'd0;
      else
        cnt <=cnt + 8'd1;
    end  
  end

  assign data_out = cnt;
  
endmodule

二进制转BCD

module bin_to_bcd(
  clk,
  data_in,
  data_out
);

  input              clk;
  input  [7:0]       data_in;

  output reg [7:0]   data_out = 8'b0;

  reg    [3:0]       one  = 4'b0;
  reg    [3:0]       ten  = 4'b0;

  always @ ( posedge clk ) begin
    one       <= data_in % 8'd10;
    ten       <= data_in / 8'd10;
    data_out  <= { ten , one };
  end

endmodule

读秒数据产生部分的顶层模块

module sd_tx (
  clk,
  rst,
  txd
);

  input           clk;
  input           rst;

  output [7:0]    txd;

  wire   [7:0]    data;   

  second_data_generator sdg (
    .clk          ( clk  ),
    .rst          ( rst  ), 
    .data_out     ( data )
  );

  bin_to_bcd b2bcd (
    .clk          ( clk  ),
    .data_in      ( data ),
    .data_out     ( txd  )
  );

endmodule

封装为IP核

1、首先点击Tool栏下的Create and package new IP。
在这里插入图片描述
2、选中红框所示选项,点击Next。
在这里插入图片描述
3、选择放置之前编写的.v文件所在地址。
在这里插入图片描述
4、给IP核命名,之后finish
在这里插入图片描述
5、之后得到如下界面
在这里插入图片描述
检查各项内容以后无需修改,点击封装IP。
在这里插入图片描述

封装AXI总线的外部设备IP核

1、打开之前封装IP的界面,这次选择创建AXI4外部设备。
在这里插入图片描述
2、给IP核命名
在这里插入图片描述
4、选择Lite AXI,作为slave,数据宽度,寄存器数量(最低4个,本次只用得到1个寄存器,用不到的不用管)。
在这里插入图片描述
5、点击编辑IP。
在这里插入图片描述
6、在自动创建打开的IP工程中对其中文件进行自定义。
首先打开下层模块
在这里插入图片描述
添加需要的端口,用作与读秒数据产生IP核的接口
在这里插入图片描述
因需要通过寄存器slv_reg0与PS交换数据,即将读秒数据输入该寄存器中让PS读取,所以屏蔽PS对该寄存器的写入操作,这样slv_reg0的数据只能有我们自定义的逻辑能改变
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最后加入使用自定义的端口输入数据给slv_reg0赋值,至此对下层模块的操作结束。
在这里插入图片描述
接下来打开顶层文件
在这里插入图片描述
同样加入一个输入端口
在这里插入图片描述
加入对下层模块的例化端口,至此对IP核.v文件的修改完成。
在这里插入图片描述
7、打开封装IP核的界面,点击封装当前工程
在这里插入图片描述
Next之后点击Overwrite,完成IP核的创建。
在这里插入图片描述
8、之后打开工程所在文件夹的ip_repo文件夹,其中红框所示文件夹即为可使用的IP核。
在这里插入图片描述
9、在工程文件夹中新建my_ip文件夹,将IP核移动到其中,在vivado中打开工程设置
在这里插入图片描述
点击加号选择添加,之后即可在工程中搜索到。
在这里插入图片描述

创建并完成Blockdesign

1、点击创建Blockdesign文件
在这里插入图片描述
2、添加ZYNQ核
在这里插入图片描述
双击ZYNQ核以后,在MIO配置中打开UART1.
在这里插入图片描述
3、添加自定义的2个IP核,并将读秒数据的输出和输入端口连接
在这里插入图片描述
点击Run Block Automation和Run Connection Automation
在这里插入图片描述
在读秒数据产生IP核的clk核和rst端口上右键,点击 Make External
在这里插入图片描述
若觉得自动生成的布线太乱,可右键选择红框所示选项,将重新自动布线。
在这里插入图片描述
点击所示选项验证
在这里插入图片描述
4、在Source栏中右键bd文件,点击Generate Ouput Products
在这里插入图片描述
选择Global然后Generate
在这里插入图片描述
在刚才的右键菜单中点击Create HDL Wrapper,ok以后将生成该blockdesign设计的verilog代码。
在这里插入图片描述
5、点击综合
在这里插入图片描述
6、综合完成后点击实现(实现即是将综合后的网表加入物理约束和始终约束)
在这里插入图片描述
点击打开I/O port分配EMIO的引脚
在这里插入图片描述
其中clk分配的是PL的全局时钟GCLK,查原理图可知其引脚编号为Y9,电平标准为LVCMOS33;rst分配的是按键BTNU,引脚编号为T18,其电平标准为VADJ,需将板子的VADJ调节区1.8V处插上短路帽,因此最后选择LVCMOS18
在这里插入图片描述
保存为.xdc文件
在这里插入图片描述
注:vivado2016存在bug,直接保存后总是会报错,解决办法是再次保存为另一个文件,之后将第一个删除即可。
注:也可直接编写xdc文件,而不用通过图形界面进行分配。
7、点击生成比特流文件。
在这里插入图片描述
点叉结束
在这里插入图片描述
8、点击export-export hardware
在这里插入图片描述
勾选include bitstream,OK
在这里插入图片描述
点击export下方的launch SDK,即可将其导入到SDK中进行PS的设计。

PS的程序设计

1、新建application project
在这里插入图片描述
2、在建立的工程的src文件夹下新建一个C语言源文件
在这里插入图片描述
3、键入代码

#include <stdio.h>
#include "xparameters.h"
#include "xil_io.h"
#include "sleep.h"
#include "xil_types.h"
#include "xil_printf.h"

int main(){
	u8 txd=0;
	txd = Xil_In32(XPAR_TX_AXI_V1_0_BASEADDR);
	while(1){
		txd = Xil_In32(XPAR_TX_AXI_V1_0_BASEADDR);
		xil_printf("%x\r\n",txd);
		sleep(1);
	}
}

Xil_In32()函数为读寄存器中数据,地址可由xparameters.h文件中获得,其中地址为字节编址,而寄存器深度为32bit,即可利用地址自由获得各寄存器不同位置的数据。
在这里插入图片描述
xil_printf()可将数据通过UART发送(波特率为115200)。
sleep()函数可设置延迟,较为精确。
4、右键所建工程,选择debug as—debug configuration
双击该项
在这里插入图片描述
勾选
在这里插入图片描述
板子选择从JTAG启动并上电,点击apply、debug,点击yes。
点击该项将程序烧写到板子运行。
在这里插入图片描述
可在SDK中的SDK Terminal处添加端口观察读秒数据,也可使用其他串口调试助手进行观察。
在这里插入图片描述

现象

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值