三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

简易寄存器接口SMMR---pwm控制器

简易寄存器接口SMMR---pwm控制器

参考

简易寄存器接口SMMR的vio_uart桥接.csdn
简易寄存器接口SMMR.csdn
可配置的PWM外设模块.csdn

pwm_slot.v

`timescale 1ns / 1ps module pwm_slot #( parameter P_ADDR_WIDTH = 8, parameter P_DATA_WIDTH = 32, parameter [P_ADDR_WIDTH-1:0] P_SLOT_BASE = 0, parameter P_REG_COUNT = 32, parameter P_NUM_PWM = 1, parameter P_COUNTER_WIDTH = 32, parameter [P_COUNTER_WIDTH-1:0] P_DEFAULT_PERIOD = 4096 )( input wire i_clk, input wire i_rst_n, //================================================== // SMMR //================================================== input wire i_reg_wr_en, input wire [P_ADDR_WIDTH-1:0] i_reg_wr_addr, input wire [P_DATA_WIDTH-1:0] i_reg_wr_data, input wire [P_ADDR_WIDTH-1:0] i_reg_rd_addr, output reg [P_DATA_WIDTH-1:0] o_reg_rd_data, //================================================== // PWM output //================================================== output wire [P_NUM_PWM-1:0] o_pwm ); //////////////////////////////////////////////////////////////////////////// // PWM SLOT Register Map //////////////////////////////////////////////////////////////////////////// localparam [P_ADDR_WIDTH-1:0] ADDR_CONTROL = P_SLOT_BASE + 9'd0; // 控制寄存器 bit0: enable localparam [P_ADDR_WIDTH-1:0] ADDR_STATUS = P_SLOT_BASE + 9'd1; // 状态寄存器 bit0: param_error localparam [P_ADDR_WIDTH-1:0] ADDR_PERIOD = P_SLOT_BASE + 9'd2; // PWM周期 localparam [P_ADDR_WIDTH-1:0] ADDR_DUTY0 = P_SLOT_BASE + 9'd16; // PWM0占空比 localparam [P_ADDR_WIDTH-1:0] ADDR_DUTY_MAX = P_SLOT_BASE + 9'd31; // 最大PWM通道地址 //////////////////////////////////////////////////////////////////////////// // Register //////////////////////////////////////////////////////////////////////////// reg [P_DATA_WIDTH-1:0] r_ctrl; reg [P_DATA_WIDTH-1:0] r_period; reg [P_DATA_WIDTH-1:0] r_duty [0:P_NUM_PWM-1]; reg [P_DATA_WIDTH-1:0] r_status; //////////////////////////////////////////////////////////////////////////// // PWM runtime //////////////////////////////////////////////////////////////////////////// reg [P_COUNTER_WIDTH-1:0] r_cnt; reg [P_COUNTER_WIDTH-1:0] r_period_latch; reg [P_COUNTER_WIDTH-1:0] r_duty_latch [0:P_NUM_PWM-1]; integer i; //////////////////////////////////////////////////////////////////////////// // SMMR WRITE //////////////////////////////////////////////////////////////////////////// always @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) begin r_ctrl <= 0; r_period <= P_DEFAULT_PERIOD; for(i=0;i<P_NUM_PWM;i=i+1) r_duty[i] <= 0; end else begin if(i_reg_wr_en) begin case(i_reg_wr_addr) ADDR_CONTROL: r_ctrl <= i_reg_wr_data; ADDR_PERIOD: r_period <= i_reg_wr_data; default: for(i=0;i<P_NUM_PWM;i=i+1) if(i_reg_wr_addr == (ADDR_DUTY0+i)) r_duty[i] <= i_reg_wr_data; endcase end end end //////////////////////////////////////////////////////////////////////////// // STATUS //////////////////////////////////////////////////////////////////////////// always @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_status <= 0; else begin r_status[0] <= (r_period==0); end end //////////////////////////////////////////////////////////////////////////// // Period counter //////////////////////////////////////////////////////////////////////////// always @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) begin r_cnt <= 0; r_period_latch <= P_DEFAULT_PERIOD; end else if(r_ctrl[0]) begin if(r_cnt >= r_period_latch-1) begin r_cnt <= 0; r_period_latch <= r_period; for(i=0;i<P_NUM_PWM;i=i+1) r_duty_latch[i] <= r_duty[i]; end else r_cnt <= r_cnt + 1'b1; end else begin r_cnt <= 0; r_period_latch <= r_period; for(i=0;i<P_NUM_PWM;i=i+1) r_duty_latch[i] <= r_duty[i]; end end //////////////////////////////////////////////////////////////////////////// // SMMR READ //////////////////////////////////////////////////////////////////////////// always @(*) begin o_reg_rd_data = 0; if((i_reg_rd_addr >= P_SLOT_BASE) && (i_reg_rd_addr < P_SLOT_BASE+P_REG_COUNT)) begin case(i_reg_rd_addr) ADDR_CONTROL: o_reg_rd_data = r_ctrl; ADDR_STATUS: o_reg_rd_data = r_status; ADDR_PERIOD: o_reg_rd_data = r_period; default: for(i=0;i<P_NUM_PWM;i=i+1) if(i_reg_rd_addr == (ADDR_DUTY0+i)) o_reg_rd_data = r_duty[i]; endcase end end //////////////////////////////////////////////////////////////////////////// // PWM output //////////////////////////////////////////////////////////////////////////// genvar g; generate for(g=0;g<P_NUM_PWM;g=g+1) begin : GEN_PWM assign o_pwm[g] = (r_ctrl[0] && (r_cnt < r_duty_latch[g]))? 1'b1: 1'b0; end endgenerate endmodule

tb_pwm_slot.v

pwm0 占空比 50% ,pwm1 占空比 20%

`timescale 1ns / 1ps module pwm_slot #( parameter P_ADDR_WIDTH = 8, parameter P_DATA_WIDTH = 32, parameter [P_ADDR_WIDTH-1:0] P_SLOT_BASE = 0, parameter P_REG_COUNT = 32, parameter P_NUM_PWM = 1, parameter P_COUNTER_WIDTH = 32, parameter [P_COUNTER_WIDTH-1:0] P_DEFAULT_PERIOD = 4096 )( input wire i_clk, input wire i_rst_n, //================================================== // SMMR //================================================== input wire i_reg_wr_en, input wire [P_ADDR_WIDTH-1:0] i_reg_wr_addr, input wire [P_DATA_WIDTH-1:0] i_reg_wr_data, input wire [P_ADDR_WIDTH-1:0] i_reg_rd_addr, output reg [P_DATA_WIDTH-1:0] o_reg_rd_data, //================================================== // PWM output //================================================== output wire [P_NUM_PWM-1:0] o_pwm ); //////////////////////////////////////////////////////////////////////////// // PWM SLOT Register Map //////////////////////////////////////////////////////////////////////////// localparam [P_ADDR_WIDTH-1:0] ADDR_CONTROL = P_SLOT_BASE + 9'd0; // 控制寄存器 bit0: enable localparam [P_ADDR_WIDTH-1:0] ADDR_STATUS = P_SLOT_BASE + 9'd1; // 状态寄存器 bit0: param_error localparam [P_ADDR_WIDTH-1:0] ADDR_PERIOD = P_SLOT_BASE + 9'd2; // PWM周期 localparam [P_ADDR_WIDTH-1:0] ADDR_DUTY0 = P_SLOT_BASE + 9'd16; // PWM0占空比 localparam [P_ADDR_WIDTH-1:0] ADDR_DUTY_MAX = P_SLOT_BASE + 9'd31; // 最大PWM通道地址 //////////////////////////////////////////////////////////////////////////// // Register //////////////////////////////////////////////////////////////////////////// reg [P_DATA_WIDTH-1:0] r_ctrl; reg [P_DATA_WIDTH-1:0] r_period; reg [P_DATA_WIDTH-1:0] r_duty [0:P_NUM_PWM-1]; reg [P_DATA_WIDTH-1:0] r_status; //////////////////////////////////////////////////////////////////////////// // PWM runtime //////////////////////////////////////////////////////////////////////////// reg [P_COUNTER_WIDTH-1:0] r_cnt; reg [P_COUNTER_WIDTH-1:0] r_period_latch; reg [P_COUNTER_WIDTH-1:0] r_duty_latch [0:P_NUM_PWM-1]; integer i; //////////////////////////////////////////////////////////////////////////// // SMMR WRITE //////////////////////////////////////////////////////////////////////////// always @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) begin r_ctrl <= 0; r_period <= P_DEFAULT_PERIOD; for(i=0;i<P_NUM_PWM;i=i+1) r_duty[i] <= 0; end else begin if(i_reg_wr_en) begin case(i_reg_wr_addr) ADDR_CONTROL: r_ctrl <= i_reg_wr_data; ADDR_PERIOD: r_period <= i_reg_wr_data; default: for(i=0;i<P_NUM_PWM;i=i+1) if(i_reg_wr_addr == (ADDR_DUTY0+i)) r_duty[i] <= i_reg_wr_data; endcase end end end //////////////////////////////////////////////////////////////////////////// // STATUS //////////////////////////////////////////////////////////////////////////// always @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_status <= 0; else begin r_status[0] <= (r_period==0); end end //////////////////////////////////////////////////////////////////////////// // Period counter //////////////////////////////////////////////////////////////////////////// always @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) begin r_cnt <= 0; r_period_latch <= P_DEFAULT_PERIOD; end else if(r_ctrl[0]) begin if(r_cnt >= r_period_latch-1) begin r_cnt <= 0; r_period_latch <= r_period; for(i=0;i<P_NUM_PWM;i=i+1) r_duty_latch[i] <= r_duty[i]; end else r_cnt <= r_cnt + 1'b1; end else begin r_cnt <= 0; r_period_latch <= r_period; for(i=0;i<P_NUM_PWM;i=i+1) r_duty_latch[i] <= r_duty[i]; end end //////////////////////////////////////////////////////////////////////////// // SMMR READ //////////////////////////////////////////////////////////////////////////// always @(*) begin o_reg_rd_data = 0; if((i_reg_rd_addr >= P_SLOT_BASE) && (i_reg_rd_addr < P_SLOT_BASE+P_REG_COUNT)) begin case(i_reg_rd_addr) ADDR_CONTROL: o_reg_rd_data = r_ctrl; ADDR_STATUS: o_reg_rd_data = r_status; ADDR_PERIOD: o_reg_rd_data = r_period; default: for(i=0;i<P_NUM_PWM;i=i+1) if(i_reg_rd_addr == (ADDR_DUTY0+i)) o_reg_rd_data = r_duty[i]; endcase end end //////////////////////////////////////////////////////////////////////////// // PWM output //////////////////////////////////////////////////////////////////////////// genvar g; generate for(g=0;g<P_NUM_PWM;g=g+1) begin : GEN_PWM assign o_pwm[g] = (r_ctrl[0] && (r_cnt < r_duty_latch[g]))? 1'b1: 1'b0; end endgenerate endmodule

测试

输出

run all READaddr=0data=00000001 READaddr=1data=00000000 READaddr=2data=000003e8 READaddr=16data=000000c8 READaddr=17data=000001f4
← 返回列表