PWM (Linux)
Introduction
This article will guide you on how to use the sysfs linux interface to control PWM signals on Toradex's System on Modules (SoMs). It also provides guidance on working with GPIO-related drivers and explains how to access GPIO within U-Boot.
Keep in mind that Torizon OS is preferred to control PWM due to its ease of use and smoother application development experience. For controlling PWM pins using Torizon, refer to How to Use PWM on Torizon OS.
The Linux kernel provides an alternative, easier-to-use driver to control the Display Backlight Brightness PWM control signal. See Backlight PWM (Linux) for more information about PWM backlight usage.
Control PWM through Pwmchip
The following instructions apply to all Toradex modules; for specific information on how to use each module's PWM interfaces, please refer to Pwmchip paths on Toradex System on Modules (SoMs).
This section provides generic information on how to use PWM in Linux with the Pwmchip interface.
- Go to your desired PWM pin's
pwmchipdirectory. Refer to Specific information about Toradex Computer on Modules (CoM) for information about each pin's directory. This example uses/sys/class/pwm/pwmchip1/.
# cd /sys/class/pwm/pwmchip1/
- Write to the
exportfile to select your pin's PWM channel. This example useschannel 0
# echo 0 > export
A pwm<n> directory should appear inside /sys/class/pwm/pwmchip1/, where <n> is the number of the channel you selected.
Each PWM controller in the SoC includes multiple channels, each mapped to specific pins. To configure PWM output correctly, you must identify the appropriate channel for your target pin, according to the channel specification for Toradex SoMs:
- For NXP iMX-based devices: The channel is always
0 - For TI AMx-based devices: Each pin has a TI equivalent signal name with the format
EHRPWMx_AorEHRPWMx_B. You must check the signal name in your device's datasheet and choose the channel with the following criteria:EHRPWMx_A: Channel0EHRPWMx_B: Channel1
- Select the period of the PWM signal. The period's value is in nanoseconds.
# echo 1000000 > pwm0/period
- Select the duty cycle of the PWM signal. The duty cicle's value is in nanoseconds and must be less than the period.
# echo 500000 > pwm0/duty_cycle
- Select the polarity of the PWM signal (you can use "normal" or "inversed"). The polarity can only be changed if the PWM is not enabled.
# echo "normal" > pwm0/polarity
- Enable/disable the PWM signal, use 1 or 0 respectively:
# echo 1 > pwm0/enable
Control PWM through the LED driver
You can use the PWM LED driver which allows controlling LED's brightness through PWM. The LED framework has also the advantage that triggers can be configured. Triggers allow to let a LED be controlled by kernel events such as NAND flash access.
Make sure the kernel configuration CONFIG_LEDS_PWM resp. CONFIG_LEDS_GPIO is enabled.
In the example below using a Verdin iMX8M Plus, PWM_1 was configured adding the following device tree overlay:
/dts-v1/;
/plugin/;
/ {
compatible = "toradex,verdin-imx8mp";
};
&pwm1 {
status = "okay";
};
&{/} {
led-controller {
compatible = "pwm-leds";
led-1 {
label = "verdin_status_led";
pwms = <&pwm1 0 5000000 0>;
max-brightness = <255>;
};
};
};
The brightness can then be configured using sysfs:
echo 120 > /sys/class/leds/verdin_status_led/brightness
To let the LED be controlled by the kernel itself, triggers can be used to control the LED:
echo nand-disk > /sys/class/leds/verdin_status_led/trigger
There is also a GPIO LED driver, which might be more appropriate for LED's which are only used in an on/off configuration (e.g. triggers).
Pwmchip paths on Toradex System on Modules (SoMs)
The tables below list the the /sys/class/pwm/pwmchip<n> paths of each PWM pin for Toradex SoMs, check the correspondent path for your own device.
The values shown here are only valid for Toradex's unmodified Device Trees. If you create a custom Device Tree for your module or apply a Device Tree Overlay, the pwmchip<n> numbers could be different. This happnes because the kernel mounts the PWM interfaces in order as the Device Tree is applied at the system startup.
If you modify your module's Device Tree, and the PWM numbers change, run the command below to list the memory addresses of the pwmchip<n> interfaces, and compare them with the addresses of the PWM nodes of the device tree.
$ ls -l /sys/class/pwm
The Display Backlight dedicated PWM pins cannot be controlled via the pwmchip interface by default, since they are used by the backlight driver. To use the dedicated pins as regular PWM sources, disable the pwm-backlight functionality on the device tree (refer to Device Tree Customization).
Aquila AM69
| Toradex Name | TI Name | sysfs path | Note |
|---|---|---|---|
| PWM_1 | EPWM0 | /sys/class/pwm/pwmchip0/ | - |
| PWM_2 | EPWM3 | /sys/class/pwm/pwmchip4/ | - |
| PWM_3_DSI | EPWM5 | /sys/class/pwm/pwmchip6/ | Dedicated PWM for display backlight |
| PWM_4_DP | EPWM2 | /sys/class/pwm/pwmchip2/ | Dedicated PWM for display port |
Verdin iMX8M Mini
| Toradex Name | NXP/Freescale Name | sysfs path | Note |
|---|---|---|---|
| PWM_1 | PWM2 | /sys/class/pwm/pwmchip1/ | - |
| PWM_2 | PWM3 | /sys/class/pwm/pwmchip2/ | - |
| PWM_3_DSI | PWM1 | /sys/class/pwm/pwmchip0/ | Dedicated PWM for display backlight |
Verdin iMX8M Plus
| Toradex Name | NXP/Freescale Name | sysfs path | Note |
|---|---|---|---|
| PWM_1 | PWM1 | /sys/class/pwm/pwmchip0/ | - |
| PWM_2 | PWM2 | /sys/class/pwm/pwmchip1/ | - |
| PWM_3_DSI | PWM3 | /sys/class/pwm/pwmchip2/ | Dedicated PWM for display backlight |
Verdin AM62
| Toradex Name | TI Name | sysfs path | Note |
|---|---|---|---|
| PWM_1 | EHRPWM0_A | /sys/class/pwm/pwmchip0/ | - |
| PWM_2 | EHRPWM0_B | /sys/class/pwm/pwmchip0/ | - |
| PWM_3_DSI | EHRPWM1_A | /sys/class/pwm/pwmchip2/ | Dedicated PWM for display backlight |
Verdin AM62P
| Toradex Name | TI Name | sysfs path | Note |
|---|---|---|---|
| PWM_1 | EHRPWM2_B | /sys/class/pwm/pwmchip0/ | - |
| PWM_2 | EHRPWM2_A | /sys/class/pwm/pwmchip0/ | - |
| PWM_3_DSI | EHRPWM0_B | /sys/class/pwm/pwmchip2/ | Dedicated PWM for display backlight |
Apalis iMX8
| Toradex Name | NXP/Freescale Name | sysfs path | Note |
|---|---|---|---|
| PWM 1 | PWM 2 | /sys/class/pwm/pwmchip2/ | - |
| PWM 2 | PWM 3 | /sys/class/pwm/pwmchip3/ | - |
| PWM 3 | PWM 0 | /sys/class/pwm/pwmchip0/ | - |
| PWM 4 | PWM 1 | /sys/class/pwm/pwmchip1/ | - |
Apalis iMX6
| Toradex Name | NXP/Freescale Name | sysfs path | Note |
|---|---|---|---|
| PWM1 | PWM1 | /sys/class/pwm/pwmchip0/ | - |
| PWM2 | PWM2 | /sys/class/pwm/pwmchip1/ | - |
| PWM3 | PWM3 | /sys/class/pwm/pwmchip2/ | - |
| PWM4 | PWM4 | /sys/class/backlight/backlight.17/ | Dedicated PWM for display backlight |
Colibri iMX8X
| Toradex Name | NXP/Freescale Name | sysfs path | Note |
|---|---|---|---|
| PWM_A | ADMA_LCD_PWM0 | /sys/class/pwm/pwmchip0/ | Dedicated PWM for display backlight |
| PWM_B | LSIO_PWM0 | /sys/class/pwm/pwmchip1/ | - |
| PWM_C | LSIO_PWM1 | /sys/class/pwm/pwmchip2/ | - |
| PWM_D | LSIO_PWM2 | /sys/class/pwm/pwmchip3/ | - |
Colibri iMX7
| Toradex Name | NXP/Freescale Name | sysfs path | Note |
|---|---|---|---|
| PWM_A | PWM1 | /sys/class/pwm/pwmchip0/ | Dedicated PWM for display backlight |
| PWM_B | PWM2 | /sys/class/pwm/pwmchip1/ | - |
| PWM_C | PWM3 | /sys/class/pwm/pwmchip2/ | - |
| PWM_D | PWM4 | /sys/class/pwm/pwmchip3/ | - |
Colibri iMX6ULL
| Toradex Name | NXP/Freescale Name | sysfs path | Note |
|---|---|---|---|
| PWM_A | PWM4 | /sys/class/pwm/pwmchip0/ | Dedicated PWM for display backlight |
| PWM_B | PWM5 | /sys/class/pwm/pwmchip1/ | - |
| PWM_C | PWM6 | /sys/class/pwm/pwmchip2/ | - |
| PWM_D | PWM7 | /sys/class/pwm/pwmchip3/ | - |
These values apply to BSP 5. In the more recent versions, the (unusable) interfaces are mounted before, so PWM_A will be at pwmchip3 (and so on).
Colibri iMX6
| Toradex Name | NXP/Freescale Name | sysfs path | Note |
|---|---|---|---|
| PWM_A | PWM3 | /sys/class/pwm/pwmchip2/ | Dedicated PWM for display backlight |
| PWM_B | PWM1 | /sys/class/pwm/pwmchip0/ | - |
| PWM_C | PWM4 | /sys/class/pwm/pwmchip3/ | - |
| PWM_D | PWM2 | /sys/class/pwm/pwmchip1/ | - |