自定义IP
实现从PS段配置输出频率,输出占空比,输出使能配置
配置界面Clk Hz为AXI总线参考时钟
模块底层代码
module breath_pwm
#(
parameter CLK_HZ = 100_000_000 // 输入时钟频率
)
(
input wire sys_clk, // 100 MHz
input wire sys_rst_n, // 低电平复位
input wire [13:0] set_freq_duty, // 0-10000 对应 0%-100%
input wire set_freq_en, // 使能,为 0 时 PWM 输出 0
input wire [24:0] set_freq, // 目标频率,单位 Hz
output reg PWM
);
//------------------------------------------------------------------
// 1. 计算一个 PWM 周期所需的时钟周期数
//------------------------------------------------------------------
reg [31:0] period_cnt_max; // = CLK_HZ / set_freq
wire [31:0] next_period_cnt_max =(set_freq == 0) ? 32'hFFFF_FFFF : (CLK_HZ / set_freq);
always @(posedge sys_clk or negedge sys_rst_n)
if (!sys_rst_n) begin
period_cnt_max <= 32'hFFFF_FFFF;
end
else if (set_freq_en) begin
period_cnt_max <= next_period_cnt_max;
end
//------------------------------------------------------------------
// 2. 计算高电平持续时间(高电平时钟周期数)
//------------------------------------------------------------------
wire [31:0] high_cnt =((period_cnt_max * set_freq_duty) + 15'd5000) / 16'd10000; // 四舍五入
//------------------------------------------------------------------
// 3. PWM 周期计数器 & 输出逻辑
//------------------------------------------------------------------
reg [31:0] period_cnt;
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
period_cnt <= 32'd0;
PWM <= 1'b0;
end
else if (!set_freq_en) begin
period_cnt <= 32'd0;
PWM <= 1'b0;
end
else begin
if (period_cnt >= period_cnt_max - 32'd1) begin
period_cnt <= 32'd0;
end
else begin
period_cnt <= period_cnt + 32'd1;
PWM <= (period_cnt < high_cnt) ? 1'b1 : 1'b0;
end
end
end
endmodule
顶层AXI接口封装
测试工程
#include "AXI_PWM.h"
#include "xparameters.h"
#include "stdio.h"
#include "xil_io.h"
#include "sleep.h"
#include "xil_printf.h"
#define PWM_BASEADDR XPAR_AXI_PWM_0_S0_AXI_BASEADDR //AXI_PWM IP 基地址
//AXI_PWM IP 寄存器偏移地址
#define AXI_PWM_REG0 AXI_PWM_S0_AXI_SLV_REG0_OFFSET //[13:0]:PWM输出占空比,10000映射到100.00
#define AXI_PWM_REG1 AXI_PWM_S0_AXI_SLV_REG1_OFFSET //[0 :0]:PWM输出使能位
#define AXI_PWM_REG2 AXI_PWM_S0_AXI_SLV_REG2_OFFSET //[25:0]:PWM输出频率(Hz)
#define AXI_PWM_REG3 AXI_PWM_S0_AXI_SLV_REG3_OFFSET //[x :x]:NC
int main(){
xil_printf("AXI_IP_PWM!!\r\n");
AXI_PWM_mWriteReg(PWM_BASEADDR, AXI_PWM_REG0, 0x04D2); //50.00% 0x1388->5000 0x04D2->1234
AXI_PWM_mWriteReg(PWM_BASEADDR, AXI_PWM_REG2, 0x04D2); //100khz 0x186A0->100_000
while(1){
//打开输出使能
AXI_PWM_mWriteReg(PWM_BASEADDR, AXI_PWM_REG1, 1);
xil_printf("PWM ON\r\n");
sleep(1);
//关闭 输出使能
// AXI_PWM_mWriteReg(PWM_BASEADDR, AXI_PWM_REG1, 0);
// xil_printf("PWM OFF\r\n");
// sleep(1);
}
}
IP获取链接
通过网盘分享的文件:AXI_PWM_v1.0.zip
链接: https://pan.baidu.com/s/1ENpRrl0rJ-y4QVsz3ky9JA?pwd=5875 提取码: 5875
(PS:需要替换makefile文件)