本帖最后由 FPGA课程 于 2024-9-28 13:43 编辑
软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1概述
本课就以AXI-Lite总线实现PWM(Pulse Width Modulation,脉冲宽度调制)自定义IP作为验证AXI-Lite总线应用的方案,实现2路PWM,通过点亮LED观察效果,带领大家快速进入实战状态。
本文实验目的:
1:设计一个简单的PWM发生器,并且通过AXI-LITE-SLAVE寄存器实现频率调整、占空比调整 2:通过VITIS-SDK实现对自定义IP中寄存器的读写访问 2系统框图
3创建IP
3.1利用模板创建AXI-Lite IP1:打开VIVADO软件,新建一个工程 2:单击ToolsàCreate and Package NEW IP,单击Next。 3:由于需要挂在到总线上,因此创建一个带AXI总线的用户IP,选择Create a new AXI4 peripheral,单击Next。
4:输入要创建的IP名字,此处命名为PWM_LITE_ML,选择保存路径,单击Next。
5:NameàS00_AXI; Interface Type(接口类型)àLite; Data Width(Bits)(数据位宽)à32位; Number of Registers(寄存器数量)à8 ;单击next。
设置总线形式为Lite总线,Lite总线是简化的AXI总线,消耗的资源少,当然性能比完整版的AXI总线差一点。因为频率要求不高,因此采用Lite总线就够了。设置寄存器数量为8,因为后面我们需要用到8个寄存器。 Step6:选择Edit IP,单击Finish完成
3.2修改IP源码IP创建后,需要对其进行修改,建立我们能够实际使用的IP。 1:打开PWM_LITE_ML_v1_0.v文件。
修改如下: 1、添加PWM_o端口 2、添加端口 2:打开PWM_LITE_ML_v1_0_S00_AXI.v文件。
修改如下: 1、添加PWM_o端口(注意录制的视频教程接口PWM_o名字改为了PWM) 2、添加PWM.v的端口 说明:slv_reg0-slv_reg7为PS部分写入PL的寄存器。通过这8个寄存器的值,我们可以控制PWM的占空比。 下面这段代码就是PS写PL部分的寄存器,一共有8个寄存器。 - always @( posedge S_AXI_ACLK )
- begin
- if ( S_AXI_ARESETN == 1'b0 )
- begin
- slv_reg0 <= 0;
- slv_reg1 <= 0;
- slv_reg2 <= 0;
- slv_reg3 <= 0;
- slv_reg4 <= 0;
- slv_reg5 <= 0;
- slv_reg6 <= 0;
- slv_reg7 <= 0;
- end
- else begin
- if (slv_reg_wren)
- begin
- case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
- 3'h0:
- for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
- if ( S_AXI_WSTRB[byte_index] == 1 ) begin
- // Respective byte enables are asserted as per write strobes
- // Slave register 0
- slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
- end
- 3'h1:
- for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
- if ( S_AXI_WSTRB[byte_index] == 1 ) begin
- // Respective byte enables are asserted as per write strobes
- // Slave register 1
- slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
- end
- 3'h2:
- for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
- if ( S_AXI_WSTRB[byte_index] == 1 ) begin
- // Respective byte enables are asserted as per write strobes
- // Slave register 2
- slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
- end
- 3'h3:
- for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
- if ( S_AXI_WSTRB[byte_index] == 1 ) begin
- // Respective byte enables are asserted as per write strobes
- // Slave register 3
- slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
- end
- 3'h4:
- for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
- if ( S_AXI_WSTRB[byte_index] == 1 ) begin
- // Respective byte enables are asserted as per write strobes
- // Slave register 4
- slv_reg4[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
- end
- 3'h5:
- for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
- if ( S_AXI_WSTRB[byte_index] == 1 ) begin
- // Respective byte enables are asserted as per write strobes
- // Slave register 5
- slv_reg5[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
- end
- 3'h6:
- for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
- if ( S_AXI_WSTRB[byte_index] == 1 ) begin
- // Respective byte enables are asserted as per write strobes
- // Slave register 6
- slv_reg6[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
- end
- 3'h7:
- for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
- if ( S_AXI_WSTRB[byte_index] == 1 ) begin
- // Respective byte enables are asserted as per write strobes
- // Slave register 7
- slv_reg7[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
- end
- default : begin
- slv_reg0 <= slv_reg0;
- slv_reg1 <= slv_reg1;
- slv_reg2 <= slv_reg2;
- slv_reg3 <= slv_reg3;
- slv_reg4 <= slv_reg4;
- slv_reg5 <= slv_reg5;
- slv_reg6 <= slv_reg6;
- slv_reg7 <= slv_reg7;
- end
- endcase
- end
- end
- end
复制代码
3:新建一个PWM.v 文件实现PWM输出。 - module PWM(
- input clk,
- input rst_n,
- input [31:0]fre_set,
- input [31:0]wav_set,
- output PWM_o
- );
- reg [31:0]fre_cnt;
- always @(posedge clk)begin
- if(rst_n==1'b0)begin
- fre_cnt <=32'd0;
- end
- else begin
- if(fre_cnt<fre_set) begin
- fre_cnt <= fre_cnt+1'b1;
- end
- else begin
- fre_cnt<=32'd0;
- end
- end
- end
- assign PWM_o = (wav_set>fre_cnt);
- endmodule
复制代码
4:进一步修改。去掉“_v1_0”。 1、PWM_LITE_ML_v1_0_S00_AXI.v中: module PWM_LITE_ML_v1_0_S00_AXI #修改为à module PWM_LITE_ML_S00_AXI # 2、PWM_LITE_ML_v1_0.v中: module PWM_LITE_ML_v1_0 # 修改为à module PWM_LITE_ML # PWM_LITE_ML_v1_0_S00_AXI # 修改为à PWM_LITE_ML_S00_AXI # PWM_LITE_ML_v1_0_S00_AXI_inst 修改为à PWM_LITE_ML_S00_AXI_inst 5:修改后,保存。出现如下界面,选择Automatically pick new top module。
6:重新封装。选择ToolsàCreat and Pakage New IP,单击Next。 7:选择Package your current project,单击Next。
8:选择Overwrite。 9:选择Package IPàRewiew and Package àRe-Package IP。完成创建自定义IP。 4硬件电路分析这里PWM输出的IO引出到LED上,调整PWM的占空比可以实现LED的亮度调节。
配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。 5搭建SOC系统工程详细的搭建过程这里不再重复,对于初学读者如果还不清楚如何创建SOC工程的,请学习“01Vitis Soc开发入门”这篇文章。 5.1SOC系统工程
1:中断设置本实验可以不设置中断
2:设置GP Master接口
3:设置复位输出
4:设置PL时钟
5:添加自定义IP设置自定义IP路径,并且添加IP
5.2设置AXI外设地址分配只要添加的AXI总线外设都要正确分配地址,这一步不能遗漏
5.3编译并导出平台文件以下步骤简写,有不清楚的看第一篇文章。 1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。 2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。 3:添加配套工程路径下uisrc/04_pin/fpga_pin.xdc约束文件 4:生成Bit文件。 5:导出到硬件: FileàExport HardwareàInclude bitstream 6:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
6搭建Vitis-sdk工程创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。 6.1创建SDK Platform工程
右击soc_base编译,编译的时间可能会有点长 6.2创建APP工程
7程序分析main函数中,根据之前章节的讲解我们可知,此处是分别向AXI总线的寄存器中写入数据。在23.2.2小节里,我们观察到,pwm_o[0]的频率设置和波形设置是通过slv_reg0和slv_reg1控制的。
从程序可以知道: PWM0为1:100的占空比,所以LED很暗 PWM1为98:100的占空比,所以LED很亮(实际由于驱动接口用了转换芯片,驱动能力没那么强) PWM2为10:100占空比,这里只能用Ila观察 PWM3为40:100占空比,这里只能用Ila观察
由上图可知,我们写入的数据和实际的输出是完全一致的,验证了我们的想法. 8方案演示
8.1硬件准备
本实验需要用到 JTAG 下载器、USB 转串口外设,另外需要把核心板上的 2P 模式开关设置到 JTAG 模式,即 ON ON(注意新版本的 MLK_H3_CZ08-7100-MZ7100FC),支持 JTAG 模式,对于老版本的核心板,JTAG 调试的时候 一定要拔掉 TF 卡,并且设置模式开关为 OFF OFF)
8.2实验结果
单击
编辑,启动触发。窗口显示采集到的信号波形。
通过控制不同的占空比也可以调整上的2个LED的显示亮度,这个用户自己可以试下。
|