2022年2月16日 星期三

Verilog PWM


 本程式進行FPGA的PWM設計。利用FPGA執行PWM,比用單晶片更為精準。通常在單晶片上,係以8 bits或10 bits進行PWM,也就是可執行0~255的1/255或0~1023的1/1023,通常只能以近似的數字換算成百分比。但在FPGA上,可設計0~100的1/100間隔的PWM,以達到更精確的控制。


為讓應用範圍更廣,本設計採用參數式設計,利用parameter讓使用者可自訂分割值,最大可切割至1023等份,也就是切割成1000等份時,精密度為0.1%。若未輸入parameter,預設為100等份,也就是1%。

程式相當簡單,一個從0計數到n-1的計數器,也就是可分為n等份,輸出則為0~n個高準位,共n+1種狀態。

PWM.v

  1. // The input clock frequency is 100 times higher than the cycle frequency.

  2. module PWM(
  3. input clk,
  4. input rst,
  5. input [9:0] iduty,
  6. output reg opwm
  7. );

  8. parameter part  = 100;
  9. reg [9:0] count;

  10. always @ (posedge clk or negedge rst)
  11. begin
  12. if (!rst)
  13. begin
  14. count <= 0;
  15. end
  16. else if (count == part-1)
  17. begin
  18. count <= 0;
  19. end
  20. else
  21. count <= count + 1;
  22. end 

  23. always @ (posedge clk or negedge rst)
  24. begin
  25. if (!rst)
  26. begin
  27. opwm <= 1'b0;
  28. end
  29. else if (count < iduty)
  30. begin
  31. opwm <= 1'b1;
  32. end
  33. else
  34. begin
  35. opwm <= 1'b0;
  36. end
  37. end

  38. endmodule
testbench如下,PWM_tb.v

  1. `timescale 1ns/1ns

  2. module PWM_tb;

  3. reg clk;
  4. reg rst;
  5. reg [9:0] iduty;
  6. wire opwm;

  7. reg [9:0] delta_duty;

  8. PWM u(
  9. .clk(clk),
  10. .rst(rst),
  11. .iduty(iduty),
  12. .opwm(opwm)
  13. );
  14. defparam u.part = 10;

  15. initial 
  16. begin
  17. #0 
  18. clk = 0;
  19. rst = 0;
  20. iduty = 0;
  21. delta_duty = 1;
  22. #100 rst = 1;

  23. #200000 delta_duty = -1;

  24. #200000 delta_duty = 1;

  25. end 

  26. always 
  27. #10 clk = ~clk;

  28. always 
  29. #2000 iduty = iduty+delta_duty;

  30. endmodule 

把iduty和delta_duty改為Decimal。


當iduty輸入為0時,PWM輸出為0%,當iduty在10以上的時候,為100%的輸出。因為目前僅分為10等份。



刪除testbench檔案PWM_tb.v中第18行的defparam u.part = 10;,會成為預設分割的100等份。把輸入iduty改為類比形式Analog顯示。



若可直接輸入cycle和duty的寫法可如下:


  1. module PWM(
  2. rst,
  3. clk,
  4. duty,
  5. cycle,
  6. oPWM
  7. );

  8. input clk,rst;
  9. input [11:0] duty, cycle;
  10. output reg oPWM;

  11. reg [11:0] count;

  12. always @ (posedge clk or negedge rst)
  13. begin
  14. if (!rst)
  15. begin
  16. count <= 0;
  17. end
  18. else if (count == cycle-1)
  19. begin
  20. count <= 0;
  21. end
  22. else
  23. count <= count + 1;
  24. end 

  25. always @ (posedge clk or negedge rst)
  26. begin
  27. if (!rst)
  28. begin
  29. oPWM <= 0;
  30. end
  31. else if (count < duty)
  32. begin
  33. oPWM <= 1;
  34. end
  35. else
  36. oPWM <= 0;
  37. end 
  38. endmodule