2

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
Unn
  • 4,775
  • 18
  • 30
yo3hcv
  • 1,531
  • 2
  • 17
  • 27
  • `PWM_H` and `PWM_L` are both driven by 1-bit FSMs. If you were to separate out the `always` blocks, you'd see this. However, the FSM for `PWM_H` uses an equality operator (`==`) whilst the FSM for `PWM_L` uses a comparison operator (`<`). Equality operators will synthesise to less logic than a comparison operator. So, I'd fix that for starters. I doubt that will get you the whole way, though. You also need to look at what kind of adder your synthesiser is using. – Matthew Taylor Dec 04 '20 at 08:20

1 Answers1

1

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
Rich Maes
  • 1,204
  • 1
  • 12
  • 29
  • I don't think it is the case that "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." The second assignment will simply overwrite the first. – Matthew Taylor Dec 04 '20 at 08:15
  • If the statement was using blocking assignments, that might be true, but in the case the <= is non-blocking which allows parallel execution. Writing two lines, foo <= variable_a ? ~foo : foo; foo <= variable_b ? 0 : 1; would not guarantee which one executes first. Changing the <= to = in the code above would resolve that issue as you describe. UPDATE: Here is an article on the topic https://electronics.stackexchange.com/questions/91688/difference-between-blocking-and-nonblocking-assignment-verilog – Rich Maes Dec 04 '20 at 17:47
  • I think the answer by "The Photon" you linked to is nonsense. (I think I will join "electronics" to say so.) Non-blocking assignments are not executed in parallel. It might seem like it, but they are not. See [this answer here](https://stackoverflow.com/questions/65145617/concurrent-and-sequential-statements-in-vhdl). It's about VHDL, but a VHDL _signal assignment operator_ (`<=`) behaves in a similar way to a non-blocking assignment in this respect. – Matthew Taylor Dec 07 '20 at 12:01