Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
15 years ago

Synchronization problem in PWM generation

I am using the DE2 board to generate a 20 kHz PWM signal. The duty ratio is constant 20%. The device is implemented by verilog. My method is to use DE2 board to generate a 20 kHz * 1000 = 20 MHz clock signal. The 20 kHz synchronization signal is an external signal from a master DSP board, 50% duty ratio square wave. We have to use external synchronization signal.

I set a variable a = 500. During the time when the 20 kHz synchronization signal is in its positive half cycle, let a = a-1 for each clock cycle (20 MHz). During the negative half cycle, a=a+1 for each clock cycle. Therefore, I have a triangle carrier signal and by comparing a with 100, I get the PWM output of 20 % duty ratio. I set the limits for a: the upper limit is 500 and the lower limit is 0.

In normal case, during the 1st 40% of the 20kHz synchronization cycle, the PWM output is 0. The next 20% is 1 and the final 40% is 0. However, every tens of normal cycles, we can observe an abnormal cycle. The 1st half cycle PWM is 0 or 1, the next 10% is 1 and the last 40% is 0. Therefore, the PWM output is wrong during the half positive cycle of the synchronization signal and is correct in the negative half cycle.

I can not figure out the reason for this problem. A possible reason is that the frequency of the 20MHz clk signal is not exactly 1000 times of that of 20 kHz signal. But how does this cause the abnormal cycle? How to solve the problem?

Thank you very much!

6 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I paste my code here. It may be helpful.

    // PWM Generation.

    module PWM_Unit ( duty_ratio,pwm_trig, clk, pwm_output, output_b);

    input [15:0] duty_ratio;

    input pwm_trig, clk;

    output pwm_output, output_b;

    integer a=0;

    integer b=-1, ref_level=400;

    integer pwm_level;

    integer half_cycle=0;

    reg pwm_output;//output of pwm

    reg output_b;//for debug, not related to pwm generation.

    parameter steps=500;

    always

    begin

    pwm_output<=pwm_level;

    if (b>0)

    output_b<=1;

    else

    output_b<=0;

    end

    //initialize the pwm unit at the beginning of each switching cycle

    always @(posedge pwm_trig)

    begin

    ref_level=100; // read the duty ratio. this is constant for test and will be change in future.

    end

    //increase variable a at each clk rising edge

    always @(posedge clk)

    begin

    if (a<ref_level)

    pwm_level=1;

    else

    pwm_level=0;

    if (pwm_trig==1) //control the slope of the triangle wave.

    b=-1;

    if (pwm_trig==1)

    b=1;

    a=a+b;

    if (a<1)

    begin

    a=0;

    end

    if (a>(steps-1))

    begin

    a=steps;

    end

    end

    endmodule
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I guess, pwm_trig is unrelated to clk, at least not guaranteed to meet the required setup and hold time? Then it's not correct to use it, as you do in your logic, it has to be synchronized to clk by two flip-flops.

    I assume, this is not the real code.

    if (pwm_trig==1) //control the slope of the triangle wave.
    b=-1;
    if (pwm_trig==1)
    b=1
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Oh, I am sorry. The code is wrong. This is correct:

    if (pwm_trig==1) //control the slope of the triangle wave.

    b=-1;

    if (pwm_trig==0)//triangle wave is rising when synchronization signal is 0

    b=1;

    The pwm_trig is the 20kHz synchronization signal. It comes from a master dsp controller. What is the meaning of “the required setup and hold time”? Due to the structure of our system, I have to use the external synchronization signal (20kHz) and internal clk signal (20 MHz). Is there any solution?

    Thank you!
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You should use a synchronization chain as described in the Quartus Software Handbook and logic design text books.

    always @(posedge clk)
    begin
      pwm_trig_s0 <= pwm_trig;
      pwm_trig_s1 <= pwm_trig_s0;
      if (pwm_trig_s1==1) //control the slope of the triangle wave.
        b=-1;
      else
        b=1;
    //....
    end
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you very much!

    It works, although I do not understand why....