SoC custom IP core--breathing light


1. Create a new IP core

1. Write code

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. Create a new IP core

New in Platfor Designer:
insert image description here


Fill in the IP name:
insert image description here


add files:
insert image description here


Signals & Interfaceset up:
insert image description here
insert image description here
insert image description here
insert image description here


3. Create an IP

insert image description here
insert image description here


2. Write code

1. Modify top

insert image description here

insert image description here

After compiling, refer to HelloWorld of SoC
to complete generating rbf file, generating new hps_0 header file, generating dtb file, and replacing SD card file.


2. C code writing

Refer to HelloWorld of SoC to create projects and files, and write the code as follows:

/*
 * 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;

}


Continue to refer to the blog to run.

Guess you like

Origin blog.csdn.net/weixin_46628481/article/details/125891189