Difference between revisions of "PWM overview"

[quality revision] [quality revision]
m
m
 

Template:ArticleMainWriter Template:ReviewersList Template:ArticleApprovedVersion SUMMARY
This article gives information about the Linux® PWM framework.
It explains how to activate the PWM interface and, based on examples, how to use it.

1 Framework purpose[edit]

PWM (Pulse Width Modulation) framework offers a unified interface for the users to:

  • control PWM output(s) such as period, duty cycle and polarity.
  • capture a PWM signal and report its period and duty cycle (e.g. input).

The interface can be used from:

  • user space (sysfs)
  • kernel space (API)

PWMs can be used in various use cases, as mentioned in How to use the framework to control LEDs, beepers, vibrators or fans...

2 System overview[edit]

PWM sysfs interface PWM kernel interface STM32 TIM Linux driver STM32 LPTIM Linux driver STM32 TIM internal peripheral STM32 LPTIM internal peripheral
PWM Implementation architecture Template:WarningImageMapOverlay

2.1 Component description[edit]

  • PWM user (User space)

The user can use PWM sysfs interface, from a user terminal or a custom application, to control PWM device(s) from user space.

  • PWM user (Kernel space)

User drivers can use PWM API to control PWM external device(s) from kernel space (such as back-light, vibrator, LED or fan drivers).

  • PWM framework (Kernel space)

The PWM core provides sysfs interface and PWM API. They can be used to implement PWM user and PWM controller drivers.

  • PWM drivers (Kernel space)

Provider drivers such as STM32 TIM Linux driver and STM32 LPTIM Linux driver that expose PWM controller(s) to the core.

  • PWM hardware

PWM controller(s) such as TIM internal peripheral[1] and LPTIM internal peripheral[2] used to drive external PWM controlled devices.

2.2 API description[edit]

Documentation on PWM interface can be found under kernel Documentation/driver-api/pwm.txtrst[3]

2.2.1 Kernel PWM API[edit]

The main useful user API are the following:

  • devm_pwm_get() or pwm_get() / pwm_put(): this API is used to look up, request, then free a PWM device.
  • pwm_init_state(), pwm_get_state(), pwm_apply_state(): this API is used to initialize, retrieve and apply the current PWM device state.
  • pwm_config(): this API updates the PWM device configuration (period and duty cycle).
  • ...

2.2.2 Sysfs interface[edit]

In addition to Documentation/driver-api/pwm.txtrst[3], details on ABI are available in Documentation/ABI/testing/sysfs-class-pwm[4].

3 Configuration[edit]

3.1 Kernel configuration[edit]

Activate PWM framework in the kernel configuration through the Linux menuconfig tool, Menuconfig or how to configure kernel (CONFIG_PWM=y):

Device Drivers  --->
   [*] Pulse-Width Modulation (PWM) Support  --->

Activate PWM drivers for STM32 PWM drivers: STM32 TIM Linux driver and/or STM32 LPTIM Linux driver

3.2 Device tree configuration[edit]

  • PWM generic DT bindings:

PWM DT bindings documentation[5] describes device tree properties related to standard PWM user nodes and PWM controller nodes.

  • Detailed DT configuration for STM32 internal peripherals:

TIM device tree configuration and/or LPTIM device tree configuration

4 How to use the framework[edit]

PWM can be used either from the user or the kernel space.

4.1 How to use PWM with sysfs interface[edit]

The available PWM controllers are listed in sysfs:

Board $> ls /sys/class/pwm
pwmchip0

The number of channels per controller can be read in npwm (read-only)

Board $> cd /sys/class/pwm/pwmchip0
Board $> cat npwm
4

Each channel is exported (requested for sysfs activation) by writing the corresponding number in 'export'.

Info.png TIMx_CH1 is exported as "pwm0", TIMx_CH2 as "pwm1", and so on:
  • PWM channels are numbered from 0 to 'npwm' - 1
  • TIM[1] channels are numbered from 1 to 'npwm'.

As an example, proceed as follows to export the first channel (TIMx_CH1, e.g. channel 0):

