5. PWM控制

本章介绍在Android中控制PWM输出。

5.1. PWM引脚使能

参考“40pin引脚对照图”章节,查看需要使用的PWM引脚, 大部分板卡的PWM复用功能默认是关闭的,需要修改设备树源码来使能PWM接口,并重新编译镜像

如果对设备树不熟悉的用户,请学习野火配套的《嵌入式Linux驱动开发实战指南》的 Linux设备树 章节内容。

以使能LubanCat-4-V1的PWM14_M2为例,修改SDK源码/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588s-lubancat-4-v1.dtsi (其他板卡修改板卡对应的设备树),在设备树中添加以下节点:

1
2
3
4
5
&pwm14 {
    status = "okay";
    pinctrl-names = "active";
    pinctrl-0 = <&pwm14m2_pins>;
};

提示

如果不清楚选定的引脚节点怎么写,可以参考Linux内核对应的 设备树插件源码

修改为如下图所示,如果与其他节点冲突需关闭冲突节点再添加:

pwm节点

参考 编译 Android 镜像 章节重新编译镜像并将编译出来的镜像烧录到板卡。

5.2. 检查PWM设备

1
2
3
4
5
6
7
8
#进入shell终端
adb shell

#查看PWM控制器
ls /sys/class/pwm/

#查看PWM状态
cat /sys/kernel/debug/pwm
查看pwm

系统默认开启风扇pwm以及mipi屏幕背光pwm,当开启多个pwm时,pwm控制器值越小,系统分配的pwmchip越小。

1
2
3
4
pwm0(pwn-fan)->pwmchip0
pwm2(backlight)->pwmchip1
pwm6(backlight1)->pwmchip2
pwm14->pwmchip3

当存在多个pwm不易区分时,可以根据地址确认哪个对应哪个pwm,例如platform/febf0020.pwm,查看芯片对应的设备树源码,如LubanCat-4-V1对应的rk3588s.dtsi,找到febf0020地址如下:

查看pwm

可以确认febf0020.pwm对应的是PWM14。

5.3. 使用shell命令控制PWM

以控制PWM14对应的pwmchip3为例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#进入shell终端
adb shell

#切换root
su root

#将pwm14导出到用户空间
echo 0 > /sys/class/pwm/pwmchip3/export

#设置pwm周期 单位为ns
echo 1000000 > /sys/class/pwm/pwmchip3/pwm0/period

#设置占空比
echo 500000 > /sys/class/pwm/pwmchip3/pwm0/duty_cycle

#设置pwm极性,可选normal或inversed
echo "normal" > /sys/class/pwm/pwmchip3/pwm0/polarity

#使能pwm
echo 1 > /sys/class/pwm/pwmchip3/pwm0/enable

#查看pwm状态
cat /sys/kernel/debug/pwm

#取消将pwm14导出到用户空间
echo 0 > /sys/class/pwm/pwmchip3/unexport

注意

当设置period与duty_cycle值的时候需要注意在任何的情况下都要保证period的值大于等于duty_cycle的值。

5.4. 使用安卓应用控制PWM

野火提供的安卓综合测试应用能很方便的PWM输出。

5.4.1. 应用测试

可参考“野火安卓综合测试应用”章节的“PWM测试”小节进行测试,如下图:

控制PWM

5.4.2. 实现方式

控制PWM调用jni接口方式,参考野火应用源码ebf_android_app/app/src/main/cpp/pwm.cpp

在Activity中声明JNI方法进行使用:

ebf_android_app/app/src/main/java/com/example/ebf_android_app/PwmTestActivity.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 获取PWM
private native List<String> getPwmChips();
// 导出PWM
private native boolean exportPwm(String chipPath);
// 设置PWM周期
private native boolean setPwmPeriod(String chipPath, int period);
// 设置PWM占空比
private native boolean setPwmDutyCycle(String chipPath, int dutyCycle);
// 设置PWM极性
private native boolean setPwmPolarity(String chipPath, String polarity);
// 使能PWM输出
private native boolean enablePwm(String chipPath);
// 关闭PWM输出
private native boolean disablePwm(String chipPath);
// 取消PWM导出
private native boolean unexportPwm(String chipPath);

