本原創教程由芯驛電子科技(上海)有限公司(ALINX)創做,版權歸本公司全部,如需轉載,需受權並註明出處。ide
AXU2CGA/AXU2CGB/AXU3EG/AXU4EV-E/AXU4EV-P/AXU5EV-E/AXU5EV-P /AXU9EG/AXU15EG測試
實驗Vivado工程目錄爲「custom_pwm_ip /vivado」。this
實驗vitis工程目錄爲「custom_pwm_ip /vitis」。spa
Xilinx官方爲你們提供了不少IP核,在Vivado的IP Catalog中能夠查看這些IP核,用戶在構建本身的系統中,不可能只使用Xilinx官方的免費IP核,不少時候須要建立屬於本身的用戶IP核,建立本身的IP核有不少好處,例如系統設計定製化;設計複用,能夠在在IP核中加入license, 有償提供給別人使用;簡化系統設計和縮短設計時間。用ZYNQ系統設計IP核,最經常使用的就是使用AXI總線將PS同PL部分的IP核鏈接起來。本實驗將爲你們介紹如何在Vivado中構建AXI總線類型的IP核,此IP核用來產生一個PWM,用這個控制開發板上的LED,作一個呼吸燈的效果。debug
如下爲FPGA工程師負責內容。設計
咱們常常使用PWM來控制LED,蜂鳴器等,經過調節脈衝的佔空比來調節LED的亮度。3d
在其餘開發板中咱們使用過的一個pwm模塊以下:調試
////////////////////////////////////////////////////////////////////////////////// // // ////////////////////////////////////////////////////////////////////////////////// // // // Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd // // All rights reserved // // // // This source file may be used and distributed without restriction provided // // that this copyright statement is not removed from the file and that any // // derivative work contains the original copyright notice and the associated // // disclaimer. // // // ////////////////////////////////////////////////////////////////////////////////// //================================================================================ // Description: pwm model // pwm out period = frequency(pwm_out) * (2 ** N) / frequency(clk); // //================================================================================ // Revision History: // Date By Revision Change Description //-------------------------------------------------------------------------------- // 2017/5/3 meisq 1.0 Original //********************************************************************************/ `timescale1ns/1ps module ax_pwm #( parameter N =32//pwm bit width ) ( input clk, input rst, input[N -1:0]period, input[N -1:0]duty, output pwm_out ); reg[N -1:0] period_r; reg[N -1:0] duty_r; reg[N -1:0] period_cnt; reg pwm_r; assign pwm_out = pwm_r; always@(posedge clk orposedge rst) begin if(rst==1) begin period_r <={ N {1'b0}}; duty_r <={ N {1'b0}}; end else begin period_r <= period; duty_r <= duty; end end always@(posedge clk orposedge rst) begin if(rst==1) period_cnt <={ N {1'b0}}; else period_cnt <= period_cnt + period_r; end always@(posedge clk orposedge rst) begin if(rst==1) begin pwm_r <=1'b0; end else begin if(period_cnt >= duty_r) pwm_r <=1'b1; else pwm_r <=1'b0; end end endmodule
能夠看到這個PWM模塊須要2個參數「period」、「duty」來控制頻率和佔空比,」period」爲步進值,也就是計數器每一個週期要加的值。Duty爲佔空比的值。咱們須要設計一些寄存器來控制這些參數,這裏須要使用AXI總線,PS經過AXI總線來讀寫寄存器。rest
用」ps_hello」工程另存爲一個名爲「custom_pwm_ip」工程code
2.1 建立自定義IP
1)點擊菜單「Tools->Create and Package IP...」
2)選擇「Next」
3)選擇建立一個新的AXI4設備
4)名稱填寫「ax_pwm」,描述填寫「alinx pwm」,而後選擇一個合適的位置用來放IP
5)下面參數能夠指定接口類型、寄存器數量等,這裏不須要修改,使用AXI Lite Slave接口,4個寄存器。
6)點擊「Finish」完成IP的建立
7)在「IP Catalog」中能夠看到剛纔建立的IP
8)這個時候的IP只有簡單的寄存器讀寫功能,咱們須要修改IP,選擇IP,右鍵「Edit in IP Packager」
9)這是彈出一個對話框,能夠填寫工程名稱和路徑,這裏默認,點擊「OK」
10)Vivado打開了一個新的工程
11)添加PWM功能的核心代碼
12)添加代碼時選擇複製代碼到IP目錄
13)修改「ax_pwm_v1_0.v」,添加一個pwm輸出端口
14)修改「ax_pwm_v1_0.v」,在例化「ax_pwm_V1_0_S00_AXI」,中添加pwm端口的例化
15)修改「ax_pwm_v1_0_s00_AXI.v」文件,添加pwm端口,這個文件是實現AXI4 Lite Slave的核心代碼
16)修改「ax_pwm_v1_0_s00_AXI.v」文件,例化pwm核心功能代碼,將寄存器slv_reg0和slv_reg1用於pwm模塊的參數控制。
17)雙擊「component.xml」文件
18)在「File Groups」選項中點擊「Merge changers from File Groups Wizard」
19)在「Customization Parameters」選項中點擊「Merge changes form Customization Parameters Wizard」
20)點擊「Re-Package IP」完成IP的修改
2.2 添加自定義IP到工程
1)搜索「pwm」,添加「ax_pwm_v1.0」
2)點擊「Run Connection Automation」
3)導出pwm端口
4)保存設計,並Generate Output Products
5)添加xdc文件分配管腳,把pwm_0輸出端口分配給LED1,作一個呼吸燈,編譯生成bit文件,導出硬件
如下爲軟件工程師負責內容。
1)啓動Vitis,新建APP,模板選擇「Hello World」
2)在bsp裏找到「xparameters.h」文件,這個很是重要的文件,裏面找到了自定IP的寄存器基地址,能夠找到自定義IP的基地址。
3)有個寄存器讀寫宏和自定義IP的基地址,咱們開始編寫代碼,測試自定義IP,咱們先經過寫寄存器AX_PWM_S00_AXI_SLV_REG0_OFFSET,控制PWM輸出頻率,而後經過寫寄存器AX_PWM_S00_AXI_SLV_REG1_OFFSET控制PWM輸出的佔空比。
#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "ax_pwm.h" #include "xil_io.h" #include "xparameters.h" #include "sleep.h" unsignedint duty; int main() { init_platform(); print("Hello World\n\r"); //pwm out period = frequency(pwm_out) * (2^N) / frequency(clk); AX_PWM_mWriteReg(XPAR_AX_PWM_0_S00_AXI_BASEADDR, AX_PWM_S00_AXI_SLV_REG0_OFFSET,17179);//200hz //duty = (2^N) * (1 - (duty cycle)) - 1 while(1){ for(duty =0x8fffffff; duty <0xffffffff; duty = duty +100000){ AX_PWM_mWriteReg(XPAR_AX_PWM_0_S00_AXI_BASEADDR, AX_PWM_S00_AXI_SLV_REG1_OFFSET, duty); usleep(100); } } cleanup_platform(); return0; }
4)經過運行代碼,咱們能夠看到PLLED1呈現出一個呼吸燈的效果。
5)經過debug,咱們來查看一下寄存器
6)進入debug狀態,按「F6」能夠單步運行。
7)經過菜單能夠查看「Memory」窗口
8)添加一個監視地址「0x80000000」
9)單步運行,觀察變化
經過本實驗咱們掌握了更多的Vitis調試技巧,掌握了ARM + FPGA開發的核心內容,就是ARM和FPGA數據交互。