거북이처럼 천천히

Verilog RTL 설계(7월 31일 - 2, PWM - 2) 본문

RTL Design/Verilog RTL 설계

Verilog RTL 설계(7월 31일 - 2, PWM - 2)

유로 청년 2024. 8. 1. 10:15

1. 다이오드가 연속적으로 켜져 있는 상태로 보이기 위해서는 10kHz Pulse wave를 줘야 한다.

  • 다이오드가 사람 눈으로 보았을 때, 연속적으로 켜져 있는 상태로 보여주기 위해서는 10kHz 주파수를 갖는 Pulse wave를 인가하는 것이 좋다.

 

 

 

2. 그럼, 어떻게 PWM을 만들 것인가? 

  • Prescaling을 통해 원하는 Duty ratio를 갖는 Pulse wave를 만들 수 있다.
  • 이를 예시와 함께 알아 보도록 하겠다.
    - 100usec 주기를 갖는 PWM을 Prescaling을 통해 만들어 보겠다.
    - Q) 왜 100usec 주기를 갖는 PWM을 만드는가?
    - A) 10000Hz 주파수를 갖는 Pulse wave의 주기는 100usec 주기를 갖기 때문에 10000Hz 주파수를 만들기
          위해서 100usec 주기를 갖는 PWM을 만들고자 한다.

 

 

 

3. Period가 100usec인 PWM 만들기

  • 10ns인 Clcok Pulse를 100분주, 100분주하여 주기가 100usec인 PWM을 만들 것이다.
  • Q) 왜 어째서 100분주를 두 번하여 100usec PWM을 만드는 것인가? 한 번에 10000분주해도 되지 않는가?
  • A) 원하는 Duty ratio를 만들기 위해서, Duty ratio를 컨트롤하기 위해서 이다.
         이는 코드를 설명한 후, 천천히 다시 설명하도록 하겠다. 

 

 

3.1. 10ns인 CP를 100분주화 + 100분주화하여 100usec인 PWM을 만들기.

  • LED의 밝기 단계를 100단계로 나누어 컨트롤 하기 위해 100분주하였다.
  • 최종적으로 주파수가 10kHz인 Pulse wave를 만들기 위해서 또 다시 100분주 하였다.

 

< Source, Period = 100usec인 PWM의 duty ratio를 100단계로 나누어 컨트롤하는 모듈 >

// PWM 100 Step 
module Duty_ratio_100(
    input clk, reset_p,
    input [6:0] duty,
    output pwm );  
    
    // 10kHz 주파수를 갖는 Pulse Wave를 만들기 위해서 
    // Prescaling 하는 과정 == 100분주 Prescaler
    reg[6:0] cnt_freqX100;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) cnt_freqX100 = 0;
        else if(cnt_freqX100 >= 99) cnt_freqX100 = 0;
        else cnt_freqX100 = cnt_freqX100 + 1;
    end
    
    wire pulse_freqX100;
    assign pulse_freqX100 = (cnt_freqX100 < 50)? 0 : 1;
    
    wire pulse_freqX100_n_edge;
    edge_detector edge_detector_0(.clk(clk), .reset_p(reset_p), .cp(pulse_freqX100), .n_edge(pulse_freqX100_n_edge));
    
    
    // PWM의 Dity ratio를 단계별로 나누어 컨트롤 하기 위해서
    // 이번에는 led를 100단계로 밝기를 컨트롤하기 위해 
    // 100분주하는 것이다.
    reg[6:0] cnt_pwm;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) cnt_pwm = 0;
        else if(pulse_freqX100_n_edge) begin
            if(cnt_pwm >= 99) cnt_pwm = 0;
            else cnt_pwm = cnt_pwm + 1;
        end
    end
    
    // duty 만큼 활성화 하기 위해서는 
    // 작으면 1, 크면 0으로 설정
    assign pwm = (cnt_pwm < duty)? 1 : 0;
    
endmodule

// Edge detector
module edge_detector (
    input clk, reset_p,
    input cp,
    output n_edge, p_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
  • LED의 밝기를 100단계로 나누어 컨트롤 하기 위해 100분주화 한다.
  • 10ns Clock Pulse를 100분주화 하면 1usec 주기를 갖는 Pulse Wave를 갖게 되며, 이를 최종적으로 100usec pulse wave로 만들기 위해서 추가적으로 100분주화 하여 1usec pulse를 100usec pulse 로 만든다.

 

 

< Source, PWM의 duty ratio를 100단계로 나누어 LED 컨트롤하기 위한 Top module >

// PWM LED Control top module
module pwm_led_top_module (
    input clk, reset_p,
    input [6:0] duty,
    output pwm);
    
    Duty_ratio_100 pwm_duty_ratio_100(.clk(clk), .reset_p(reset_p), .duty(duty), .pwm(pwm));  
    
endmodule

 

 

 

< Simulation, Duty ratio = 50 >

 

 

 

< Simulation, Duty ratio = 80 >

 

 

 

< Simulation, Duty ratio = 10 >