值得注意的是普通用户没有读写PWM接口的权限,需要添加权限,在野火应用源码的PwmTestActivity.java中提供了executeRootCommand函数用来执行root命令, 通过executeRootCommand函数执行chmod命令为PWM接口添加权限。

ebf_android_app/app/src/main/java/com/example/ebf_android_app/PwmTestActivity.java
1
private boolean executeRootCommand(String command)

那么控制PWM输出的流程为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 添加export和unexport权限
boolean exportPermResult = executeRootCommand("chmod 777 /sys/class/pwm/pwmchip3/export");
boolean unexportPermResult = executeRootCommand("chmod 777 /sys/class/pwm/pwmchip3/unexport");

// 导出PWM
int exportResult = exportPwm(selectedChipPath);

// 添加子目录权限
boolean exportPermResult = executeRootCommand("chmod 777 /sys/class/pwm/pwmchip3/pwm0/*");

// 设置PWM周期
int PeriodResult = setPwmPeriod(selectedChipPath, period);

// 设置PWM占空比
int DutyCycleResult = setPwmDutyCycle(selectedChipPath, dutyCycle);

// 设置PWM极性
int PolarityResult = setPwmPolarity(selectedChipPath, polarity);

// 使能PWM
int enableResult = enablePwm(selectedChipPath);

由于野火测试应用是不确定用户选择的PWM接口是哪个,那么必须根据用户选择及时添加权限, 如果自己的项目中明确使用哪些PWM接口,也可以在系统shell脚本中提前添加权限,在Activity中省去添加权限步骤。

系统自启动的shell脚本位于/system/bin/android_shell.sh,由/vendor/etc/init/init.rk3588.rc调用执行(如果是其他芯片则是[对应芯片名字].rc), 以提前添加导出pwmchip3并添加权限为例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#重新挂载系统
adb root && adb remount

#拉取系统中的android_shell.sh
adb pull system/bin/android_shell.sh



#电脑文本软件打开android_shell.sh,在其末尾添加权限命令
chmod 777 /sys/class/pwm/pwmchip3/export
chmod 777 /sys/class/pwm/pwmchip3/unexport
echo 0 > /sys/class/pwm/pwmchip3/export
chmod 777 /sys/class/pwm/pwmchip3/pwm0/*



#将修改后的android_shell.sh的覆盖到系统system/bin/
adb push android_shell.sh system/bin/

#重启系统
adb reboot

#查看目录权限
adb shell ls -l /sys/class/pwm/pwmchip3/pwm0/*
#信息输出如下
-rwxrwxrwx 1 root root 4096 2025-07-31 10:14 /sys/class/pwm/pwmchip3/pwm0/capture
-rwxrwxrwx 1 root root 4096 2025-07-31 10:14 /sys/class/pwm/pwmchip3/pwm0/duty_cycle
-rwxrwxrwx 1 root root 4096 2025-07-31 10:14 /sys/class/pwm/pwmchip3/pwm0/enable
-rwxrwxrwx 1 root root 4096 2025-07-31 10:14 /sys/class/pwm/pwmchip3/pwm0/output_type
-rwxrwxrwx 1 root root 4096 2025-07-31 10:14 /sys/class/pwm/pwmchip3/pwm0/period
-rwxrwxrwx 1 root root 4096 2025-07-31 10:14 /sys/class/pwm/pwmchip3/pwm0/polarity
-rwxrwxrwx 1 root root 4096 2025-07-31 10:14 /sys/class/pwm/pwmchip3/pwm0/uevent

最终可以看到重启系统后,pwmchip3子目录的文件普通用户也具有读写权限。

如需修改SDK源码来修改android_shell.sh,该文件位于SDK源码/device/rockchip/rk[具体芯片]/android_shell.sh,由SDK源码/device/rockchip/rk[具体芯片]/init.rk[具体芯片].rc中调用脚本, 由SDK源码/device/rockchip/rk[具体芯片]/device.mk中拷贝脚本进系统。