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
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
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
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; }
时间: 2024-10-14 21:15:01