Board $> echo 0 > export
Board $> ls
device  export  npwm  power  pwm0  subsystem  uevent  unexport

The period and duty cycle must be configured before enabling any channel.

As an example, proceed as follows to set a period of 100 ms with a duty cycle of 60% on channel 0:

Board $> echo 100000000 > pwm0/period
Board $> echo 60000000 > pwm0/duty_cycle
Board $> echo 1 > pwm0/enable

The polarity can be inverted or set to normal by using the polarity entry:

Board $> echo "inversed" > pwm0/polarity
Board $> cat pwm0/polarity
inversed

Board $> echo "normal" > pwm0/polarity
Board $> cat pwm0/polarity
normal

4.2 How to use PWM capture with sysfs interface[edit]

PWM capture is available on some PWM controllers such as TIM internal peripheral[1] (see TIM configured in PWM input capture mode ).

Info.png PWM output and capture mode are mutually exclusive on a TIM instance
# First export a channel (e.g. 0), then capture PWM input on it:
Board $> cd /sys/class/pwm/pwmchip0
Board $> echo 0 > export

Board $> cd pwm0
Board $> ls
capture  duty_cycle  enable  period  polarity  power  uevent

Board $> cat capture
10000 1002               # capture result is in nano-seconds, e.g.: 100KHz, 10% duty cycle

4.3 Example of PWM usage with kernel PWM API[edit]

Several in-kernel drivers use kernel PWM API. Below a few examples:

5 How to trace and debug the framework[edit]

5.1 How to monitor with debugfs[edit]

PWM usage can be monitored from debugfs 'pwm' entry. For example:

Board $> cd /sys/kernel/debug/
Board $> cat pwm
platform/44000000.timer:pwm, 4 PWM devices                                                               <-- One timer instance exposes 4 PWM channels.
 pwm-0   (sysfs               ): requested enabled period: 1000000 ns duty: 500000 ns polarity: normal   <-- Channel 0 has been exported, enabled and configured via sysfs
 pwm-1   ((null)              ): period: 0 ns duty: 0 ns polarity: normal
 pwm-2   ((null)              ): period: 0 ns duty: 0 ns polarity: normal                                <-- Other channels aren't used currently
 pwm-3   ((null)              ): period: 0 ns duty: 0 ns polarity: normal

5.2 Troubleshooting PWM capture[edit]

Here are some clues on how to debug possible errors in PWM capture mode.
See How to use PWM capture with sysfs interface as a pre-requisite.

Board $> cat capture 
cat: capture: Connection timed out

This may be due to:

  • the input signal isn't recognized as a PWM input (or there's no input signal to capture).
  • a wrong alternate function number is used for the input pin configuration in the device-tree.
    See "TIM configured in PWM input capture mode" for further details.
Board $> cat capture 
cat: capture: Device or resource busy

This may be due to:

  • a PWM channel on the same TIM instance is already running (in capture or output mode)
Board $> cat capture 
cat: capture: No such device

This may be due to:

Board $> cat capture
cat: capture: Function not implemented

This may be due to:

  • a wrong TIM instance is being used (e.g. "/sys/class/pwm/pwmchip/pwmchipN"), and it doesn't support capture (like LPTIM)
  • the DMA support isn't enabled (CONFIG_DMA_ENGINE)

6 References[edit]

  1. 1.01.11.2 TIM internal peripheral
  2. LPTIM internal peripheral
  3. 3.0 3.1 Documentation/driver-api/pwm.
  4. txt, Linux PWM interface overview
  5. rst , Pulse Width Modulation interface
  6. Documentation/ABI/testing/sysfs-class-pwm ,
  7. Linux PWM Application binary interface
  8. Pulse Width Modulation ABI
  9. Documentation/devicetree/bindings/pwm/pwm.txt , PWM DT bindings documentation
  10. drivers/input/misc/pwm-beeper.c , Example to use kernel PWM API
  11. drivers/input/misc/pwm-vibra.c , Example to use kernel PWM API



<noinclude>

