一、新建IP核
1. 编写代码
pwm_logic
:
module pwm_logic (
input clk ,
input rst_n ,
input cn_en ,
input [31:0] counter_arr , // 最大值
input [31:0] counter_crr , // 比较值
output reg o_pwm
);
// 计数器--比较值
reg [31:0] cnt_compare;
wire add_com;
wire end_com;
// r
reg [31:0] counter_crr_r;
// 计数器--比较值
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_compare <= 32'b0;
end
else if (add_com) begin
if (end_com) begin
cnt_compare <= 32'b0;
end
else begin
cnt_compare <= cnt_compare + 1'b1;
end
end
else if (cn_en) begin
cnt_compare <= 0;
end
end
assign add_com = (~cn_end);
assign end_com = (add_com && (cnt_compare == counter_arr - 1));
// counter_crr_r
always @(posedge clk) begin
if (!cnt) begin
counter_crr_r <= counter_crr;
end
else begin
counter_crr_r <= counter_crr_r;
end
end
// o_pwm
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
o_pwm <= 0;
end
else if (cnt > counter_crr_r) begin
o_pwm <= 1;
end
else begin
o_pwm <= 0;
end
end
endmodule //pwm_logic
pwm_avalon.v
:
module pwm_avalon (
input clk ,
input rst_n ,
// avalon
input chipselect ,
input [1:0] address ,
input write ,
input [31:0] writedata ,
output [31:0] readdata ,
// o_pwm
output reg pwm_out
);
// 中间信号定义
reg [31:0] counter_arr; // 最大值
reg [31:0] counter_crr; // 比较值
reg control;
// r
reg [31:0] readdata_r;
// counter_arr
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter_arr <= 0;
end
else if (chipselect && write && (address == 0)) begin
counter_arr <= writedata;
end
else begin
counter_arr <= counter_arr;
end
end
// counter_crr
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter_crr <= 0;
end
else if (chipselect && write && (address == 1)) begin
counter_crr <= writedata;
end
else begin
counter_crr <= counter_crr;
end
end
// control
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
control <= 0;
end
else if (chipselect && write && (address == 2)) begin
control <= writedata;
end
else begin
control <= control;
end
end
// 读control寄存器
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
readdata_r <= 0;
end
// 延时一个时钟周期再读
else if (chipselect) begin
case (address)
0: readdata_r <= counter_arr;
1: readdata_r <= counter_crr;
2: readdata_r <= control;
default: readdata_r <= 0;
endcase
end
else begin
readdata_r <= readdata_r;
end
end
assign readdata = readdata_r;
pwm_logic u_pwm_logic(
/*input */ .clk (clk),
/*input */ .rst_n (rst_n),
/*input */ .cn_en (control),
/*input [31:0]*/ .counter_arr (counter_arr), // 最大值
/*input [31:0]*/ .counter_crr (counter_crr), // 比较值
/*output reg */ .o_pwm (pwm_out)
);
endmodule //pwm_avalon
2. 新建IP核
在Platfor Designer
中新建:
填写IP名称:
添加文件:
Signals & Interface
设置:
3. 创建IP
二、编写代码
1. 修改top
编译完毕后,参考SoC之HelloWorld
完成 生成rbf文件 、 生成新的hps_0头文件、生成dtb文件,并替换SD卡文件。
2. C代码编写
参考SoC之HelloWorld创建工程和文件,编写代码如下:
/*
* breath_led.c
*
* Created on: 2022年7月20日
* Author: 16438
*/
//gcc标准头文件
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
//HPS厂家提供的底层定义头文件
#define soc_cv_av //开发平台Cyclone V 系列
#include "hwlib.h"
#include "socal/socal.h"
#include "socal/hps.h"
//与用户具体的HPS 应用系统相关的硬件描述头文件
#include "hps_0.h"
#define HW_REGS_BASE (ALT_STM_OFST) //HPS外设地址段基地址
#define HW_REGS_SPAN (0x04000000) //HPS外设地址段地址空间 64MB大小
#define HW_REGS_MASK (HW_REGS_SPAN - 1) //HPS外设地址段地址掩码
static unsigned long * pwm_pio_virtual_base = NULL;
static void * virtual_base;
int init(){
// open函数打开MMU,获取总线虚拟地址
int fd = open("/dev/mem", (O_ASYNC | O_RDWR));
if (fd == -1){
printf("Open MMU 失败!\n");
}
virtual_base = mmap(NULL, HW_REGS_SPAN, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, HW_REGS_BASE);
if ((unsigned long)virtual_base == MAP_SHARED){
printf("地址映射失败");
return -1;
}
pwm_pio_virtual_base = virtual_base +
((unsigned long)(ALT_LWFPGASLVS_OFST + PWM_0_BASE) & (unsigned long)(HW_REGS_MASK));
return fd;
}
int main(){
int fd = init();
if (fd == -1){
printf("初始化失败!\n");
return 1;
}
int max_value = 100000; // 最大值
int compare_value = 0; // 比较值,比比较值大的时候为1
int dealt_value = 100; // 每次变化的值
int is_increasing = 1; // 是否在增加
(*(pwm_pio_virtual_base + 0)) = max_value; // 设置最大值
(*(pwm_pio_virtual_base + 1)) = compare_value; // 设置比较值,初始0
(*(pwm_pio_virtual_base + 2)) = 0; // 设置control,低有效
while (1){
// 一个时钟周期0.02微秒
usleep((int)(max_value * 0.02));
if (is_increasing){ // 增
compare_value += dealt_value;
if (compare_value >= max_value){
compare_value = max_value;
is_increasing = 0;
}
} else{ // 减
compare_value -= dealt_value;
if (compare_value <= 0){
compare_value = 0;
is_increasing = 1;
}
}
(*(pwm_pio_virtual_base + 1)) = compare_value; // 设置比较值
}
if (munmap(virtual_base, HW_REGS_SPAN) == -1){
printf("取消映射失败!\n");
close(fd);
return -1;
}
close(fd);
return 0;
}
继续参考博客运行即可。