SoC 自定义 IP 核--呼吸灯


一、新建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;

}


继续参考博客运行即可。

猜你喜欢

转载自blog.csdn.net/weixin_46628481/article/details/125891189
soc