URL: http://blog.csdn.net/xzyiverson/article/details/12889521
1:实验说明:
对于Zedboard的用户自定义的IP核有两种可行的方案:
一:通过EMIO交换数据(GPIO,SPI),这个其实就是将PL的IP核看作系统的外设,在数据交互性能和效率上都有很大的缺陷。(不常用)
二:利用向导来制作满足AXI协议的IP核,向导自动生成总线相关的代码,做好地址译码逻辑,读写控制逻辑,并在用户工作区生成一些寄存器。我们写的PL逻辑通过读写这些寄存器和PS交互。这也是常用的方法。
Zedboard也有一些自己做好了的IP core,实验八就是用的自带的IP core。
本实验就是采用第二种方法,制作一个简单的PWM发生器。在PL端开发了这个IP核以后,先在裸跑的程序里面调用这个IP core,测试我们的逻辑有没有实现,这个和之前做的实验没有什么区别(zedboard--zynq使用自带外设IP让ARM PS访问FPGA(八),只不过这里是我们自己写的IP core)
PWM发生器内部只有两个寄存器,一个是调节周期的周期寄存器,另一个是调节占空比的占空比寄存器,其中周期寄存器的最高位是状态位,控制PWM波最后是否产生。
2:具体步骤
启动PlanAhead,创建工程,Next,图1
输入工程名project_10,Next,图2
Next,RTL工程 图3
一路Next,不添加任何文件 图4
选择board 图5
完成工程 图6
PlanAhead进入工作视图,在Project Manager中单击那个有+的图标(addsources),出现下图,选择Embedded Sources 图7,图8
Next 选着Create Sub-Design。 图9
输入名称,这里为system 图10
点击finish 图11
进入了XPS,提示所建立的一个zynq工程,提示是否建立bsb Wizard,选择yes 图12
出现下图 图13
点击ok 出现 图14
选择next 这里不要大意,一定要把右侧的两个东西来remove掉,我当时就是卡在这里。,remove后出现这样的图 图15
Finish,点击finish就可以了,然后进入zynq的配置界面,Diligent公司做好了一个配置方案,可以到网上下载到配置文件。
如图16 17 18
Hardware- Createor Import Periphera 来到欢迎界面 图19
Next,创建新的模板(默认选择) 图20
Next 默认 图21
Next命名工程 图22
采用AXI4-Lite 图23
Next,这里只要 User logic master support 图24
Next,我们要两个寄存器,分别是占空比寄存器和周期寄存器,图25
Next,不做任何修改 图26
Next,不需要仿真平台 图27
Next, 全选图28
第一个选项表示生成的User Logic使用VerilogHDL
第二个选项表示同时生成一个ISE的工程,便于调试和测试Ipcore
第三个选项表示生成软件驱动库文件,方便在SDK里使用Ipcore
Next,点击finish就可以了 图29
我们自己配置的IP核就建立好了,接下来添加刚完成的IP核,在IP Catalog里面的USER选项中找到它 图30
双击PWM_IP,出现 图31
选择YES, 图32
点击两次ok,出现 图33
注意一下不要粘贴外面的(如word文档里面的),容易出错,输入法选择在英文输入法下。
右击pwm_ip_0,View MPD,添加PORT pwm_out=””,DIR=O,如图34(添加在60行),保存并关闭
右击pwm_ip_0,Brouse HDLsources,打开pwm_ip.vhd.添加代码
1添加(138行) 将pwm_out接口设置为模块的输出接口
pwm_out :out std_logic; 图35
2添加(253行)将pwm_out接口到user_logic设备
pwm_out :out std_logic; 图36
3添加(342)将设备的pwm_out接口和IP核的pwm_out接口连接
pwm_out =>pwm_out, 图37
保存,退出,右击pwm_ip_0,Brouse HDLsources,打开user_logic.v.添加代码
1添加(58行),声明pwm_out接口,添加pwm_out, 图38
2添加(88行)定义pwm_out为输出,而且位宽为1,添加
output pwm_out; 图39
3接下来就是用户实现段了,令slv_reg0为周期寄存器,slv_reg1为占空比寄存器。此外我们还需要一个计数器(pwm_counter),下一个周期的开始信号(Over Period)和预输出信号(pre_pwm_out)。
在110添加逻辑
wire ovprd;
reg [C_SLV_DWIDTH-1 :0] pwm_counter;
wire pre_pwm_out;
图40
pwm产生器的逻辑
在124行添加逻辑 图41
// USER logic implementation added here
always @(posedgeBus2IP_Clk)
begin
if(!Bus2IP_Resetn || ovprd ||~slv_reg1[31])
pwm_counter=32'h8000_0000;
else if(slv_reg1[31])
pwm_counter=pwm_counter+1'b1;
else pwm_counter=pwm_counter;
end
assignovprd=(pwm_counter[30:0]==slv_reg0[30:0])?1'b1:1'b0;
assignpre_pwm_out=(slv_reg1<pwm_counter)?1'b0:1'b1;
assignpwm_out=pre_pwm_out & slv_reg1[31];
保存,退出,在project菜单中选择RescanUser Repositories,从port中可以看到我们新添加的引脚pwm_out.选择External Ports把引脚引出去,如图42
打开Address标签页,单击右上角的GeneratedAddresses按钮,如图43
单击project –>Design Rule Check,没有报错,关闭xps,回到PlanAhead图44
在system.xmp文件上右击,选择CreateTop HDL 图45,46
单击Add source按钮,选择Add orCreate Constrains 单击Next 图47
单击 Create File…选项 图48
改文件名 图49,finish就可以了
单击左边的Run Synthesis ,这里就出错了,如图50,
在tcl console 按下ctrl +f 输入error,如图51一看是user_logic.v出错了,<slv_reg> is not d eclared这个时候启动xps,改正错误,可以看到图41,确实是错的,应该在128和134行为slv_reg1,而我漏掉了1,改正,保存,退出xps,重新Run Synthesis,这里也是寻找解决错误的方法。
过程结束后会弹出对话框,图52
选择Open Synthesized Design,会有一些警告,忽略,打开I/O Port标签,由于以前一直用Altera,这个标签找了一会儿(window->I/O Port),设置pwm_out的引脚,保存。图53
选择Select an existing file
看不到system.ucf,重启PlanAhead,这时候就可以看到system.ucf文件的内容如下 图54
单击左边的Generate Bitstream.单击yes,完成implementation,至此硬件工程就做完了。(这个过程又点长)
在PlanAhead中,单击File->Export->ExportHardware 图55
建立c工程 图56
选择Xilinx Tools->Repositories,单击new,找到工程路径,图57
在hello_bsp_0上右击,选择BoardSupport Package Setting ,找到drivers中得pwm_ip_0,修改Driver,图58,如果你没有出现估计就悲剧了。
然后我们将自设的IP核的Driver添加进来后就可以添加c代码了。图59
/**
* 通过用户自设IP,输出pwm波至LED T22,显示不同亮度。
* IP核说明:
* pwm_ip有两个32位寄存器,slv_reg0和slv_reg1。slv_reg0是周期寄存器,
* slv_reg1是占空比寄存器。pwm_out是ip核的输出端口。其逻辑定义在user_logic.v
* 文件中由用户自己完成。
*
* 软件自动生成pwm_ip.h文件,该文件提供了对pwm_ip进行读写的函数。实际上
* 就是xil_out和xil_in的宏定义。寄存器地址在xps中的ports和Address中可以
* 查看。将pwm_ip添加后,其寄存器地址XPAR_PWM_IP_0_BASEADDR将会定义在
* xparameter.h中。
*
* 下面两句先是设定了pwm周期为10000,又设置占空比为5000。其基地址位于xparameter.h
* 中,slv_reg0偏移地址为0,(因为它是第一个寄存器),slv_reg1偏移地址为4,(因为它是
* 第二个,且slv_reg0为32位,占4个字节)。10000和0x80000000+5000分别是要写入寄存器
* 的数据。其中0x80000000是因为user_logic.v中编写pwm逻辑时,计数器只用了前31位,MSB
* 被用于溢出判断,从而判断周期是否结束。
*/
修改bug在hello_bsp_0上面有一个红色的叉,是有一个宏没有设置,需要手动设置这个宏,找到pwm_ip_selftest,c这个文件,C:\zedboard\project_11\project_11.srcs\sources_1\edk\system/drivers/pwm_ip_v1_00_a/src/pwm_ip_selftest.c(我的目录在这里)
注释 #include "xio.h"
添加#define PWM_IP_USER_NUM_REG 2 图60
保存,等待工程编译结束。
出现图61的错误,解决办法。重新建立一个c工程。然后和上面的是一样的,至于原因就不知道了。
测试
选择Xilinx Tools->Program FPGA
在hello_world_0工程上右击,选择RunAs->Launch on Hardware,用示波器看波形结果是正确的,修改helloworld.c 中的占空比可以看到不同的波形。
易出错的地方:
第一个:在添加vhdl和verilog代码的时候以及找错误的方法。
第二个是出现类似于以下的错误: "Building target: hello_world_0.elf Invoking: ARM gcc linker arm-xilinx-eabi-gcc -Wl,-T -Wl,../src/lscript.ld -L../../standalone_bsp_0/ps7_cortexa9_0/lib -o"hello_world_0.elf" ./src/helloworld.o ./src/platform.o -l-Wl,--start-group,-lxil,-lgcc,-lc,--end-group ../lib/gcc/arm-xilinx-eabi/4.6.1/../../../../arm-xilinx-eabi/bin/ld.exe: cannot find -l-Wl,--start-group,-lxil,-lgcc,-lc,--end-group collect2: ld returned 1 exit status make: *** [hello_world_0.elf] Error 1"解决方法就是重新新建一个c工程,(冲PlanAhead重新导入一次),原因不祥。
以上都在上面有提到过。这次是用裸跑的程序来调用IPcore,下次实验是要为这个IPcore开发Linux系统上的设备驱动,使得运行在Linux上的应用程序可以使用这个驱动程序与PL端进行通信,从而控制PWM的输出。