PWM使用参考


1. 概述

1.1. 概述

PWM(Pulse Width Modulation)模块通过改变占空比来改变输出的电流、电压进而控制电机转速、液晶屏调光等。

1.2. 说明

目前PWM支持的period范围:

pwm driver的period精度支持2档调节,普通模式精度范围为44Hz – 6MHz;设置更高的精度时在menuconfig中打开CONFIG_PWM_NEW选项,此时精度范围为0.000698Hz – 6MHz。

1.3. 频率和占空比

  • 频率(period)

    每秒钟信号从高电平到低电平再回到高电平的次数。

  • 占空比(duty)

    高电平持续时间和低电平持续时间之间的比例。

2. 驱动配置

2.1. DTSI配置

PWM在dtsi中的节点如下所示:

PWM在dtsi中的节点如下所示:

1.  pwm {  
2.      compatible = "sstar,infinity-pwm";  
3.      reg = <0x0 0x1F203200 0x0 0x400>;  
4.      npwm = <11>;  
5.      clocks = <&CLK_pwm>;  
6.      interrputs = <GIC_SPI INT_IRQ_PWM IRQ_TYPE_EDGE_RISING>;  
7.      status = "ok";  
8.  };

2.2. 节点属性

PWM驱动支持的属性如下:

属性 描述 备注
compatible 用于匹配驱动进行驱动注册,需与代码中一致 禁止修改
reg 用于指定PWM寄存器bank的地址 不需要修改
interrupts 用于指定使用的硬件中断号及属性 不需要更改
clocks 用于指定使用的时钟源 不需要更改
npwm 用于指定PWM Channel的数量 不需要修改
status 用于选择是否使能PWM驱动 可根据需要修改

2.3. KERNEL CONFIG

编译Kernel时:make menuconfig

Device Drivers-->
    [*] SStar SoC platform drivers-->
        [*] Sstar PWM
            [*] Support NEW PWM configuration

Support NEW PWM configuration:

开启该选项可以提高PWM设置的精度和范围,可以根据情况选择是否打开。不打开时PWM可以设置的范围为44Hz – 6MHz,打开时可以设置的范围为0.000698Hz – 6MHz。

2.4. PADMUX配置注意事项

在padmux.dtsi中配置mode格式如下图的,"<>"中第一个值为PAD值,第二个值为要设置的mode,第三个值为PAD在该mode下对应的功能。

如下配置1完成后,请检查2和3,是否有其他的PAD也设置成了需要设置的mode,重复设置会引起冲突导致配置padmux失效,如果冲突的mode不需要使用则可以将其注释掉,如果需要使用,请重新选择mode。

1.  <PAD_PWM0       PINMUX_FOR_PWM0_MODE_1       MDRV_PUSE_PWM0>,  
2.  <PAD_PWM1       PINMUX_FOR_PWM1_MODE_1       MDRV_PUSE_PWM1>,     <==1  
3.    
4.  <PAD_FUART_RX   PINMUX_FOR_PWM0_MODE_3       MDRV_PUSE_PWM0>,  
5.  <PAD_FUART_TX   PINMUX_FOR_PWM1_MODE_3       MDRV_PUSE_PWM0>,      <==2  
6.    
7.  <PAD_PWM0       PINMUX_FOR_FUART_2W_MODE_4   MDRV_PUSE_FUART_RX>,  
8.  <PAD_PWM1       PINMUX_FOR_FUART_2W_MODE_4   MDRV_PUSE_FUART_TX>,  <==3

2.5. PADMUX所有描述

