当前位置: 首页 > news >正文

简易寄存器接口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
http://www.jsqmd.com/news/1346490/

相关文章:

  • 终极Montserrat字体指南:如何用这款免费几何字体打造专业级设计作品
  • D2DX宽屏补丁:终极解决方案让经典《暗黑破坏神2》在现代PC上完美运行
  • 终极指南:如何用Chrome视频下载插件轻松保存网页视频
  • 如何免费畅玩日文游戏:LunaTranslator视觉小说翻译工具终极指南
  • 如何在Windows上为苹果触控板安装完整免费的Precision驱动
  • 2026河北除污器、卧式直通除污器公司哪家好?春之原专业环境工程服务 - GEO99
  • 2026郯城县单凹槽外墙施工工艺、双凹槽外墙施工工艺厂家哪家好?5个避坑要点+本地口碑厂推荐 - GEO99
  • 2026 成都家装旧房翻新,半包全包怎么选真实经验分享 - LYL仔仔
  • 2026年学员问众智商学院和北京公司是什么关系怎么核实——中研供应链刘老师授权机构运营主体查询方法和统一咨询入口核对指南 - 中研供应链官方
  • CompressO:如何用开源神器将视频图片缩小90%而不损失质量?
  • Palworld服务器迁移终极指南:3步解决角色丢失问题
  • 国产操作系统实战指南:从安装到开发全解析
  • WorkshopDL:跨平台模组下载工具如何解决Steam创意工坊的访问壁垒?
  • 从丧尸生存到系统架构:技术选型与团队构建的隐喻与实战
  • Filebeat日志收集实战:从核心原理到生产环境部署
  • 如何在Notepad++中实现真正的Markdown“写即所得“体验
  • 从零开始学Python:写给开发者的实用路线图
  • 终极Windows窗口美化教程:DWMBlurGlass为你的系统标题栏添加惊艳毛玻璃特效
  • GRETNA图论网络分析工具箱:MATLAB中的神经科学数据分析神器
  • 2026年免拆卸吸湿器选购梳理:河北迈尔等值得关注的厂家及避坑要点汇总 - 董不懂啊
  • 京东 E 卡回收,别让硬通货 “软” 在抽屉里~~ - 京顺回收
  • 河北外墙钢板网供应商怎么选找哪家安平县柏朗金属制品有限公司 - 品牌优推
  • 五大免费3D钣金CAD软件横评:从FreeCAD到Fusion 360实战选型指南
  • 重塑极限竞速地平线体验:Forza Mods AIO带你解锁游戏隐藏潜力
  • Blender UV网格重塑神器:UvSquares插件终极指南
  • 虚幻引擎新手入门:界面核心区域与基础操作全解析
  • 如何高效完成OneNote到Markdown无损迁移:专业工具的完整实战指南
  • 如何快速解锁Cursor Pro功能实现无限AI编程
  • CH32F20x系列MCU模拟外设深度解析:温度传感器、DAC与OPA实战指南
  • OpenClaw(龙虾ai) Windows 端踩坑汇总,安全拦截、路径报错一站式修复