This guide demonstrates how to configure and use PWM (Pulse Width Modulation) on the SP7350 platform using the sysfs interface. We'll cover setting up the period, duty cycle, and enabling PWM.
Table of Contents
1. Modify Device-tree Source
To enable and configure PWM pins, edit the PWM node in the device-tree source. For the SP7350 Evaluation Board, you can find the file at "arch/arm64/boot/dts/sunplus/sp7350-ev.dts" within the kernel directory.
Locate the PWM node, configure the pins, and activate it. For instance,
&pwm { pinctrl-names = "default"; pinctrl-0 = <&pwm0_pins &pwm1_pins &pwm2_pins &pwm3_pins>; //status = "disabled"; }; &pctl { // ... (previous configurations) pwm0_pins: pinmux_pwm0-pins { function = "PWM0"; groups = "PWM0_X2"; drive-strength-microamp = <SPPCTRL_DVIO_DRV_IOH_15200_IOL_18700UA>; }; pwm1_pins: pinmux_pwm1-pins { function = "PWM1"; groups = "PWM1_X2"; drive-strength-microamp = <SPPCTRL_DVIO_DRV_IOH_15200_IOL_18700UA>; }; pwm2_pins: pinmux_pwm2-pins { function = "PWM2"; groups = "PWM2_X1"; drive-strength-microamp = <SPPCTRL_DVIO_DRV_IOH_15200_IOL_18700UA>; }; pwm3_pins: pinmux_pwm3-pins { function = "PWM3"; groups = "PWM3_X1"; drive-strength-microamp = <SPPCTRL_DVIO_DRV_IOH_15200_IOL_18700UA>; }; // ... (other configurations) };
Please note that the "pwm" label refers to the node "pwm@f8800d80" in "arch/arm64/boot/dts/sunplus/sp7350-common.dtsi" located in the kernel directory.
The subnodes under "pinctrl", "pinmux_pwm0-pins", "pinmux_pwm1-pins", "pinmux_pwm2-pins", and "pinmux_pwm3-pins", configure the output pins for PWM channels 0, 1, 2, and 3. These channels correspond to the pins AO_MX8, AO_MX9, AO_MX10, and AO_MX11, respectively. For detailed pin configurations, please refer to the table available at https://sunplus.atlassian.net/wiki/spaces/C3/pages/1971126471/SP7350+Specification#13.3-Pulse-Width-Modulation-(PWM). Each PWM output can support two pin positions:
Channel | Pin at Position X1 | Pin at Position X2 | Remarks |
---|---|---|---|
PWM_CH0 | AO_MX28 | AO_MX8 |
|
PWM_CH1 | AO_MX29 | AO_MX9 |
|
PWM_CH2 | AO_MX10 | AO_MX42 |
|
PWM_CH3 | AO_MX11 | AO_MX43 |
|
2. Enable Linux PWM Driver
The Linux PWM driver should be enabled by default. Confirm by running make kconfig in the project top directory and check "Device Drivers" → "Pulse-width Modulation (PWM) support" for "Sunplus PWM support". Refer to screenshot of Linux Kernel Configuration menu below:
3. Build Linux Image
Whether you modify the device-tree source or kernel features, execute the make command to build the Linux image.
4. Check PWM Output Pins
After booting into Linux, you can check the pin assignments by running:
cat /sys/kernel/debug/pinctrl/f8800080pinctl/pinmux-pins
This will provide a report on the pin assignments for all GPIOs. Referring to the relevant portion of the report:
~ # cat /sys/kernel/debug/pinctrl/f8800080.pinctrl/pinmux-pins Pinmux settings per pin Format: pin (name): mux_owner|gpio_owner (strict) hog? pin 0 (GPIO0): UNCLAIMED pin 1 (GPIO1): UNCLAIMED pin 2 (GPIO2): UNCLAIMED pin 3 (GPIO3): device f8103000.stmmac function GMAC group GMAC_RGMII : : pin 58 (GPIO58): device f8800d80.pwm function PWM0 group PWM0_X2 pin 59 (GPIO59): device f8800d80.pwm function PWM1 group PWM1_X2 pin 60 (GPIO60): device f8800d80.pwm function PWM2 group PWM2_X1 pin 61 (GPIO61): device f8800d80.pwm function PWM3 group PWM3_X1 pin 62 (GPIO62): UNCLAIMED :
GPIO58 (AO_MX8), GPIO59 (AO_MX9), GPIO60 (AO_MX10), and GPIO61 (AO_MX11) are assigned to PWM channels as follows:
GPIO58 (AO_MX8) is set to PWM0 (X2 position)
GPIO59 (AO_MX9) is set to PWM1 (X2 position)
GPIO60 (AO_MX10) is set to PWM2 (X1 position)
GPIO61 (AO_MX11) is set to PWM3 (X1 position)
5. Using PWM with the sysfs Interface
A straightforward sysfs interface is available for PWM control from userspace. The path to this interface is /sys/class/pwm/pwmchipN, where N represents the base of the PWM controller. Since the SP7350 has only one PWM controller, N is 0. Within this directory, you'll find the following files and directories: npwm, export, unexport, and so on.
Here's the content of the /sys/class/pwm/pwmchip0 directory as shown by the ls -l command:
~ # ls -l /sys/class/pwm/pwmchip0/ lrwxrwxrwx 1 root root 0 Jan 1 00:48 device -> ../../../f8800d80.pwm --w------- 1 root root 4096 Jan 1 00:48 export -r--r--r-- 1 root root 4096 Jan 1 00:48 npwm drwxr-xr-x 2 root root 0 Jan 1 00:48 power lrwxrwxrwx 1 root root 0 Jan 1 00:48 subsystem -> ../../../../../class/pwm -rw-r--r-- 1 root root 4096 Jan 1 00:48 uevent --w------- 1 root root 4096 Jan 1 00:48 unexport
Files and Their Descriptions:
npwm: This file indicates the number of PWM channels supported by this chip (read-only).
export: Use this file to export a PWM channel for sysfs use (write-only).
unexport: This file allows you to unexport a PWM channel from sysfs (write-only).
The SP7350 PWM controller supports 4 channels, as indicated by the output of the cat command:
~ # cat /sys/class/pwm/pwmchip0/npwm 4
To export PWM channels 0 through 3, you can use the following commands:
~ # echo 0 > /sys/class/pwm/pwmchip0/export ~ # echo 1 > /sys/class/pwm/pwmchip0/export ~ # echo 2 > /sys/class/pwm/pwmchip0/export ~ # echo 3 > /sys/class/pwm/pwmchip0/export
Once a PWM channel is exported, a corresponding folder pwmX is created within the pwmchipN directory, where X is the channel number. As shown by the output of the ls -l command:
~ # ls -l /sys/class/pwm/pwmchip0/ lrwxrwxrwx 1 root root 0 Jan 1 00:48 device -> ../../../f8800d80.pwm --w------- 1 root root 4096 Jan 1 01:07 export -r--r--r-- 1 root root 4096 Jan 1 00:48 npwm drwxr-xr-x 2 root root 0 Jan 1 00:48 power drwxr-xr-x 3 root root 0 Jan 1 01:07 pwm0 drwxr-xr-x 3 root root 0 Jan 1 01:07 pwm1 drwxr-xr-x 3 root root 0 Jan 1 01:07 pwm2 drwxr-xr-x 3 root root 0 Jan 1 01:07 pwm3 lrwxrwxrwx 1 root root 0 Jan 1 00:48 subsystem -> ../../../../../class/pwm -rw-r--r-- 1 root root 4096 Jan 1 00:48 uevent --w------- 1 root root 4096 Jan 1 00:48 unexport
You can see that the directories pwm0, pwm1, pwm2, and pwm3 have been created under /sys/class/pwm/pwmchip0/.
Here's a breakdown of the content of the /sys/class/pwm/pwmchip0/pwm0 directory:
~ # ls -l /sys/class/pwm/pwmchip0/pwm0 -r--r--r-- 1 root root 4096 Jan 1 01:08 capture -rw-r--r-- 1 root root 4096 Jan 1 01:08 duty_cycle -rw-r--r-- 1 root root 4096 Jan 1 01:08 enable -rw-r--r-- 1 root root 4096 Jan 1 01:08 period -rw-r--r-- 1 root root 4096 Jan 1 01:08 polarity drwxr-xr-x 2 root root 0 Jan 1 01:08 power -rw-r--r-- 1 root root 4096 Jan 1 01:08 uevent
Files and Their Descriptions:
period: The period of PWM signal (read/write). The unit is nanoseconds.
duty_cycle: The active time of PWM signal (read/write). The unit is nanoseconds. It must be less than period.
polarity: Changes the polarity of PWM signal (read/write). Value can be either “normal” or “inversed”.
enable: Enable/disable the PWM signal (read/write). Value can be either 0 (disabled) or 1 (enabled).
To set the PWM channels to the specified configurations, you can use the following commands:
PWM0 to 1 kHz with 25% duty cycle:
~ # echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period ~ # echo 250000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle ~ # echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
PWM1 to 2 kHz with 50% duty cycle:
~ # echo 500000 > /sys/class/pwm/pwmchip0/pwm1/period ~ # echo 250000 > /sys/class/pwm/pwmchip0/pwm1/duty_cycle ~ # echo 1 > /sys/class/pwm/pwmchip0/pwm1/enable
PWM2 to 1 kHz with 75% duty cycle:
~ # echo 500000 > /sys/class/pwm/pwmchip0/pwm2/period ~ # echo 375000 > /sys/class/pwm/pwmchip0/pwm2/duty_cycle ~ # echo 1 > /sys/class/pwm/pwmchip0/pwm2/enable
PWM3 to 1 kHz with 20% duty cycle and inverted:
~ # echo 1000000 > /sys/class/pwm/pwmchip0/pwm3/period ~ # echo 200000 > /sys/class/pwm/pwmchip0/pwm3/duty_cycle ~ # echo inversed > /sys/class/pwm/pwmchip0/pwm3/polarity ~ # echo 1 > /sys/class/pwm/pwmchip0/pwm3/enable
Refer to snapshot of oscilloscope:
Channels:
C1 (yellow) - PWM0 signal
C2 (red) - PWM1 signal
C3 (blue) - PWM2 signal
C4 (green) - PWM3 signal
PWM Signal:
Period:
PWM0 and PWM3: 1 millisecond
PWM1 and PWM2: 0.5 millisecond
Duty Cycle:
PWM0: 25%
PWM1: 50%
PWM2: 75%
PWM3: 20% (inverted)
6. PWMtest
Refer to GitHub - simonqin09/PWMtest which provides a PWM test program.