1.  //PWM0  
2.  <PAD_PWM0        PINMUX_FOR_PWM0_MODE_1    MDRV_PUSE_PWM0>  
3.  <PAD_GPIO14      PINMUX_FOR_PWM0_MODE_2    MDRV_PUSE_PWM0>  
4.  <PAD_FUART_RX    PINMUX_FOR_PWM0_MODE_3    MDRV_PUSE_PWM0>  
5.  <PAD_GPIO0       PINMUX_FOR_PWM0_MODE_4    MDRV_PUSE_PWM0>  
6.  //PWM1  
7.  <PAD_PWM1        PINMUX_FOR_PWM1_MODE_1    MDRV_PUSE_PWM1>  
8.  <PAD_GPIO15      PINMUX_FOR_PWM1_MODE_2    MDRV_PUSE_PWM1>  
9.  <PAD_FUART_RX    PINMUX_FOR_PWM1_MODE_3    MDRV_PUSE_PWM1>  
10. <PAD_GPIO1       PINMUX_FOR_PWM1_MODE_4    MDRV_PUSE_PWM1>  
11. //PWM2  
12. <PAD_I2C0_SCL    PINMUX_FOR_PWM2_MODE_1    MDRV_PUSE_PWM2>  
13. <PAD_FUART_CTS   PINMUX_FOR_PWM2_MODE_2    MDRV_PUSE_PWM2>  
14. <PAD_GPIO7       PINMUX_FOR_PWM2_MODE_3    MDRV_PUSE_PWM2>  
15. <PAD_GPIO2       PINMUX_FOR_PWM2_MODE_4    MDRV_PUSE_PWM2>  
16. //PWM3  
17. <PAD_I2C0_SDA    PINMUX_FOR_PWM3_MODE_1    MDRV_PUSE_PWM3>  
18. <PAD_FUART_RTS   PINMUX_FOR_PWM3_MODE_2    MDRV_PUSE_PWM3>  
19. <PAD_GPIO8       PINMUX_FOR_PWM3_MODE_3    MDRV_PUSE_PWM3>  
20. <PAD_GPIO3       PINMUX_FOR_PWM3_MODE_4    MDRV_PUSE_PWM3>  
21. //PWM4  
22. <PAD_PM_GPIO0    PINMUX_FOR_PWM4_MODE_1    MDRV_PUSE_PWM4>  
23. <PAD_SPI0_CZ     PINMUX_FOR_PWM4_MODE_2    MDRV_PUSE_PWM4>  
24. <PAD_GPIO4       PINMUX_FOR_PWM4_MODE_3    MDRV_PUSE_PWM4>  
25. //PWM5  
26. <PAD_PM_GPIO1    PINMUX_FOR_PWM5_MODE_1    MDRV_PUSE_PWM5>  
27. <PAD_SPI0_CK     PINMUX_FOR_PWM5_MODE_2    MDRV_PUSE_PWM5>  
28. <PAD_GPIO5       PINMUX_FOR_PWM5_MODE_3    MDRV_PUSE_PWM5>  
29. //PWM6  
30. <PAD_PM_GPIO2    PINMUX_FOR_PWM6_MODE_1    MDRV_PUSE_PWM6>  
31. <PAD_SPI0_DI     PINMUX_FOR_PWM6_MODE_2    MDRV_PUSE_PWM6>  
32. <PAD_GPIO6       PINMUX_FOR_PWM6_MODE_3    MDRV_PUSE_PWM6>  
33. //PWM7  
34. <PAD_PM_GPIO3    PINMUX_FOR_PWM7_MODE_1    MDRV_PUSE_PWM7>  
35. <PAD_SPI0_DO     PINMUX_FOR_PWM7_MODE_2    MDRV_PUSE_PWM7>  
36. <PAD_GPIO7       PINMUX_FOR_PWM7_MODE_3    MDRV_PUSE_PWM7>  
37. //PWM8  
38. <PAD_GPIO0       PINMUX_FOR_PWM8_MODE_1    MDRV_PUSE_PWM8>  
39. <PAD_GPIO2       PINMUX_FOR_PWM8_MODE_2    MDRV_PUSE_PWM8>  
40. <PAD_SR_IO14     PINMUX_FOR_PWM8_MODE_3    MDRV_PUSE_PWM8>  
41. //PWM9  
42. <PAD_GPIO1       PINMUX_FOR_PWM9_MODE_1    MDRV_PUSE_PWM9>  
43. <PAD_PWM0        PINMUX_FOR_PWM9_MODE_2    MDRV_PUSE_PWM9>  
44. <PAD_GPIO14      PINMUX_FOR_PWM9_MODE_3    MDRV_PUSE_PWM9>  
45. <PAD_SR_IO15     PINMUX_FOR_PWM9_MODE_4    MDRV_PUSE_PWM9>  
46. //PWM10  
47. <PAD_GPIO3       PINMUX_FOR_PWM10_MODE_1    MDRV_PUSE_PWM10>  
48. <PAD_PWM1        PINMUX_FOR_PWM10_MODE_2    MDRV_PUSE_PWM10>  
49. <PAD_GPIO15      PINMUX_FOR_PWM10_MODE_3    MDRV_PUSE_PWM10>  
50. <PAD_SR_IO16     PINMUX_FOR_PWM10_MODE_4    MDRV_PUSE_PWM10>

