Registered User mNo edit summary |
Registered User |
||
(12 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
< | This article gives information about the Linux<sup>®</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 | ImageMap|Image:PWM_overview.png {{!}} frame {{!}} center{{!}} PWM Implementation architecture | ||
rect | rect 414 242 514 284 [[PWM_overview#Sysfs_interface|PWM sysfs interface]] | ||
rect | rect 632 350 756 382 [[PWM_overview#Kernel_PWM_API|PWM kernel interface]] | ||
rect | rect 402 486 526 529 [[TIM Linux driver|STM32 TIM Linux driver]] | ||
rect | rect 588 486 711 529 [[LPTIM Linux driver|STM32 LPTIM Linux driver]] | ||
rect | rect 402 581 526 624 [[TIM internal peripheral|STM32 TIM internal peripheral]] | ||
rect | rect 588 582 711 624 [[LPTIM internal peripheral|STM32 LPTIM internal peripheral]] | ||
}} | }} | ||
===Component description=== | ===Component description=== | ||
Line 43: | Line 37: | ||
===API description=== | ===API description=== | ||
Documentation on PWM interface can be found under kernel | 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 53: | Line 47: | ||
====Sysfs interface==== | ====Sysfs interface==== | ||
In addition to ''Documentation/pwm. | 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== | ||
===Kernel configuration=== | ===Kernel configuration=== | ||
Line 67: | Line 61: | ||
===Device tree configuration=== | ===Device tree configuration=== | ||
* PWM generic DT bindings: | * PWM generic DT bindings: | ||
''PWM DT bindings documentation''<ref> | ''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]] | ||
==How to use | ==How to use the framework== | ||
PWM can be used either from the user or the kernel space. | PWM can be used either from the user or the kernel space. | ||
===How to use PWM with sysfs interface=== | ===How to use PWM with sysfs interface=== | ||
The available PWM controllers are listed in sysfs: | The available PWM controllers are listed in sysfs: | ||
$ ls /sys/class/pwm | {{Board$}} ls /sys/class/pwm | ||
'''pwmchip0''' | '''pwmchip0''' | ||
The number of channels per controller can be read in npwm (read-only) | The number of channels per controller can be read in npwm (read-only) | ||
$ cd /sys/class/pwm/pwmchip0 | {{Board$}} cd /sys/class/pwm/pwmchip0 | ||
$ cat npwm | {{Board$}} cat npwm | ||
'''4''' | '''4''' | ||
Each channel is exported (requested for sysfs activation) by writing the corresponding number in 'export'. | 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 (e.g. channel 0): | As an example, proceed as follows to export the first channel (TIMx_CH1, e.g. channel 0): | ||
{{ | {{Board$}} echo '''0''' > export | ||
{{Board$}} ls | |||
$ ls | device export '''npwm''' power '''pwm0''' subsystem uevent unexport | ||
device export npwm power '''pwm0''' subsystem uevent unexport | |||
The period and duty cycle must be configured before enabling any channel. | 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: | As an example, proceed as follows to set a period of 100 ms with a duty cycle of 60% on channel 0: | ||
$ echo 100000000 > pwm0/period | {{Board$}} echo 100000000 > pwm0/period | ||
$ echo 60000000 > pwm0/duty_cycle | {{Board$}} echo 60000000 > pwm0/duty_cycle | ||
$ echo 1 > pwm0/enable | {{Board$}} echo 1 > pwm0/enable | ||
The polarity can be inverted or set to normal by using the polarity entry: | The polarity can be inverted or set to normal by using the polarity entry: | ||
$ echo "'''inversed'''" > pwm0/polarity | {{Board$}} echo "'''inversed'''" > pwm0/polarity | ||
$ cat pwm0/polarity | {{Board$}} cat pwm0/polarity | ||
'''inversed''' | '''inversed''' | ||
$ echo "'''normal'''" > pwm0/polarity | {{Board$}} echo "'''normal'''" > pwm0/polarity | ||
$ cat pwm0/polarity | {{Board$}} cat pwm0/polarity | ||
'''normal''' | '''normal''' | ||
===How to use PWM capture with sysfs interface=== | ===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]] ). | 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: | # First export a channel (e.g. 0), then capture PWM input on it: | ||
$ cd /sys/class/pwm/pwmchip0 | {{Board$}} cd /sys/class/pwm/pwmchip0 | ||
$ echo '''0''' > export | {{Board$}} echo '''0''' > export | ||
$ cd pwm0 | {{Board$}} cd pwm0 | ||
$ ls | {{Board$}} ls | ||
'''capture''' duty_cycle enable period polarity power uevent | '''capture''' duty_cycle enable period polarity power uevent | ||
$ cat capture | {{Board$}} cat capture | ||
'''10000 1002''' {{highlight|# capture result is in nano-seconds, e.g.: 100KHz, 10% duty cycle}} | '''10000 1002''' {{highlight|# capture result is in nano-seconds, e.g.: 100KHz, 10% duty cycle}} | ||
===Example of PWM usage with kernel PWM API=== | ===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: | Several in-kernel drivers use [[PWM_overview#Kernel_PWM_API|kernel PWM API]]. Below a few examples: | ||
Line 130: | Line 125: | ||
=== How to monitor with debugfs === | === How to monitor with debugfs === | ||
PWM usage can be monitored from [[Debugfs|debugfs]] 'pwm' entry. For example: | PWM usage can be monitored from [[Debugfs|debugfs]] 'pwm' entry. For example: | ||
$ cd /sys/kernel/debug/ | {{Board$}} cd /sys/kernel/debug/ | ||
$ cat pwm | {{Board$}} cat pwm | ||
platform/44000000.timer:pwm, 4 PWM devices {{highlight|<-- One timer instance exposes 4 PWM channels.}} | 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-0 (sysfs ): requested enabled period: 1000000 ns duty: 500000 ns polarity: normal {{highlight|<-- Channel 0 has been exported, enabled and configured via sysfs}} | ||
Line 137: | Line 132: | ||
pwm-2 ((null) ): period: 0 ns duty: 0 ns polarity: normal {{highlight|<-- Other channels aren't used currently}} | 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 | 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== | ||
<references /> | <references /> | ||
<noinclude> | |||
{{ArticleBasedOnModel | Framework overview article model}} | |||
{{PublicationRequestId | 7957 | 2018-06-29 | AnneJ}} | |||
[[Category:Timers|0]] | |||
</noinclude> |
Latest revision as of 12:37, 18 February 2021
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 source]
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 source]
2.1. Component description[edit source]
- 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 source]
Documentation on PWM interface can be found under kernel Documentation/driver-api/pwm.rst[3]
2.2.1. Kernel PWM API[edit source]
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 source]
In addition to Documentation/driver-api/pwm.rst[3], details on ABI are available in Documentation/ABI/testing/sysfs-class-pwm[4].
3. Configuration[edit source]
3.1. Kernel configuration[edit source]
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 source]
- 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 source]
PWM can be used either from the user or the kernel space.
4.1. How to use PWM with sysfs interface[edit source]
The available PWM controllers are listed in sysfs:
ls /sys/class/pwm pwmchip0
The number of channels per controller can be read in npwm (read-only)
cd /sys/class/pwm/pwmchip0 cat npwm 4
Each channel is exported (requested for sysfs activation) by writing the corresponding number in 'export'.
As an example, proceed as follows to export the first channel (TIMx_CH1, e.g. channel 0):
echo 0 > export 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:
echo 100000000 > pwm0/period echo 60000000 > pwm0/duty_cycle echo 1 > pwm0/enable
The polarity can be inverted or set to normal by using the polarity entry:
echo "inversed" > pwm0/polarity cat pwm0/polarity inversed echo "normal" > pwm0/polarity cat pwm0/polarity normal
4.2. How to use PWM capture with sysfs interface[edit source]
PWM capture is available on some PWM controllers such as TIM internal peripheral[1] (see TIM configured in PWM input capture mode ).
# First export a channel (e.g. 0), then capture PWM input on it: cd /sys/class/pwm/pwmchip0 echo 0 > export cd pwm0 ls capture duty_cycle enable period polarity power uevent cat capture 10000 1002 Template:Highlight
4.3. Example of PWM usage with kernel PWM API[edit source]
Several in-kernel drivers use kernel PWM API. Below a few examples:
- pwm-beeper: drivers/input/misc/pwm-beeper.c[6] driver, Template:CodeSource DT binding documentation.
- pwm-vibrator: drivers/input/misc/pwm-vibra.c[7] driver, Template:CodeSource DT binding documentation.
5. How to trace and debug the framework[edit source]
5.1. How to monitor with debugfs[edit source]
PWM usage can be monitored from debugfs 'pwm' entry. For example:
cd /sys/kernel/debug/ cat pwm platform/44000000.timer:pwm, 4 PWM devices Template:Highlight pwm-0 (sysfs ): requested enabled period: 1000000 ns duty: 500000 ns polarity: normal Template:Highlight pwm-1 ((null) ): period: 0 ns duty: 0 ns polarity: normal pwm-2 ((null) ): period: 0 ns duty: 0 ns polarity: normal Template:Highlight pwm-3 ((null) ): period: 0 ns duty: 0 ns polarity: normal
5.2. Troubleshooting PWM capture[edit source]
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.
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.
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)
cat capture cat: capture: No such device
This may be due to:
- the DMA isn't configured properly in the device-tree.
See "TIM configured in PWM input capture mode" for further details.
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 source]
- ↑ 1.0 1.1 1.2 TIM internal peripheral
- ↑ LPTIM internal peripheral
- ↑ 3.0 3.1 Template:CodeSource, Pulse Width Modulation interface
- ↑ Template:CodeSource, Pulse Width Modulation ABI
- ↑ Template:CodeSource, PWM DT bindings documentation
- ↑ Template:CodeSource, Example to use kernel PWM API
- ↑ Template:CodeSource, Example to use kernel PWM API