文章目录
前言
PWM子系统用于管理PWM波的输出,与我们之前学习的其他子系统类似,PWM具体实现代码由芯片厂商提供并默认编译进内核, 而我们可以使用内核(pwm子系统)提供的一些接口函数来实现具体的功能,例如使用PWM波控制显示屏的背光、控制无源蜂鸣器、伺服电机、电压调节等等。
一、PWM子系统
1.1 基础知识
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。
占空比是PWM中最重要的概念之一,它指的是在一个周期内高电平所占周期总时长的比例,例如:若占空比为50%,则表明一个中期内高低电平的时长相同各占50%。
1.2 系统框架
下图为PWM子系统框架,其可大致分为三层,即用户层、核心层及硬件层。
内核的PWM core,向下对实际pwm控制器驱动,提供了pwm_chip,soc厂商编程控制器驱动,只需注册结构体,配置好private_data,实例化pwm_ops操作,编写具体函数即可。 向上为其他驱动调用提供了统一的接口,通过pwm_device,关联pwm_chip,其他驱动或者用户程序通过接口来操作pwm_device结构体。
pwm_chip层实际上也是核心层的一部分,其主要对应一个pwm控制器,一个pwm控制器可包含多个pwm_device,针对一个pwm_chip,提供了访问pwm 控制器的方法,通过pwm_chip提供的方法,实现对pwm 控制器的配置
在硬件层,pwm控制器驱动soc厂商已经写好,我们要做的是在设备树(或者是设备树插件)中开启控制器节点, 描述pwm设备节点,然后驱动中调用内核PWM提供的接口,来实现pwm驱动控制。
值得注意的是,PWM驱动有两条路径可以选择,第一种就是按照我们以往的流程,进行应用层的编辑,调用设备驱动来获取核心层提供的数据;第二种则是利用上章的sysfs文件系统直接调用核心层数据,这种方法可以不进行设备树的匹配和设备驱动的编写。
目前主流的 pwm 设备驱动都是集成到 sysfs 文件系统中,通过 cat 和 echo 操作来控制。sysfs接口对PWM驱动进行功能调试,主要调试命令示例如下,以pwmchip0为例:
命令 | 描述 |
---|---|
ls /sys/class/pwm/pwmchip0/ | 查看PWM控制器节点 |
echo 0 > export | 打开指定PWM通道信号 |
echo 50000> pwm0/period | 设置PWM周期,单位为 ns |
echo 25000> pwm0/duty_cycle | 设置PWM信号占空比,这里不能直接设置占空比,而是设置的一个周期的 ON 时间,也就是高电平时间 |
echo normal> pwm0/duty_cycle | 设置PWM的极性,这里有normal和inversed两种 |
echo 1 > pwm0/enable | 使能某个PWM通道信号 |
echo 0 > pwm0/enable | 禁止某个PWM通道信号 |
具体过程可以参考这个视频:sysfs操作pwm的流程,我们接下来的部分就继续另一种方式——设备驱动的编写,如果采用sysfs这种方式的话,我们已经实现了所有过程。
1.3 重要结构体
PWM设备结构定义一个代表PWM设备的结构体,包括设备的硬件相关信息和操作方法。
struct pwm_device {
struct device dev;
const struct pwm_ops *ops;
int hwpwm;
...
};
- 成员描述:
- dev:设备结构体
- ops:设备操作集
- hwpwm: 硬件PWM编号
PWM操作结构定义一组操作方法,用于控制PWM设备。
struct pwm_ops {
int (*request)(struct pwm_chip *chip,
struct pwm_device *pwm);
void (*free)(struct pwm_chip *chip,
struct pwm_device *pwm);
int (*config)(struct pwm_device *pwm, int duty_ns, int period_ns);
int (*enable)(struct pwm_device *pwm);
void (*disable)(struct pwm_device *pwm);
...
};
- 成员描述:
- request:申请PWM设备
- free:释放PWM设备
- config:PWM设备配置函数
- enable:PWM设备使能
- disable:PWM设备关闭
PWM芯片结构定义一个代表PWM芯片的结构体,包含多个PWM设备。
struct pwm_chip {
struct device *dev;
const struct pwm_ops *ops;
int npwm;
int base;