3. 配置PWM输出(普通模式)

3.1. 普通精度设置

menuconfig中不开启PWM_NEW的情况下可以配置pwm周期与占空比的精度相对较低,建议开启PWM_NEW。这种模式下配置PWM的period的单位为Hz,duty的单位为百分比。

配置方法如下:

1.  # 跳转到PWM控制目录
2.  cd sys/class/pwm/pwmchip0/
3.  
4.  # 创建PWM0节点
5.  echo 0 > export
6.  
7.  # 进入PWM0控制目录
8.  cd pwm0
9.  
10. # 设置周期为10000Hz
11. echo 10000 > period
12. 
13. # 设置占空比为50%
14. echo 50 > duty_cycle
15. 
16. # 设置极性为反向(不设置反向为echo normal > polarity)
17. echo inversed > polarity
18. 
19. # 使能PWM0
20. echo 1 > enable
21.

3.2. 高精度设置

在menuconfig中开启PWM_NEW选项时,PWM的period与duty_sycle配置的范围更大,精度也更高。配置方法与普通精度也不同,这种模式下配置PWM的period和duty_cycle使用纳秒为单位,所以要先计算周期和占空比的值。

要设置PWM0频率为10KHZ占空比为½,则:

period = 109 ÷ 10000 = 100000

duty cycle = ½ × 100000 = 50000

要设置PWM1频率为30HZ占空比为½,则:

period = 109 ÷ 30 = 33333333

duty cycle = ½ × 33333333 = 16666666

配置PWM:

1.  # 跳转到PWM控制路径
2.  cd sys/class/pwm/pwmchip0/
3.  
4.  # 创建PWM0节点 使用PAD_GPIO0
5.  echo 0 >export
6.  
7.  # 进入PWM0控制路径
8.  cd pwm0
9.  
10. # 配置周期
11. echo 100000 >period
12. 
13. # 设置占空比
14. echo 50000 >duty_cycle
15. 
16. # 使能PWM0
17. echo 1 >enable

4. GROUP相关概念

4.1. Group功能(Sync mode)

Group功能可以同时对多个PWM进行控制(一个group至多4个),要使用PWM的Group功能需要将PWM加入到Group中(每个PWM只能加入到固定的Group中:PWM0 - 3 >Group 0 ,PWM4 – 7>Group 1,PWM8 – 10==>Group 2),可通过以下命令将一个PWM加入到Group中:

echo PWM_ID enable > group_mode

之后对加入到Group的各个PWM进行配置再Enable,这时driver会将之前的配置一起下到寄存器中再Enable Group中的PWM,Group中的PWM会同时开始出配置的波形。

Group功能的典型应用是Sync mode(也叫马达模式),这个模式要求在同一个Group中的PWM的Period都相同,这样波形的周期就是同时开始同时结束,可以用来实现电机同步等功能。

4.2. period、begin、end

period是PWM的周期,开关PWM_NEW配置period的值单位不同,详见配置PWM输出(GROUP模式),配置方法如下:

echo PWM_ID period > group_period

begin设置的是PWM 的shift值,这个值可以将PWM的相位相对于其他的PWM有一个偏移,end设置的是PWM的duty值,group中的duty与普通模式下不同,group中PWM的占空比需要将duty减去shift即end – begin

Group中配置begin与shift的方法如下:

1.  echo PWM_ID end > group_end
2.  echo PWM_ID begin > group_begin

4.3. Hold功能

Group的Hold功能可以让加入到Group中的PWM在完成Hold命令前的周期波形之后停止。

Hold命令如下:

echo GROUP_ID > group_hold

Group的Hold功能分为2种:Hold_mode_0 和 Hold_mode_1。

两者的区别为:Hold_mode_0在PWM停止以后会维持结束时电平;Hold_mode_1会PWM停止之后将电平全部拉低。

