forked from SJTU-YONGFU-RESEARCH-GRP/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparameterized_pwm.v
More file actions
executable file
·161 lines (154 loc) · 6.67 KB
/
parameterized_pwm.v
File metadata and controls
executable file
·161 lines (154 loc) · 6.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/**
* Parameterized PWM (Pulse Width Modulation) Generator
*
* This module implements a configurable PWM generator that produces a pulse
* width modulated signal with programmable duty cycle and frequency. PWM is
* widely used for motor control, LED dimming, and power regulation.
*
* Key Features:
* - Configurable duty cycle: 0 to 100% via duty input
* - Configurable frequency: Via clock divider
* - Configurable polarity: Active high or active low output
* - Configurable resolution: Via CNT_WIDTH parameter
* - Enable control: Can pause/resume PWM generation
*
* PWM Operation:
* - Counter counts from 0 to 2^CNT_WIDTH - 1
* - Output is high when counter < duty
* - Output is low when counter >= duty
* - Duty cycle = duty / 2^CNT_WIDTH
*
* Frequency Control:
* - Clock divider: Divides input clock by (div + 1)
* - PWM frequency = f_clk / ((div + 1) × 2^CNT_WIDTH)
* - div = 0: No division (maximum frequency)
*
* Resolution:
* - CNT_WIDTH determines duty cycle resolution
* - Resolution = 1 / 2^CNT_WIDTH
* - Example: CNT_WIDTH=8 → 256 steps (0.39% resolution)
*
* Polarity:
* - POLARITY=1: Active high (high = on, low = off)
* - POLARITY=0: Active low (low = on, high = off)
*
* Use Cases:
* - Motor speed control
* - LED brightness control
* - Power regulation (switching regulators)
* - Audio generation
* - Servo control
*
* @param CNT_WIDTH Counter width (default: 8 bits)
* Determines duty cycle resolution: 1 / 2^CNT_WIDTH
* @param POLARITY Output polarity: 1=active high, 0=active low (default: 1)
* @param DIV_WIDTH Clock divider width (default: 16 bits)
*
* @input clk Input clock signal
* @input rst_n Active-low reset signal
* @input enable Enable PWM generation (high to enable)
* @input duty[CNT_WIDTH-1:0] Duty cycle value
* Duty cycle = duty / 2^CNT_WIDTH
* @input div[DIV_WIDTH-1:0] Clock divider value
* PWM clock = clk / (div + 1), div=0 means no division
* @output pwm_out PWM output signal
*/
module parameterized_pwm #(
parameter CNT_WIDTH = 8, // Counter width (resolution)
parameter POLARITY = 1, // Output polarity (1: active high, 0: active low)
parameter DIV_WIDTH = 16 // Clock divider width
)(
input wire clk, // Input clock
input wire rst_n, // Active low reset
input wire enable, // Module enable
input wire [CNT_WIDTH-1:0] duty, // Duty cycle value
input wire [DIV_WIDTH-1:0] div, // Optional frequency divider
output wire pwm_out // PWM output
);
// Counter and clock divider registers
reg [CNT_WIDTH-1:0] counter;
reg [DIV_WIDTH-1:0] div_counter;
reg pwm_reg;
wire tick;
// ============================================================================
// Clock Divider Logic
// ============================================================================
// Divides input clock to generate PWM clock
// Generates tick when div_counter reaches div
always @(posedge clk) begin
if (!rst_n) begin
div_counter <= 0;
end else if (enable) begin
if (div_counter >= div) begin
// ================================================================
// Divider Period Complete
// ================================================================
// Reset divider counter for next period
div_counter <= 0;
end else begin
// ================================================================
// Divider Counting
// ================================================================
// Increment divider counter
div_counter <= div_counter + 1;
end
end
end
// ============================================================================
// Tick Generation
// ============================================================================
// Generate tick when divider period completes
// If div=0, no division (tick always high)
assign tick = (div == 0) ? 1'b1 : (div_counter >= div);
// ============================================================================
// PWM Counter Logic
// ============================================================================
// Counts from 0 to 2^CNT_WIDTH - 1 to create PWM period
always @(posedge clk) begin
if (!rst_n) begin
counter <= 0;
end else if (enable && tick) begin
// ====================================================================
// Counter Update
// ====================================================================
if (counter >= {CNT_WIDTH{1'b1}}) begin
// ================================================================
// Counter Wrap-Around
// ================================================================
// Counter reached maximum: wrap to 0
counter <= 0;
end else begin
// ================================================================
// Counter Increment
// ================================================================
// Increment counter for PWM period generation
counter <= counter + 1;
end
end
end
// ============================================================================
// PWM Output Logic
// ============================================================================
// Generates PWM output based on counter and duty cycle
always @(posedge clk) begin
if (!rst_n) begin
pwm_reg <= 0;
end else if (enable) begin
// ====================================================================
// PWM Generation
// ====================================================================
// Output is high when counter < duty
// This creates the pulse width modulation
// Duty cycle = duty / 2^CNT_WIDTH
pwm_reg <= (counter < duty);
end else begin
// ====================================================================
// Disabled State
// ====================================================================
// PWM disabled: output is low
pwm_reg <= 0;
end
end
// Output with configurable polarity (using 1-bit comparison to fix WIDTHTRUNC warning)
assign pwm_out = (POLARITY != 0) ? pwm_reg : ~pwm_reg;
endmodule