verilog, improve speed of PWM

Viewed 127

I'm trying to design a PWM + dead band that works at 250MHz input clock. (I need something around 250KHz PWM freq. for a custom buck regulator)

This is what I implemented so far using IceCube2 from Lattice, using iCE40LP1K device. Maximum freq. obtained (simulated) is 142 MHz worst case and 260 Mhz best case (-40 deg).

I wonder if this is the right approach for PWM generator that includes a dead zone for complementary outputs or in other words, if this can be improved more.

module top(
  input clk_16,
  input [9:0] data_in,
  output reg PWM_H,
  output reg PWM_L
);

  reg [9:0] compare;
  reg [9:0] counter = 0;

  always @(posedge PLLOUTCORE)
  begin
   compare <= data_in;
  end

  always@ (posedge PLLOUTCORE )
  begin

    if ( counter < compare )
        PWM_H <= 1;
    else // >= compare
        PWM_H <= 0;

    if ( counter == compare + 16 )
        PWM_L <= 1;
        
    if ( counter == (1024-16) )
        PWM_L <= 0;    
        
    counter <= counter+1;
  end
1 Answers

This is a bit of open ended question and slightly opinion based, however, since you are asking about the PWM with deadband I'll answer with an example, and point out something I see in your code which IMHO is bad practice.

Your assignment of PWM_H, is a pretty good example, you have an IF and an ELSE IF setting PWM_H. How you wrote PWM_L is not as good and that style could result in a synthesis error. Having two independent IF's assigning the same variable could have a multiple driver issue if both IF's happen to be true at the same time. You may think/know that is not the case, but don't do it. If the synthesize detects this, it will hopefully throw an error. Instead re-write as IF and an ELSE IF like you did for PWM_H.

Next thing, I get that reg counter=0 will reset counter for simulation, but obviously not for synthesis. That will work in your case, because you are using the full count, and it will actually be a very fast synthesizing counter.

I wrote an example below and used parameters. That is just a personal choice, but it does make things kind of cool if you want to adjust later. I have some extra code in there because when I simulated it, I found that bad stuff happened at the extremes of the offset setting.

Much like your code, my PWM_L is a little more complex than PWM_H, but notice I have it in one statement rather than two, thus no chance of multi-driver.

module pwm_db
    (input clk,
     input reset,
     input [9:0] offset,
     output pwm_l,
     output pwm_h
     );

    reg [9:0] counter = 0;
    reg [9:0] proc_offset;  
    reg pwm_ld;
    reg pwm_hd;

    parameter COUNTER_MAX = 1024-1;
    parameter DEADBAND_WIDTH = 16;
    parameter DB_X2 = DEADBAND_WIDTH * 2;
    parameter COUNTER_DB = COUNTER_MAX - DEADBAND_WIDTH;
    
    // Limit the offset internally to keep the deadband from being over written
    // Burning some registers for this to increase final synthesis speed.
    always @ (posedge clk)
    begin
    proc_offset <= (offset >= DB_X2) && (offset <= COUNTER_MAX - DB_X2) ? offset :
                      offset < DB_X2                                      ? DB_X2  : COUNTER_MAX - DB_X2; 
    end


    always @ (posedge clk)
        begin
            counter <= counter + 10'h001;
            pwm_hd <= counter <  proc_offset - DEADBAND_WIDTH;  // on initially and turn off a DB width prior to offset
            pwm_ld <= counter > proc_offset && counter < COUNTER_DB; // on at offset and off DW width prior to max count;
        end
    assign pwm_h = pwm_hd;
    assign pwm_l = pwm_ld;
    
endmodule
Related