改变Hold的mode命令如下:

echo HOLD_mode > group_hold_mode1

在驱动中将Hold_mode_0作为Group出波形中更改PWM设置的方法,在Enable group之后配置需要更改的配置,再使用Hold_mode_0会将新配置导入到寄存器并出现新波形,这样不会影响到Group之间的PWM同步,具体操作方法见:配置PWM输出(GROUP模式)

4.4. Round功能

Round功能可以让Group中的PWM出完指定的周期数之后停止并触发Round中断。Round命令如下:

echo GROUP_ID round > group_round

4.5. Stop功能

Stop功能可以让当前Group中的PWM立即停止(不会等当前周期完成),PWM会维持结束时的电平。Stop命令如下:

echo GROUP_ID enable > group_stop

5. 配置PWM输出(GROUP模式)

Group模式为了保持PWM之间的同步会将用户的配置先暂存,只有在Enable以及Hold中断触发时将用户的配置写到寄存器中才生效。

使用中需要Group在enable之后,更改PWM的period、begin、end的值时,先进行配置,再下Hold_mode_0使能命令来触发中断,将新的配置下到寄存器中来使其生效。

5.1. 普通精度设置

menuconfig中不开启PWM_NEW的情况下,配置pwm周期与占空比的精度相对较低,建议开启PWM_NEW。这种模式下配置PWM的period的单位为Hz,duty的单位为千分比。配置方法如下(注意:在同一个GROUP中的PWM的period要相同):

1.  # 进入马达模式控制目录
2.  cd sys/devices/virtual/mstar/motor/
3.  
4.  # 将PWM1加入到GROUP模式中
5.  echo 1 1 > group_mode
6.  
7.  # 设置PWM0的period为10000HZ
8.  echo 0 10000 > group_period
9.  
10. # 设置PWM0的duty为500‰
11. echo 0 500 > group_end
12. 
13. # 设置PWM1的period为10000HZ
14. echo 1 10000 > group_period
15. 
16. # 设置PWM1的shift为250‰
17. echo 1 250 > group_begin
18. 
19. # 设置PWM1的duty为750‰
20. echo 1 750 > group_end
21. 
22. # 启动Group0
23. echo 0 1 > group_enable
24. 
25. # 更改PWM0的duty为750‰
26. echo 0 750 > group_end
27. 
28. # 触发Group0 Hold中断使Enable之后的配置生效
29. echo 0 1 > group_hold
30. 
31. # 配置Group0输出1000个周期的
32. echo 0 1000 > group_round

5.2. 高精度设置

menuconfig中开启PWM_NEW时,PWM的period与duty_sycle配置的范围更大,精度也更高。配置方法与普通精度也不同,这种模式下配置PWM的period和duty_cycle使用纳秒为单位,所以要先计算周期和占空比的值。

要设置PWM0频率为10KHZ占空比为½,则:

period = 109 ÷10000 = 100000

duty cycle = ½ × 100000 = 50000

要设置PWM1频率为30HZ占空比为½,则:

period = 109 ÷30 = 33333333

duty cycle = ½ × 33333333 = 16666666

配置PWM:

1.  # 进入马达模式控制目录
2.  cd sys/devices/virtual/mstar/motor/
3.  
4.  # 将PWM1加入到GROUP模式中
5.  echo 1 1 > group_mode
6.  
7.  # 设置PWM0的period为10000HZ
8.  echo 0 10000 > group_period
9.  
10. # 设置PWM0的duty为500‰
11. echo 0 500 > group_end
12. 
13. # 设置PWM1的period为10000HZ
14. echo 1 10000 > group_period
15. 
16. # 设置PWM1的shift为250‰
17. echo 1 250 > group_begin
18. 
19. # 设置PWM1的duty为750‰
20. echo 1 750 > group_end
21. 
22. # 启动Group0
23. echo 0 1 > group_enable
24. 
25. # 更改PWM0的duty为750‰
26. echo 0 750 > group_end
27. 
28. # 触发Group0 Hold中断使Enable之后的配置生效
29. echo 0 1 > group_hold
30. 
31. # 配置Group0输出1000个周期的
32. echo 0 1000 > group_round