前言
脉宽调制(PWM,Pulse Width Modula
tion)功能在嵌入式系统中是非常常见的,它是利用微处理器的数字输出来对模拟
电路进行控制的一种非常有效的技术,广泛应用在从测量、
通信到功率控制与变换的许多领域中。 Rockchip PWM 支持三种模式: Continuous mode、One-shot mode 和 Capture mode, 4 通道 built-in。
说明
ROC-RK3568-PC的 PWM 驱动为:kernel/drivers/pwm/pwm-rockchip.c
3.10 和 4.4 及以上版本内核下驱动文件名字是同一个,pwm-rockchip.c 只支持Continuous mode,但是里面的代码有些差别。4.4 及以上内核版本将 pwm_config(),pwm_enable() 和 pwm_disable() 包装在pwm_apply_state() 函数里面,这样做的好处是可以一次改变几个 PWM 参数,3.10 内核的 PWM 驱动还是原来的接口.
DTS配置
配置 PWM 主要有以下三大步骤:配置 PWM DTS 节点、配置 PWM 内核驱动、控制 PWM 设备。
配置 PWM DTS节点
在 DTS 源文件 kernel/arch/arm64/boot/dts/rockchip/rk356x-firefly-demo.dtsi 添加 PWM DTS 配置,如下所示:
pwm_demo: pwm_demo {
status = "okay";
compatible = "firefly,rk356x-pwm";
pwms = <&pwm1 0 10000 1>; //pwm1:PWM number 0 10000:PWM period in nanoseconds 1:polarity
duty_ns = <5000>; //pwm duty cycle activation time, unit ns
};
接口说明
用户可在其它驱动文件中使用以下步骤生成的 PWM 节点。具体方法如下:
1、在要使用 PWM 控制的设备驱动文件中包含以下头文件:
#include
该头文件主要包含 PWM 的函数接口。
2、使用 pwm_request 函数申请 PWM :
struct pwm_device *pwm_request(int pwm_id, const char *label);
例如:
struct pwm_device * pwm1 = NULL;
pwm0 = pwm_request(1, “firefly-pwm”);
3、使用pwm_config 函数配置 PWM 的占空比:
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
例如:
pwm_config(pwm0, 500000, 1000000);
4、使用pwm_enable函数使能PWM函数
int pwm_enable(struct pwm_device *pwm);
例如:
pwm_enable(pwm0);
5、使用pwm_free函数释放所申请的 PWM
void pwm_free(struct pwm_device *pwm);
例如:
pwm_free(pwm0);
5、使用pwm_disable函数禁用 PWM
void pwm_disable(struct pwm_device *pwm);
例如:
pwm_disable(pwm0);
调试方法
通过内核丰富的 debug 接口查看 PWM 注册状态,adb shell 或者串口进入 Android 终端执行:
cat /sys/kernel/debug/pwm
查看注册是否成功,成功则返回接口名和寄存器地址。
FAQs
PWM 无法注册成功:
dts 配置文件是否打开对应的 PWM。
PWM 所在的 IO 口是否被其他资源占用,可以根据报错的返回值去查看原因。
例子
以下是 pwmchip0 的例子,设置 pwm0 输出频率 100K,占空比 50%, 极性为正极性:
PWM Backlight
PWM的连续模式使用最多,且背光使用较为频繁。
以下是 DTS 文件中背光很常见的背光配置节点:
cd /sys/class/pwm/pwmchip0/
echo 0 > export
cd pwm0
echo 10000 > period
echo 5000 > duty_cycle
echo normal > polarity
echo 1 > enable
PWM 在 U-Boot 与 kernel 之间的衔接问题
1、U-Boot 如果有用 PWM 调压功能,到了 kernel 阶段,此时 PWM 仍然是工作状态, 需要根据当前 PWM 的硬件状态,将 PWM clock count 调整与当前 PWM 状态一致。否则可能会出现 clock 架构发现无人使用的 PWM clock,将其关闭后,导致 PWM 无法工作,出现类似 PWM 调压电压不够导致的死机问题等。
2、U-Boot 与 kernel PWM 所用的时钟源的频率不同,也会导致中间出现切换,可能会导致 PWM 占空比发生变化,
出现类似 PWM 调压电压不够导致的死机问题等,所以要保持 U-Boot 与 kernel 的时钟源或时钟源的频率一
致。确保 U-Boot 的 GPLL 频率与 kernel 保持一致,因为 PWM 的时钟现在都是挂在 GPLL 下面;U-Boot 的
GPLL 频率通过 U-Boot 的开机打印 log 可以看到,kernel 的频率通过查看 clock tree, cat
/sys/kernel/debug/clock/clock_tree | grep gpll。
3、U-Boot 与 kernel 所配置的极性和周期不一致,也会导致中间出现切换,可能会导致 PWM 占空比发生变化,出现类似 PWM 调压电压不够导致的死机问题等,所以要保持 U-Boot 与 kernel 的极性和周期一致。
PWM 使用
PWM 提供了用户层的接口,在 /sys/class/pwm/ 节点下面,PWM 驱动加载成功后,会在 /sys/class/pwm/ 目录下产生 pwmchip0 目录;向 export 文件写入 0,就是打开 pwm 定时器 0,会产生一个 pwm0 目录,相反的往 unexport 写入 0 就会关闭 pwm 定时器了,同时 pwm0 目录会被删除,该目录下有以下几个文件:
enable:写入 1 使能 pwm,写入 0 关闭 pwm
polarity:有 normal 或 inversed 两个参数选择,表示输出引脚电平翻转
duty_cycle:在 normal 模式下,表示一个周期内高电平持续的时间(单位:纳秒),在 reversed 模式下,表示一个周期中低电平持续的时间(单位:纳秒)
period:表示 pwm 波的周期(单位:纳秒)
内核下测试:
cd /sys/class/pwm/pwmchip0/
echo 0 > export
cd pwm0
echo 10000 > period
echo 5000 > duty_cycle
echo normal > polarity
echo 1 > enable
原作者:悲伤的小强
0