Vivado HLS IP-XACT快速创建AXI总线IP(PWM)
0赞Vivado HLS IP-XACT快速创建AXI总线IP(PWM)
1、摘要
该笔记主要是利用HLS设计PWM算法IP核,借助IP-XACT快速创建基于AXI总线的IP核的心得。
2、目标
1)设计PWM IP
2)了解如何使用HLS创建AXI总线IP
之前设计了一个简单的MUX21函数来熟悉HLS的使用流程,生成的IP也不涉及AXI总线。AXI总线是Zynq PS、PL的桥梁,想要发挥好Zynq的优势,AXI总线IP是不可或缺的。因此,如何在Vivado和HLS下创建AXI总线IP也是非常重要的,通过使用HLS创建IP发现整个流程比XPS创建AXI总线IP简单方便很多,应当点赞!
3、算法设计:
关于资源添加、算法仿真、综合、C/RTL联合仿真,本文不多说了,参考前面博文即可。
pwm函数:
pwm.c
#include "pwm.h"
void pwm(int32 duty, int32 freq, int1 * out )
{
int32 i=0;
for(i=0;i<freq;i++)
{
if(i<duty)
*out = 1;
else
*out = 0;
}
}
// end of filepwm.h
#include <ap_cint.h>
pwm_tb.c
#include "pwm.h"
int main(void)
{
int i=10;
int1 tmp;
while(i--) // do simulation for a while
pwm(10,100,&tmp); // duty=10%
i=10; // do simulation for a while
while(i--)
pwm(50,100,&tmp); // duty=50%
i = 10; // do simulation for a while
while(i--)
pwm(70,100,&tmp); // duty=70%
printf("test passed!\n");
return 0;
}查看C/RTL联合仿真结果:
在Tcl Console输入的指令为:
cd E:/hls/pwm/pwm_ip/solution1/sim/verilog
current_fileset
open_wave_database pwm.wdb
open_wave_config pwm.wcfg
仿真结果如图1所示:

图1 C/RTL联合仿真结果
从图1中可以看出,当更改占空比duty时,输出信号占空比发生改变,设计是正确的。在使用IP时,需要注意ap_start这个输入信号是否有效。
4、借助IP-XACT封装IP:
打开pwm.c,点击Directive选项卡,(Vivado HLS主界面最右侧的子窗口)。该子窗口内容如图2所示。
图2 Directive选项卡
右键duty,在弹出的菜单中选择“Insert Directive”
图3 弹出菜单
单击“Insert Directive…”指令后,弹出对话框如图4所示。

图4 弹出对话框
更改Directive类型为RESOURCE,界面变化如图5所示。
图5 改变Directive类型
单击红色方框内的按钮,弹出图6所示的对话框,选择adapter类型为axi4lites。
图6 选择adapter
点击OK,返回Directive Editor,设置metadata属性为:-bus_budle_pwm_io。最终结果如图7所示。

图7 duty端口Directive属性
点击OK,完成配置。
参照上述步骤,完成freq端口的配置。
out端口不需要和PS通信,仅用作输出端口,因此选择directive类型为INTERFACE,其他默认即可,不需要更改。
完成3个端口的配置,Directive子窗体变化如图8所示。
图8 配置结果
重新综合solution,然后Export RTL,成功后,左侧多出目录如图9所示。
图9 导出结果
其中比较重要的是IP包和驱动程序。Vivado的IP Catalog导入的就是该IP包,驱动程序用于软件操作该IP。有兴趣的话,可以查看最终生成的各种代码。
5、IP核测试:
5.1、创建测试工程
不多说了,直接上结果,图10所示。
图10 bd结果
注意:在添加pwm ip前,需要设置一下IP Repositories路径(Tools > Project Settings > IP),否则找不到pwm ip,路径设置完毕如图11所示。
图11 add Repository
编写约束文件、生成Bitstream、转战SDK。
5.2、编写测试程序
这里pwm ip的驱动很简单,就是操作duty和freq对应的寄存器,HLS生成的driver里面有相关偏移地址的定义。driver还生成了ip初始化、寄存器读写等函数,这里我并没有用,还存在一些疑问,最终是自己编写了驱动,程序如下(没有优化):
#include <stdio.h>
#include "platform.h"
#include "xparameters.h"
#include "xpwm_hw.h"
#include "xil_io.h"
#include "sleep.h"
#define PWM_BASE_ADDR XPAR_PWM_0_S_AXI_PWM_IO_BASEADDR
int main()
{
u8 duty = 0;
u8 dir = 0;
init_platform();
Xil_Out32((PWM_BASE_ADDR) + (XPWM_PWM_IO_ADDR_FREQ_DATA), 100);
while(1)
{
Xil_Out32((PWM_BASE_ADDR) + (XPWM_PWM_IO_ADDR_DUTY_DATA), duty);
usleep(20000); // 20ms
if(dir)
duty -= 1;
else
duty += 1;
if(100==duty)
dir = 1;
if(0==duty)
dir = 0;
}
return 0;
}
// end of file
6、测试结果
版权声明:
本文由博主“cuter”发布。欢迎转载,但不得擅自更改博文内容,也不得用于任何盈利目的。转载时不得删除作者简介和版权声明。如有盗用而不说明出处引起的版权纠纷,由盗用者自负。
博客官方地址:
ChinaAET:http://blog.chinaaet.com/cuter521
