PWM定制组件实现过程

module pwm_task_logic
(
    clk,
    pwm_enable,
    resetn, 
    clock_divide,
    duty_cycle,
    pwm_out
);

//Inputs
input clk;                //Input Clock to be divided
input [31:0] clock_divide;    //Clock Divide value
input [31:0] duty_cycle;    //Duty Cycle vale
input pwm_enable;            //Enable signal
input resetn;            //Reset

//Outputs
output pwm_out;            //PWM output

//Signal Declarations    
reg [31:0] counter;        //PWM Internal Counter
reg pwm_out;            //PWM output
    
//Start Main Code    
always @(posedge clk or negedge resetn)         //PWM Counter Process
begin
    if (~resetn)begin
        counter <= 0;
    end
    else if(pwm_enable)begin
        if (counter >= clock_divide)begin
            counter <= 0;
        end
        else begin    
            counter <= counter + 1;
        end
    end
    else begin
        counter <= counter;            
    end
end

always @(posedge clk or negedge resetn)      //PWM Comparitor
begin
    if (~resetn)begin
        pwm_out <= 0;
    end
    else if(pwm_enable)begin
        if (counter >= duty_cycle)begin
            pwm_out <= 1'b1;
        end
        else begin
            if (counter == 0)
                pwm_out <= 0;
            else
                pwm_out <= pwm_out;
            end
        end
    else begin
        pwm_out <= 1'b0;
    end
end

    
endmodule
View Code
module pwm_register_file
(    //Avalon Signals
    clk,
    resetn, 
    chip_select,
    address,
    write,
    write_data,
    read,
    read_data,

    //PWM Output Signals
    pwm_clock_divide,
    pwm_duty_cycle,
    pwm_enable
);

//Parameters
parameter clock_divide_reg_init = 32'h0000_0000;
parameter duty_cycle_reg_init   = 32'h0000_0000;

//Inputs

input clk;                  //System Clock
input resetn;            //System Reset
input chip_select;        //Avalon Chip select signal
input [1:0] address;          //Avalon Address bus 
input write;            //Avalon Write signal
input [31:0] write_data;    //Avalon Write data bus
input read;                  //Avalon read signal
    
//Outputs
output [31:0] read_data;      //Avalon read data bus
output [31:0] pwm_clock_divide; //PWM clock divide drive signals
output [31:0] pwm_duty_cycle;   //PWM duty cycle drive signals
output        pwm_enable;       //PWM enable drive signals

//Signal Declarations    
        
reg [31:0] clock_divide_register;    //Clock divider register
reg [31:0] duty_cycle_register;      //Duty Cycle Register
reg        enable_register;         //Enable Bit    
reg [31:0] read_data;            //Read_data bus
    
//Nodes used for address decoding
wire clock_divide_reg_selected, duty_cycle_reg_selected, enable_reg_selected;
//Nodes for determining if a valid write occurred to a specific address
wire write_to_clock_divide, write_to_duty_cycle, write_to_enable;
//Nodes for determining if a valid read occurred to a specific address
wire read_to_clock_divide, read_to_duty_cycle, read_to_enable;
//Nodes used to determine if a valid access has occurred
wire valid_write, valid_read;

//Start Main Code    

//address decode
assign clock_divide_reg_selected = !address[1] & !address[0];  //address 00
assign duty_cycle_reg_selected   = !address[1] &  address[0];  //address 01
assign enable_reg_selected       =  address[1] & !address[0];  //address 10

//determine if a vaild transaction was initiated 
assign valid_write = chip_select & write;        
assign valid_read  = chip_select & read;

//determine if a write occurred to a specific address
assign write_to_clock_divide = valid_write & clock_divide_reg_selected;
assign write_to_duty_cycle   = valid_write & duty_cycle_reg_selected;
assign write_to_enable       = valid_write & enable_reg_selected;

//determine if a read occurred to a specific address
assign read_to_clock_divide = valid_read & clock_divide_reg_selected;
assign read_to_duty_cycle   = valid_read & duty_cycle_reg_selected;
assign read_to_enable       = valid_read & enable_reg_selected;

//Write to clock_divide Register
always@(posedge clk or negedge resetn)
begin
    if(~resetn)begin //Async Reset
        clock_divide_register <= clock_divide_reg_init; //32'h0000_0000;
    end
    else begin    
        if(write_to_clock_divide) begin
            clock_divide_register <= write_data;      
        end
        else begin
            clock_divide_register <= clock_divide_register;  
        end
        
    end
end    

