1. 軟件平臺
vivado2019.1
2. 硬件平臺
PYNQ_Z2
3. 目的
旨在利用PS端來控制PWM波的頻率佔空比以及啓動和關閉。
在這裏不做太複雜的功能。
4. 自定義IP核
如果是剛接觸vivado,可以參考vivado-PYNQ_Z2-SDK入門教程
如果沒有自定義IP核的經驗,可以事先查看博客自定義IP核詳細流程
兩路pwm波,這裏設置用兩個16位數據來控制頻率和佔空比,一位來做使能,所以只需要3個寄存器,這裏最低4個,選擇4個寄存器。
由於數據量極低,接口類型選擇Lite就可以滿足了。
這裏AXI接口數量,自行探討。
這裏新建一個源文件,pwm_gen.v
代碼如下
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/10/05 15:33:27
// Design Name:
// Module Name: pwm_gen
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/10/05 10:41:44
// Design Name:
// Module Name: pwm_gen
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/10/03 18:09:27
// Design Name:
// Module Name: pwm_gen
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
/*時鐘信號 clk
復位信號 rst
使能信號 en
週期 period = clk/f
佔空比 h_time = period * D
輸出 pwm
*/
module pwm_gen(
input clk,
input rst,
input en,
input [15:0]period,
input [15:0]h_time,
output reg pwm
);
reg [31:0]CNT;
always @(posedge clk or negedge rst)
begin
if(!rst)
CNT <= 0;
else if(CNT >= period-1 || en ==0)
CNT <= 0;
else
CNT <= CNT + 1'b1;
end
always @(posedge clk or negedge rst)
begin
if(!rst)
pwm <= 0;
else
begin
if(en == 0)
pwm <= 0;
else
begin
if(CNT <= h_time-1)
pwm <=1;
else
pwm <= 0;
end
end
end
endmodule
在該文件下添加寄存器輸出的數據“端口”
點擊保存
轉到top level,主要是調用模塊
添加輸出端口,
“輸出寄存器的值”
調用pwm發生器模塊
// Add user logic here
//pwm0
pwm_gen pwm0(
.clk(s00_axi_aclk),
.rst(s00_axi_aresetn),
.en(en),
.period(ctrl_pwm0[15:0]),
.h_time(ctrl_pwm0[31:16]),
.pwm(pwm_out0)
);
//pwm1
pwm_gen pwm1(
.clk(s00_axi_aclk),
.rst(s00_axi_aresetn),
.en(en),
.period(ctrl_pwm1[15:0]),
.h_time(ctrl_pwm1[31:16]),
.pwm(pwm_out1)
);
// User logic ends
然後保存,進行綜合,這裏只需要run synthesis,不需要implementation (作用是防止錯漏,但不能完全檢查出來)
無誤後,re_pakage-IP,,這樣一個pwm發生器的IP核就建立好了
下圖是block design
然後generate output product
然後選擇create HDL wrapper
再添加時序約束
##Raspberry Digital I/O
set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { pwm_out0 }]; #IO_L22P_T3_34 Sch=rpio_02_r
set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { pwm_out1 }]; #IO_L22N_T3_34 Sch=rpio_03_r
最後點擊generate bitstream
之後的步驟參考自定義IP核詳細流程
SDK工程代碼如下
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
/* Include Files */
#include "xparameters.h"
#include "xil_io.h"
#include "xstatus.h"
/* Definitions */
#define printf xil_printf /* smaller, optimised printf */
/*
* pwm_gen 16λ Ϊperiod 15λΪ ռ¿ձȪperiod 1λΪenable
*/
u32 pwm_gen0= 0x0BB81388; /* h_time & period*/
u32 pwm_gen1= 0x094c1388; /* h_time & period*/
u32 pwm_en = 0x01; /*enable flag*/
#define pwm0 0x43c00000 /* address of pwm0 configure register*/
#define pwm1 0x43c00004 /* address of pwm0 configure register*/
#define en 0x43c00008 /* address of enable flag configure register*/
int main()
{
init_platform();
print("Hello World\n\r");
cleanup_platform();
/* Execute the pwm output. */
Xil_Out32(pwm0,pwm_gen0); //configure pwm0 period and D
Xil_Out32(pwm1,pwm_gen1); //configure pwm1 period and D
Xil_Out32(en,pwm_en); // enable pwm0 pwm1 at the same time
return 0;
}
注意:寄存器的地址間隔爲4
運行結果如下
pwm0輸出20khz,佔空比爲50%
pwm0輸出20khz,佔空比爲47.6%
pwm0和pwm1沒有相位偏移(verilog部分沒操作好可能會造成一定的相位偏移,這是由於pwm發生器計數不是同時開始而造成的)