Compare commits

...

10 Commits

Author SHA1 Message Date
8a7ed7a61b Update RGB PWM IP source list 2025-12-03 01:37:26 -08:00
631f46f339 Modify RGB PWM IP to use enable pulser instead of clock divider 2025-12-03 01:36:41 -08:00
8ffe9271f2 Modify hardware implemented PWM controller to use enable pulser 2025-12-03 00:07:02 -08:00
26eb01a9e8 Remove redundant clk_out from enable pulser
Was just passing through
2025-12-03 00:04:40 -08:00
6b441b12ae Add clock enable input to pwm_core 2025-12-03 00:02:34 -08:00
31730fba46 Add clock enable pulser with testbench
Clock divider implemented in RTL does not get implemented properly when
used inside IP block. Instead, this module will pulse an enable pin at
the same intervals, which will be used by other modules instead of a
separate clock.
2025-12-02 23:56:01 -08:00
067e4c1f6a Fix incorrect oen pin in HW PWM controller 2025-12-02 21:44:53 -08:00
941cbdf2dc Update HW PWM controller src list 2025-12-02 21:33:53 -08:00
1c532bdd95 Add HW PWM controller top module 2025-12-02 21:33:38 -08:00
616166f69f Add project for HW implementation of PWM controller 2025-12-02 21:19:16 -08:00
12 changed files with 163 additions and 16 deletions

View File

@ -0,0 +1,6 @@
#vivado 2022.1
[main]
PART = xc7z007sclg400-1
IP_REPO_PATHS = "IP/ UserIP/"

View File

@ -0,0 +1,2 @@
pwm_controller/con/blackboard.xdc

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,4 @@
hw_pwm_controller/src/top.v top=top
pwm_block/src/pwm_core.v
pwm_block/src/clk_enable_pulser.v

View File

@ -0,0 +1,12 @@
# Simulator xsim
[generics]
VCD_DUMPFILE=clk_enable_pulser_tb.vcd
[properties]
ACTIVE=1
TOP=clk_enable_pulser_tb
[files]
pwm_block/src/clk_enable_pulser.v
pwm_block/sim/clk_enable_pulser_tb.v

View File

@ -1,5 +1,5 @@
pwm_block/src/rgb_pwm_block.v top=rgb_pwm_block
pwm_block/src/rgb_pwm_block_S_AXI.v
pwm_block/src/pwm_core.v
pwm_block/src/conf_div.v
pwm_block/src/clk_enable_pulser.v

View File

@ -0,0 +1,41 @@
`timescale 1ns/1ps
module top (
input clk,
input [0:0] btn,
input [11:0] sw,
output [2:0] RGB_led_A,
output [7:0] led
);
wire pulse_en;
clk_enable_pulser enpulser (
.clk(clk),
.rst(0),
.sel(6),
.en_out(pulse_en)
);
wire cur_en = btn[0] ? pulse_en : 1;
wire oen = sw[11];
assign led[0] = oen;
pwm_core #(
.WINDOW_REG_SIZE(8)
) pwm_core_r (
.clk(clk),
.en(cur_en),
.rst(0),
.duty(sw[7:0]),
.window_width(255),
.oen(oen),
.pulse(RGB_led_A[0])
);
assign RGB_led_A[1] = 0;
assign RGB_led_A[2] = 0;
endmodule

View File

@ -0,0 +1,58 @@
`timescale 1ns/1ps
module clk_enable_pulser_tb #(
VCD_DUMPFILE = ""
);
reg clk = 0;
reg rst = 1;
reg [3:0] sel;
wire clk_out;
wire en_out;
clk_enable_pulser cut (
.clk(clk),
.rst(rst),
.sel(sel),
.clk_out(clk_out),
.en_out(en_out)
);
reg [4:0] test_counter = 0;
always @ (posedge clk) begin
if (en_out) begin
test_counter <= test_counter + 1;
end
end
integer k;
initial begin
rst = 1;
clk = 0;
#10
rst = 0;
sel = 2;
for (k=0; k<15; k=k+1) begin
#5 clk = 1;
#5 clk = 0;
end
sel = 3;
for (k=0; k<31; k=k+1) begin
#5 clk = 1;
#5 clk = 0;
end
$dumpvars;
$finish;
end
endmodule

View File

@ -5,6 +5,7 @@ module pwm_core_tb #(
);
reg clk = 0;
reg en = 1;
reg rst = 1;
reg [15:0] duty;
reg [15:0] window_width;
@ -16,6 +17,7 @@ pwm_core#(
.WINDOW_REG_SIZE(16)
) cut (
.clk(clk),
.en(en)
.rst(rst),
.duty(duty),
.window_width(window_width),

View File

@ -0,0 +1,19 @@
module clk_enable_pulser (
input clk,
input rst,
input [3:0] sel,
output wire en_out
);
reg [15:0] count = 0;
wire [15:0] trigger_bits = count >> sel;
always @ (posedge clk) begin
if (rst || trigger_bits) count <= 1;
else count <= count + 1;
end
assign en_out = count[sel];
endmodule

View File

@ -1,11 +1,10 @@
`timescale 1ns/1ps
/*
* @brief PWM controller for a single output
*
* @param WINDOW_REG_SIZE Window and duty register size in bits
*
* @param [in] clk PWM counter clock
* @param [in] en Clock enable
* @param [in] rst Asynchronous reset
* @param [in] duty Duty cycle high time in number of clock cycles
* @param [in] window_width Number of clock cycles in a window
@ -16,6 +15,7 @@ module pwm_core #(
WINDOW_REG_SIZE = 16
)(
input clk,
input en,
input rst,
input [WINDOW_REG_SIZE-1:0] duty,
input [WINDOW_REG_SIZE-1:0] window_width,
@ -26,11 +26,14 @@ module pwm_core #(
reg [WINDOW_REG_SIZE-1:0] duty_counter;
always @ (posedge(clk), posedge(rst)) begin
if (rst || duty_counter >= window_width - 1)
if (rst) duty_counter <= 0;
else if (en) begin
if (duty_counter >= window_width - 1)
duty_counter <= 0;
else
duty_counter <= duty_counter + 1;
end
end
wire pulse_high;

View File

@ -399,10 +399,6 @@
end
// Add user logic here
wire led_en;
assign led_en = slv_reg1[0];
assign led = led_en ? slv_reg0[7:0] : 0;
wire rst = ~S_AXI_ARESETN;
wire [15:0] duty_R = slv_reg0[15:0];
@ -413,17 +409,18 @@
wire [3:0] pwm_clk_mod = slv_reg3[11:8];
wire pwm_oen = slv_reg3[0];
wire pwm_clk;
wire pwm_clk_en;
conf_div clk_div (
.clk_in(S_AXI_ACLK),
.rst(S_AXI_ARESETN),
clk_enable_pulser clkdiv_pulser (
.clk(S_AXI_ACLK),
.rst(rst),
.sel(pwm_clk_mod),
.clk_out(pwm_clk)
.en_out(pwm_clk_en)
);
pwm_core core_R(
.clk(pwm_clk),
.en(pwm_clk_en),
.rst(rst),
.duty(duty_R),
.window_width(window_width),
@ -433,6 +430,7 @@
pwm_core core_G(
.clk(pwm_clk),
.en(pwm_clk_en),
.rst(rst),
.duty(duty_G),
.window_width(window_width),
@ -442,6 +440,7 @@
pwm_core core_B(
.clk(pwm_clk),
.en(pwm_clk_en),
.rst(rst),
.duty(duty_B),
.window_width(window_width),