{{ArticleBasedOnModel | [[Contributors:Framework overview article model]]}}
{{ArticleMainWriter | FabriceG}}
{{ReviewersList|GeraldB, BenjaminG, FabriceG}}
{{ ArticleApprovedVersion | FabriceG | GeraldB, BenjaminG, LoicP, NathalieS | No previous approved version | AnneJ - 29June'18 - 7957 | 04July'18}}

[[Category:Timers|0]]</noinclude>


'''SUMMARY '''<br>
This article gives information about the Linux<sup>&reg;</sup> PWM framework.<br />

It explains how to activate the PWM interface and, based on examples, how to use it.<br />
<br />


==Framework purpose==
'''PWM''' (Pulse Width Modulation) framework offers a unified interface for the users to:
* control PWM output(s) such as period, duty cycle and polarity.
* capture a PWM signal and report its period and duty cycle (e.g. input).

The interface can be used from:
* user space (sysfs)
* kernel space (API)

PWMs can be used in various use cases, as mentioned in [[#How to use the framework|How to use the framework]] to control LEDs, beepers, vibrators or fans...

==System overview==
{{
ImageMap|Image:PWM_overview.png {{!}} frame {{!}} center{{!}} PWM Implementation architecture<br/> {{WarningImageMapOverlay}}rect 400 232 500 272 [[PWM_overview#Sysfs_interface|PWM sysfs interface]]
rect 612 335 736 368 [[PWM_overview#Kernel_PWM_API|PWM kernel interface]]
rect 389 470 510 512 [[TIM Linux driver|STM32 TIM Linux driver]]
rect 571 470 692 512 [[LPTIM Linux driver|STM32 LPTIM Linux driver]]
rect 389 563 510 605 [[TIM internal peripheral|STM32 TIM internal peripheral]]
rect 571 563 692 605 [[LPTIM internal peripheral|STM32 LPTIM internal peripheral]]
}}
===Component description===
* '''PWM user''' (User space)
The user can use PWM sysfs interface, from a user terminal or a custom application, to control PWM device(s) from user space.
* '''PWM user''' (Kernel space)
User drivers can use PWM API to control PWM external device(s) from kernel space (such as back-light, vibrator, LED or fan drivers).
* '''PWM framework''' (Kernel space)
The PWM core provides sysfs interface and PWM API. They can be used to implement PWM user and PWM controller drivers.
* '''PWM drivers''' (Kernel space)
Provider drivers such as [[TIM Linux driver|STM32 TIM Linux driver]] and [[LPTIM Linux driver|STM32 LPTIM Linux driver]] that expose PWM controller(s) to the core.
* '''PWM hardware'''
PWM controller(s) such as ''TIM internal peripheral''<ref name="TIM internal peripheral">[[TIM internal peripheral]]</ref> and ''LPTIM internal peripheral''<ref name="LPTIM internal peripheral">[[LPTIM internal peripheral]]</ref> used to drive external PWM controlled devices.

===API description===
Documentation on PWM interface can be found under kernel [https://www.kernel.org/doc/Documentation/pwm.txt Documentation/pwm.txt] 
''Documentation/driver-api/pwm.rst''<ref name="pwm_rst">{{CodeSource | Linux kernel | Documentation/driver-api/pwm.rst | Documentation/driver-api/pwm.rst }}, Pulse Width Modulation interface</ref> 

====Kernel PWM API====
The main useful user API are the following:
*'''devm_pwm_get()''' or pwm_get() / pwm_put(): this API is used to look up, request, then free a PWM device.
*'''pwm_init_state()''', '''pwm_get_state()''', '''pwm_apply_state()''': this API is used to initialize, retrieve and apply the current PWM device state.
*'''pwm_config()''': this API updates the PWM device configuration (period and duty cycle).
*...

====Sysfs interface====
In addition to ''Documentation/driver-api/pwm.txtrst''<ref name="pwm_rst"/>[https://www.kernel.org/doc/Documentation/pwm.txt Documentation/pwm.txt], Linux PWM interface overview</ref> , details on ABI are available in ''Documentation/ABI/testing/sysfs-class-pwm''<ref name="sysfs_class_pwm">[https://www.kernel.org/doc/{{CodeSource | Linux kernel | Documentation/ABI/testing/sysfs-class-pwm | Documentation/ABI/testing/sysfs-class-pwm], Linux PWM Application binary interface }}, Pulse Width Modulation ABI</ref>.

==Configuration==

===Kernel configuration===
Activate PWM framework in the kernel configuration through the Linux menuconfig tool, [[Menuconfig or how to configure kernel | Menuconfig or how to configure kernel ]] (CONFIG_PWM=y):
 Device Drivers  --->
    [*] Pulse-Width Modulation (PWM) Support  --->

Activate PWM drivers for STM32 PWM drivers:
[[TIM Linux driver#Kernel configuration |STM32 TIM Linux driver]] and/or [[LPTIM Linux driver#Kernel configuration |STM32 LPTIM Linux driver]]

===Device tree configuration===
* PWM generic DT bindings:
''PWM DT bindings documentation''<ref name="pwm_txt">[https://www.kernel.org/doc/{{CodeSource | Linux kernel | Documentation/devicetree/bindings/pwm/pwm.txt | Documentation/devicetree/bindings/pwm/pwm.txt] }}, PWM DT bindings documentation</ref> describes device tree properties related to standard '''PWM user nodes''' and '''PWM controller nodes'''.
* Detailed DT configuration for STM32 internal peripherals:
[[TIM device tree configuration]] and/or [[LPTIM device tree configuration]]

==How to use the framework==
PWM can be used either from the user or the kernel space.

===How to use PWM with sysfs interface===
The available PWM controllers are listed in sysfs:
 {{Board$}} ls /sys/class/pwm
 '''pwmchip0'''

The number of channels per controller can be read in npwm (read-only)
 {{Board$}} cd /sys/class/pwm/pwmchip0
 {{Board$}} cat npwm
 '''4'''

Each channel is exported (requested for sysfs activation) by writing the corresponding number in 'export'.
{{Info|'''TIMx_CH1''' is exported as '''"pwm0"''', TIMx_CH2 as "pwm1", and so on:
*PWM channels are numbered from '''0 to 'npwm' - 1'''
* TIM<ref name="TIM internal peripheral"/> channels are numbered from '''1 to 'npwm''''.}}

As an example, proceed as follows to export the first channel (TIMx_CH1, e.g. channel 0):
 {{Board$}} echo '''0''' > export
 {{Board$}} ls
 device  export  '''npwm'''  power  '''pwm0'''  subsystem  uevent  unexport

The period and duty cycle must be configured before enabling any channel.

As an example, proceed as follows to set a period of 100 ms with a duty cycle of 60% on channel 0:
 {{Board$}} echo 100000000 > pwm0/period
 {{Board$}} echo 60000000 > pwm0/duty_cycle
 {{Board$}} echo 1 > pwm0/enable

The polarity can be inverted or set to normal by using the polarity entry:
 {{Board$}} echo "'''inversed'''" > pwm0/polarity
 {{Board$}} cat pwm0/polarity
 '''inversed'''

 {{Board$}} echo "'''normal'''" > pwm0/polarity
 {{Board$}} cat pwm0/polarity
 '''normal'''

===How to use PWM capture with sysfs interface===
PWM capture is available on some PWM controllers such as ''TIM internal peripheral''<ref name="TIM internal peripheral"/> (see [[TIM_device_tree_configuration#TIM configured in PWM input capture mode|TIM configured in PWM input capture mode]] ).
{{Info|PWM output and capture mode are mutually exclusive on a TIM instance}}
 # First export a channel (e.g. 0), then capture PWM input on it:
 {{Board$}} cd /sys/class/pwm/pwmchip0
 {{Board$}} echo '''0''' > export

 {{Board$}} cd pwm0
 {{Board$}} ls
 '''capture'''  duty_cycle  enable  period  polarity  power  uevent

 {{Board$}} cat capture
 '''10000 1002'''               {{highlight|# capture result is in nano-seconds, e.g.: 100KHz, 10% duty cycle}}
===Example of PWM usage with kernel PWM API===
Several in-kernel drivers use [[PWM_overview#Kernel_PWM_API|kernel PWM API]]. Below a few examples:
* pwm-beeper: ''drivers/input/misc/pwm-beeper.c''<ref>{{CodeSource | Linux kernel | drivers/input/misc/pwm-beeper.c | drivers/input/misc/pwm-beeper.c}}, Example to use kernel PWM API</ref> driver, {{CodeSource | Linux kernel | Documentation/devicetree/bindings/input/pwm-beeper.txt | Documentation/devicetree/bindings/input/pwm-beeper.txt}} DT binding documentation.
* pwm-vibrator: ''drivers/input/misc/pwm-vibra.c''<ref>{{CodeSource | Linux kernel | drivers/input/misc/pwm-vibra.c | drivers/input/misc/pwm-vibra.c}}, Example to use kernel PWM API</ref> driver, {{CodeSource | Linux kernel | Documentation/devicetree/bindings/input/pwm-vibrator.txt | Documentation/devicetree/bindings/input/pwm-vibrator.txt}} DT binding documentation.

==How to trace and debug the framework==
=== How to monitor with debugfs ===
PWM usage can be monitored from [[Debugfs|debugfs]] 'pwm' entry. For example:
 {{Board$}} cd /sys/kernel/debug/
 {{Board$}} cat pwm
 platform/44000000.timer:pwm, 4 PWM devices                                                               {{highlight|<-- One timer instance exposes 4 PWM channels.}}
  pwm-0   (sysfs               ): requested enabled period: 1000000 ns duty: 500000 ns polarity: normal   {{highlight|<-- Channel 0 has been exported, enabled and configured via sysfs}}
  pwm-1   ((null)              ): period: 0 ns duty: 0 ns polarity: normal
  pwm-2   ((null)              ): period: 0 ns duty: 0 ns polarity: normal                                {{highlight|<-- Other channels aren't used currently}}
  pwm-3   ((null)              ): period: 0 ns duty: 0 ns polarity: normal
=== Troubleshooting PWM capture ===
Here are some clues on how to debug possible errors in PWM capture mode.<br/>
See [[#How to use PWM capture with sysfs interface|How to use PWM capture with sysfs interface]] as a pre-requisite.
 {{Board$}} cat capture 
 cat: capture: Connection timed out
This may be due to:
* the input signal isn't recognized as a PWM input (or there's no input signal to capture).
* a wrong alternate function number is used for the input pin configuration in the device-tree.<br/>See "[[TIM_device_tree_configuration#TIM configured in PWM input capture mode|TIM configured in PWM input capture mode]]" for further details.
 {{Board$}} cat capture 
 cat: capture: Device or resource busy
This may be due to:
* a PWM channel on the same TIM instance is already running (in capture or output mode)
 {{Board$}} cat capture 
 cat: capture: No such device
This may be due to:
* the DMA isn't configured properly in the device-tree.<br/>See "[[TIM_device_tree_configuration#TIM configured in PWM input capture mode|TIM configured in PWM input capture mode]]" for further details.
 {{Board$}} cat capture
 cat: capture: Function not implemented
This may be due to:
* a wrong TIM instance is being used (e.g. "/sys/class/pwm/pwmchip/pwmchipN"), and it doesn't support capture (like LPTIM)
* the DMA support isn't enabled (CONFIG_DMA_ENGINE)
==References==
<references />

<noinclude>

{{ArticleBasedOnModel | Framework overview article model}}
{{PublicationRequestId | 7957 | 2018-06-29 | AnneJ}}

[[Category:Timers|0]]</noinclude>
(2 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<noinclude>
 
{{ArticleBasedOnModel | [[Contributors:Framework overview article model]]}}
 
{{ArticleMainWriter | FabriceG}}
 
{{ReviewersList|GeraldB, BenjaminG, FabriceG}}
 
{{ ArticleApprovedVersion | FabriceG | GeraldB, BenjaminG, LoicP, NathalieS | No previous approved version | AnneJ - 29June'18 - 7957 | 04July'18}}
 
 
[[Category:Timers|0]]
 
</noinclude>
 
 
'''SUMMARY '''<br>
 
 
This article gives information about the Linux<sup>&reg;</sup> PWM framework.<br />
 
This article gives information about the Linux<sup>&reg;</sup> PWM framework.<br />
 
It explains how to activate the PWM interface and, based on examples, how to use it.<br />
 
It explains how to activate the PWM interface and, based on examples, how to use it.<br />
Line 26: Line 16:
 
==System overview==
 
==System overview==
 
{{
 
{{
ImageMap|Image:PWM_overview.png {{!}} frame {{!}} center{{!}} PWM Implementation architecture <br/> {{WarningImageMapOverlay}}
+
ImageMap|Image:PWM_overview.png {{!}} frame {{!}} center{{!}} PWM Implementation architecture
 
rect 400 232 500 272 [[PWM_overview#Sysfs_interface|PWM sysfs interface]]
 
rect 400 232 500 272 [[PWM_overview#Sysfs_interface|PWM sysfs interface]]
 
rect 612 335 736 368 [[PWM_overview#Kernel_PWM_API|PWM kernel interface]]
 
rect 612 335 736 368 [[PWM_overview#Kernel_PWM_API|PWM kernel interface]]
Line 47: Line 37:
   
 
===API description===
 
===API description===
Documentation on PWM interface can be found under kernel [https://www.kernel.org/doc/Documentation/pwm.txt Documentation/pwm.txt]
+
Documentation on PWM interface can be found under kernel ''Documentation/driver-api/pwm.rst''<ref name="pwm_rst">{{CodeSource | Linux kernel | Documentation/driver-api/pwm.rst | Documentation/driver-api/pwm.rst }}, Pulse Width Modulation interface</ref>
   
 
====Kernel PWM API====
 
====Kernel PWM API====
Line 57: Line 47:
   
 
====Sysfs interface====
 
====Sysfs interface====
In addition to ''Documentation/pwm.txt''<ref>[https://www.kernel.org/doc/Documentation/pwm.txt Documentation/pwm.txt], Linux PWM interface overview</ref> details on ABI are available in ''Documentation/ABI/testing/sysfs-class-pwm''<ref>[https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-pwm Documentation/ABI/testing/sysfs-class-pwm], Linux PWM Application binary interface</ref>.
+
In addition to ''Documentation/driver-api/pwm.rst''<ref name="pwm_rst"/>, details on ABI are available in ''Documentation/ABI/testing/sysfs-class-pwm''<ref name="sysfs_class_pwm">{{CodeSource | Linux kernel | Documentation/ABI/testing/sysfs-class-pwm | Documentation/ABI/testing/sysfs-class-pwm }}, Pulse Width Modulation ABI</ref>.
   
 
==Configuration==
 
==Configuration==
Line 71: Line 61:
 
===Device tree configuration===
 
===Device tree configuration===
 
* PWM generic DT bindings:
 
* PWM generic DT bindings:
''PWM DT bindings documentation''<ref>[https://www.kernel.org/doc/Documentation/devicetree/bindings/pwm/pwm.txt Documentation/devicetree/bindings/pwm/pwm.txt], PWM DT bindings documentation</ref> describes device tree properties related to standard '''PWM user nodes''' and '''PWM controller nodes'''.
+
''PWM DT bindings documentation''<ref name="pwm_txt">{{CodeSource | Linux kernel | Documentation/devicetree/bindings/pwm/pwm.txt | Documentation/devicetree/bindings/pwm/pwm.txt }}, PWM DT bindings documentation</ref> describes device tree properties related to standard '''PWM user nodes''' and '''PWM controller nodes'''.
 
* Detailed DT configuration for STM32 internal peripherals:
 
* Detailed DT configuration for STM32 internal peripherals:
 
[[TIM device tree configuration]] and/or [[LPTIM device tree configuration]]
 
[[TIM device tree configuration]] and/or [[LPTIM device tree configuration]]
Line 166: Line 156:
   
 
<references />
 
<references />
  +
  +
<noinclude>
  +
{{ArticleBasedOnModel | Framework overview article model}}
  +
{{PublicationRequestId | 7957 | 2018-06-29 | AnneJ}}
  +
  +
[[Category:Timers|0]]
  +
</noinclude>