Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- prescaling
- pwm
- D Flip Flop
- Recursion
- stop watch
- vivado
- dataflow modeling
- test bench
- Edge Detector
- BASYS3
- KEYPAD
- behavioral modeling
- structural modeling
- verilog
- Pspice
- Linked List
- half adder
- ring counter
- i2c 통신
- LED
- DHT11
- FND
- ATMEGA128A
- hc-sr04
- java
- atmega 128a
- soc 설계
- Algorithm
- gpio
- uart 통신
Archives
- Today
- Total
거북이처럼 천천히
Verilog RTL 설계(8월 1일 - 1, PWM - 5) 본문
1. Period = 100usec, Frequency = 10kHz인 Pulse wave를 128단계로 나누어 컨트롤하는 모듈 설계
< Source, Pulse wave를 128단계로 나누어 컨트롤하는 모듈 >
// PWM Duty ratio 128
module PWM_Duty_Ratio_cntr(
input clk, reset_p,
input [6:0] duty,
output pwm);
// Declare parameter.
parameter sysclk_freq = 100_000_000;
parameter duty_step = 128;
parameter pwm_freq = 10_000;
parameter temp = sysclk_freq / duty_step / pwm_freq;
parameter half_temp = temp / 2;
// Prescaling for making 10kHz pulse wave.
integer cnt_sysclk;
always @(posedge clk or posedge reset_p) begin
if(reset_p) cnt_sysclk = 0;
else begin
if(cnt_sysclk >= temp-1) cnt_sysclk = 0;
else cnt_sysclk = cnt_sysclk + 1;
end
end
wire clk_div_temp;
assign clk_div_temp = (cnt_sysclk < half_temp)? 0 : 1;
wire clk_div_temp_nedge;
edge_detector edge_detector_0(.clk(clk), .reset_p(reset_p), .cp(clk_div_temp), .n_edge(clk_div_temp_nedge));
// prescaling 128
reg [6:0] cnt_div_128;
always @(posedge clk or posedge reset_p) begin
if(reset_p) cnt_div_128 = 0;
else if(clk_div_temp_nedge) cnt_div_128 = cnt_div_128 + 1;
end
assign pwm = (cnt_div_128 < duty)? 1 : 0;
endmodule
// Edge Detector
module edge_detector (
input clk, reset_p,
input cp,
output p_edge, n_edge );
reg flip_flop_current, flip_flop_old;
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin
flip_flop_current <= 0;
flip_flop_old <= 0;
end
else begin
flip_flop_current <= cp;
flip_flop_old <= flip_flop_current;
end
end
assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10)? 1 : 0;
assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01)? 1 : 0;
endmodule
< Source, Top module >
// PWM Control top module
module PWM_top_module (
input clk, reset_p,
output led_pwm);
reg [31:0] cnt_sysclk;
always @(posedge clk) cnt_sysclk = cnt_sysclk + 1;
PWM_Duty_Ratio_cntr PWM_Module(.clk(clk), .reset_p(reset_p), .duty(cnt_sysclk[29:24]), .pwm(led_pwm));
endmodule
- Q) 아래 코드처럼 duty 값을 주었는데, 무엇을 의미하는가?
PWM_Duty_Ratio_cntr PWM_Module(.clk(clk), .reset_p(reset_p), .duty(cnt_sysclk[29:24]), .pwm(led_pwm));
- A) 아래 그림과 함께 보면 쉽게 이해할 수 있다.
- cnt_sysclk counter는 10ns마다 1씩 증가하는 counter이다.
- LSB 부근에 있는 bit 값들은 빠르게 변화하지만, MSB 부근에 있는 bit 값들은 상대적으로 천천히 변화하는 것을 확인할 수 있다.
- 이를 통해 MSB 부근에 있는 7bit 값들을 묶어 duty값으로 준다면 천천히 변화하겠지만, 반대로 LSB 부근에 있는 7bit 값들을 묶어 준다면 duty 값이 빠르게 변화할 것이다.
- Q) 구체적으로 얼마나 MSB 쪽으로 갈수록 duty가 천천히 변화하는가?
- A) LSB에서 MSB로 1bit 씩 이동할 때마다 2배씩 천천히 변화할 것이며, duty 값의 bit 숫자가 7bit에서 1bit씩 늘어날수록 2배씩 천천히 변화한다.
2. RGB diode에 PWM을 인가하여 다양한 색상 확인하기.
< Source, Pulse wave를 128단계로 나누어 컨트롤하는 모듈 >
// PWM Duty ratio 128 step cntr
module LED_PWM_cntr(
input clk, reset_p,
input [6:0] duty,
output pwm);
// Declare parameter
parameter sysclk_freq = 100_000_000;
parameter duty_step = 128;
parameter pwm_freq = 10_000;
// Prescaling for pwm frequency
parameter temp = sysclk_freq / duty_step / pwm_freq;
parameter half_temp = temp / 2;
reg [6:0] cnt_sysclk;
always @(posedge clk or posedge reset_p) begin
if(reset_p) cnt_sysclk = 0;
else cnt_sysclk = cnt_sysclk + 1;
end
wire clk_div_temp;
assign clk_div_temp = (cnt_sysclk < half_temp) ? 0 : 1;
wire clk_div_temp_nedge;
edge_detector edge_detector_0(.clk(clk), .reset_p(reset_p), .cp(clk_div_temp), .n_edge(clk_div_temp_nedge));
// Prescaling of duty ratio step 128
reg [6:0] cnt_duty_step;
always @(posedge clk or posedge reset_p) begin
if(reset_p) cnt_duty_step = 0;
else if(clk_div_temp_nedge) cnt_duty_step = cnt_duty_step + 1;
end
assign pwm = (clk_div_temp_nedge < duty)? 1 : 0;
endmodule
// edge detector.
module edge_detector (
input clk, reset_p,
input cp,
output p_edge, n_edge );
reg flip_flop_current, flip_flop_old;
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin
flip_flop_current <= 0;
flip_flop_old <= 0;
end
else begin
flip_flop_current <= cp;
flip_flop_old <= flip_flop_current;
end
end
assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10)? 1 : 0;
assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01)? 1 : 0;
endmodule
< Source, Top module >
// top module
module PWM_top_module (
input clk, reset_p,
output led_red,
output led_green,
output led_blue );
reg [31:0] cnt_sysclk;
always @(posedge clk) cnt_sysclk = cnt_sysclk + 1;
LED_PWM_cntr pwm_red(.clk(clk), .reset_p(reset_p), .duty(cnt_sysclk[28:23]), .pwm(led_red));
LED_PWM_cntr pwm_green(.clk(clk), .reset_p(reset_p), .duty(cnt_sysclk[27:22]), .pwm(led_green));
LED_PWM_cntr pwm_blue(.clk(clk), .reset_p(reset_p), .duty(cnt_sysclk[26:21]), .pwm(led_blue));
endmodule
< RGB LED 구동 영상 >
3. 다목적으로 사용 가능한 PWM의 Duty ratio 컨트롤 모듈
- LED를 연속적으로 켜져 있는 상태로 만들기 위해서는 10kHz 주파수를 갖는 PWM이 필요하지만, Motor에서는 연속적으로 구동하게 만들기 위해서는 100Hz 주파수를 갖는 PWM이 필요하다.
- 따라서 다양한 주파수를 갖는 PWM을 만드는 동시에 PWM의 duty ratio를 컨트롤 하기 위해서는 다목적으로 사용이 가능한 PWM Duty ratio 컨트롤이 가능한 모듈이 필요하다.
- 따라서 이번에는 만들고자하는 PWM의 frequency, Duty Step 값을 Parameter 값으로 받아 원하는 주파수를 갖는 PWM과 원하는 Duty ratio의 Step으로 컨트롤 할 수 있게끔 모듈을 설계하도록 하겠다.
< Source, 다목적으로 사용 가능한 PWM의 Duty ratio 컨트롤 모듈 >
// Control module for various duty ratios of various PWMs
module Multi_PWM_Duty_Ratio #(
// Declare parameter.
parameter pwm_freq = 10_000,
parameter duty_step = 128,
parameter sysclk_freq = 100_000_000,
parameter temp = sysclk_freq / pwm_freq / duty_step,
parameter temp_half = temp / 2
) ( input clk, reset_p,
input [31:0] duty,
output pwm);
// Prescaling for making pwm frequency.
integer cnt_sysclk;
always @(posedge clk or posedge reset_p) begin
if(reset_p) cnt_sysclk = 0;
else begin
if(cnt_sysclk >= temp - 1) cnt_sysclk = 0;
else cnt_sysclk = cnt_sysclk + 1;
end
end
wire clk_div_temp;
assign clk_div_temp = (cnt_sysclk < temp_half)? 0 : 1;
wire clk_div_temp_nedge;
edge_detector edge_detector_0(.clk(clk), .reset_p(reset_p), .cp(clk_div_temp), .n_edge(clk_div_temp_nedge));
// Prescaling for PWM Duty ratio step control
integer cnt_pwm;
always @(posedge clk or posedge reset_p) begin
if(reset_p) cnt_pwm = 0;
else if(clk_div_temp_nedge) begin
if(cnt_pwm >= duty_step - 1) cnt_pwm = 0;
else cnt_pwm = cnt_pwm + 1;
end
end
assign pwm = (cnt_pwm < duty)? 1 : 0;
endmodule
// Edge detector
module edge_detector (
input clk, reset_p,
input cp,
output p_edge, n_edge);
reg flip_flop_current, flip_flop_old;
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin
flip_flop_current <= 0;
flip_flop_old <= 0;
end
else begin
flip_flop_current <= cp;
flip_flop_old <= flip_flop_current;
end
end
assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10)? 1 : 0;
assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01)? 1 : 0;
endmodule
- clcok Pulse 값과 만들고자 하는 PWM의 주파수, Duty ratio의 step값을 Instance 생성할 때, Parameter값으로 주면 다목적으로 사용할 수 있는 PWM의 duty ratio control module 생성할 수 있다.
- parameter 생성 시, 모든 parameter는 Parameter 위치에 선언 및 위치해야 한다.
- 범용성을 위해서 duty 변수와 각각의 count 크기를 32bit로 선언하였다.
< Source, Top Module >
// Top Module
module Multi_PWM_Top_Module (
input clk, reset_p,
output led_red,
output led_green,
output led_blue);
// Making system clock counter.
reg [31:0] cnt_sysclk;
always @(posedge clk or posedge reset_p) begin
if(reset_p) cnt_sysclk = 0;
else cnt_sysclk = cnt_sysclk + 1;
end
// Declare Instance
Multi_PWM_Duty_Ratio #(
.duty_step(93)
) pwm_red (
.clk(clk),
.reset_p(reset_p),
.duty(cnt_sysclk[28:23]),
.pwm(led_red)
);
Multi_PWM_Duty_Ratio #(
.duty_step(97)
) pwm_blue (
.clk(clk),
.reset_p(reset_p),
.duty(cnt_sysclk[26:21]),
.pwm(led_blue)
);
Multi_PWM_Duty_Ratio #(
.duty_step(101)
) pwm_green (
.clk(clk),
.reset_p(reset_p),
.duty(cnt_sysclk[27:22]),
.pwm(led_green)
);
endmodule
- Red, Blue, Green LED는 각각 93단계, 97단계, 101단계로 밝기 단계를 나누었다.
- Red LED는 5.368초를 주기로 밝았다 꺼졌다를 반복한다.
- Blue LED는 1.342초를 주기로 밝았다 꺼졌다를 반복한다.
- Green LED는 2.684초를 주기로 밝았다 꺼졌다를 반복한다.
- 이처럼 서로 다른 주기로 밝았다 꺼졌다를 하기 때문에 다양한 색상이 LED로 출력되는 것을 확인할 수 있다.
< 구동 영상 >
4. 어떻게 Duty ratio를 컨트롤함으로서 LED의 밝기를 조절할 수 있는가?
- Duty ratio = 50, Duty step = 100, Period = 1sec인 PWM을 LED를 인가하는 상황을 가정하자.
- 위와 같은 PWM을 LED에 인가하면 0.5sec동안 0V, 0.5sec동안 3.3V를 인가한다.
- 0.5sec동안 0V를 인가하는 동안에는 다이오드의 문턱 전압을 넘지 못하기 때문에 다이오드가 켜지지 않지만, 0.5sec 동안 3.3V를 인가하는 동안에는 다이오드의 문턱 전압을 넘어 다이오드가 켜진다.
- 따라서 실제로는 0V, 3.3V 전압을 0.5sec 동안 주는 것이지만, 다이오드 입장에서는 평균 전압, 1.65V을 인가해주는 것과 동일하게 작용하기 때문에 최대 밝기의 50%만 나오게 된다.
- 이 처럼 PWM의 duty ratio를 조절 함으로서 다이오드에 전해지는 평균 전압을 조절할 수 있고, 이를 통해 다이오드, LED의 밝기가 조절되어 나타난다.
- 주의) 실제로는 0V, 3.3V 전압이 작용하기 때문에 이를 잊지 말것.
'RTL Design > Verilog RTL 설계' 카테고리의 다른 글
Verilog RTL 설계(7월 19일 - 2, Cooking Timer - 2) (0) | 2024.08.08 |
---|---|
Verilog RTL 설계(7월 19일 - 1, Cooking Timer - 1) (0) | 2024.08.08 |
Verilog RTL 설계(7월 31일 - 4, PWM - 4) (0) | 2024.08.01 |
Verilog RTL 설계(7월 31일 - 3, PWM - 3) (0) | 2024.08.01 |
Verilog RTL 설계(7월 31일 - 2, PWM - 2) (0) | 2024.08.01 |