//Write to duty_cycle Register
always@(posedge clk or negedge resetn)
begin
    if(~resetn)begin //Async Reset
        duty_cycle_register <= duty_cycle_reg_init; //32'h0000_0000;
    end
    else begin    
        if(write_to_duty_cycle) begin
            duty_cycle_register <= write_data;      
        end
        else begin
            duty_cycle_register <= duty_cycle_register;  
        end
    end
end    

//Write to enable register
always@(posedge clk or negedge resetn)
begin
    if(~resetn)begin //Async Reset
        enable_register <= 1'b0;
    end
    else begin
        if(write_to_enable)begin
            enable_register <= write_data[0];
        end
        else begin
            enable_register <= enable_register;
        end
    end
end

//Read Data Bus Mux
always@(read_to_clock_divide or read_to_duty_cycle or read_to_enable or clock_divide_register or duty_cycle_register or enable_register)
begin
    if(read_to_clock_divide) begin
        read_data = clock_divide_register;
    end
    else if(read_to_duty_cycle) begin
        read_data = duty_cycle_register;
    end
    else if(read_to_enable) begin
        read_data = {31'd0,enable_register};
    end
    else begin
        read_data = 32'h0000_0000;
    end
end

//assign register values to register file outputs to the PWM
assign pwm_clock_divide = clock_divide_register;
assign pwm_duty_cycle = duty_cycle_register;
assign pwm_enable = enable_register;

endmodule
View Code
 
module pwm_avalon_interface
(    clk,
    resetn,
    avalon_chip_select,
    address,
    write,
    write_data,
    read,
    read_data,
    pwm_out
 );

//Parameter values to pass to pwm_register_file instance
parameter clock_divide_reg_init = 32'h0000_0000;
parameter duty_cycle_reg_init = 32'h0000_0000;

//Avalon_Slave_PWM Avalon I/O
input clk;                   //System clock - tied to all blocks
input resetn;             //System reset - tied to all blocks
input avalon_chip_select;    //Avalon Chip select
input [1:0]address;          //Avalon Address bus 
input write;            //Avalon Write signal
input [31:0]write_data;        //Avalon Write data bus
input read;                    //Avalon Read signal
    
output [31:0]read_data;        //Avalon Read data bus

//Avalon_Slave_PWM Exported I/O
output pwm_out;              //PWM output signal
    
//Avalon_Slave_PWM Interal Nodes
wire [31:0] pwm_clock_divide;  //Clock divide wire from register file to pwm task logic
wire [31:0] pwm_duty_cycle;    //Duty cycle value from register file to pwm task logic
wire           pwm_enable;        //PWM enable signal from register file to pwm task logic
    

//PWM Instance
pwm_task_logic task_logic
(
    .clk             (clk ),
    .pwm_enable       (pwm_enable),
    .resetn           (resetn),
    .clock_divide     (pwm_clock_divide),
    .duty_cycle       (pwm_duty_cycle),
    .pwm_out        (pwm_out)
);

//Register File instance
pwm_register_file #(clock_divide_reg_init, duty_cycle_reg_init) memory_element
(    
    .clk                 (clk),
    .resetn            (resetn),
    .chip_select       (avalon_chip_select),
    .address           (address),
    .write             (write),
    .write_data        (write_data),
    .read              (read),
    .read_data         (read_data),
    .pwm_clock_divide  (pwm_clock_divide),
    .pwm_duty_cycle     (pwm_duty_cycle),
    .pwm_enable           (pwm_enable)
);

endmodule
View Code

 

 

PWM软件测试代码:

#include <stdio.h>
#include "system.h"
#include "unistd.h"

typedef struct{
        volatile unsigned int divi;
        volatile unsigned int duty;
        volatile unsigned int enable;
    }PWM;

    int main()
    {
    int dir = 1;
    int d = 0 ;

        //将pwm指向PWM_0_BASE首地址
    PWM *pwm = (PWM *)PWM_AVALON_INTERFACE_0_BASE;
    //对pwm进行初始化,divi最大值为232-1。
        pwm->divi = 50000000;
        pwm->duty = 0;
        pwm->enable = 1;

        //通过不断的改变duty值来改变LED一个周期亮灯的时间长短
        while(1){
            if(dir > 0){
                if(pwm->duty < pwm->divi)
                { pwm->duty += 1000000;
                    d++ ;
                }
                else
                { dir = 0;
                    d = 0;}
            }
            else{
                if(pwm->duty > 0)
                {
                    pwm->duty -= 1000000;
                d--;
                }
                else
                    dir = 1;
            }

            usleep(1000000);

            printf("hello from pwm %d",d);
        }

        return 0;
    }
View Code

 

posted @ 2015-01-31 00:35  ylqin  阅读(275)  评论(0编辑  收藏  举报