本文目录
- 一、PWM子系统框架
- 二、通过sysfs接口操作pwm
- 1. 选择硬件pwm接口,修改设备树。
- 2. 查看pwm接口是否复用成功
- 3. 使用sysfs接口操作pwm
- 三、PWM驱动API函数
- 1. 获取设备树PWM设备
- 2. 设置占空比和周期
- 3. 用于设置 PWM 的极性
- 4. 使能PWM
- 5. 释放PWM资源
- 四、编写SG90舵机驱动程序
- 1. 编写设备树
- 2. 编写驱程序(平台设备驱动框架)
对于PWM的基础知识点,请查看本篇文章内容。
一、PWM子系统框架
二、通过sysfs接口操作pwm
1. 选择硬件pwm接口,修改设备树。
由于一个GPIO口可以被复用为多个功能,假设这个IO口之前被复用为了串口功能(uart9),现在我们要使用该IO口的PWM功能,则我们需要将设备树中该IO口的串口节点注释掉,重新来复用为PWM功能。如该IO口可以复用为pwm12m1,则我们可以使用设备树中pwm12节点。
如下所示,源码中pwm12控制器设备节点如下。(设备树源码路径:arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-linux.dtsi
)
pwm12: pwm@fe700000 {compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; // 兼容的设备型号reg = <0x0 0xfe700000 0x10>; // 寄存器地址和大小#pwm-cells = <3>; // PWM的参数个数,通常为3pinctrl-names = "active"; // 引脚控制器状态名pinctrl-0 = <&pwm12m0_pins>; // 引脚控制器设置clocks = <&cru CLK_PWM3>, <&cru PCLK_PWM3>; // 时钟资源clock-names = "pwm", "pclk"; // 时钟名,pwm是PWM时钟,pclk是外设时钟status = "disabled"; // 默认状态,禁用
};
由于原节点使用的是m0引脚复用,而我们需要使用m1,所以我们直接修改即可,因为源码中已经完成了m0和m1复用的代码。(设备树源码路径:arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi
),源码如下:
pwm12 {pwm12m0-pins {rockchip,pins = <3 RK_PB7 2 &pcfg_pull_none>;};pwm12ml-pins {rockchip,pins = <4 RK_PC5 1 &pcfg_pull_none>;};
};
最终需要使用pwm12节点控制器,并修改某些属性。修改完成如下。重新编译源码生成镜像包安装到开发板上即可。
&pwm12 {status = "okay"; // 启用PWM12设备pinctrl-names = "active"; // 引脚控制的状态名称pinctrl-0 = <&pwm12m1_pins>; // 绑定引脚组(确保定义正确的引脚组)
};
2. 查看pwm接口是否复用成功
使用命令:cd /sys/class/pwm
,查看生成的pwm设备节点。
那么如何确定哪个是我们自己设置的pwm节点呢?首先使用命令:cat /sys/kernel/debug/pwm
查看自己的pwm节点是否导出成功。如下图证明导出成功。
设备节点的对应关系如下:
3. 使用sysfs接口操作pwm
(1)确定好设备节点后,进入设备节点:cd /sys/class/pwm/pwmchip2
(2)使用:echo 0 > export
,导出pwm设备。
(3)进入pwm0节点。使用下面的命令设置属性。注意:下面周期和高电平时间均为nm。
echo 20000000 >period //设置周期
echo 2000000 >duty_cycle //设置高电平的时间。
echo normal > polarity //设置极性,有 normal 或 inversed 两个参数选择
echo 1 > enable //使能pwm
echo 0 > enable //失能pwm
三、PWM驱动API函数
1. 获取设备树PWM设备
返回值: 返回指向 pwm_device 的指针,表示获取到的 PWM 设备。如果获取失败,返回 NULL。
struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, const char *con_id)
/**dev: 指向 device 结构体的指针,表示与此 PWM 关联的设备。*np: 指向设备树节点 (device_node) 的指针,表示从设备树中获取 PWM 的节点。*con_id: PWM 控制器的连接标识符 (con_id),可以是一个字符串,用于指定哪个 PWM 控制器被获取,填NULL。
*/
2. 设置占空比和周期
返回值: 成功时返回 0,失败时返回负数。
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
/**pwm: 指向 pwm_device 的指针,代表要配置的 PWM 设备。duty_ns: 占空比,单位为纳秒,表示高电平持续的时间。period_ns: 周期,单位为纳秒,表示 PWM 信号的总周期。
*/
3. 用于设置 PWM 的极性
返回值: 成功时返回 0,失败时返回负数。
int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
/**pwm: 指向 pwm_device 的指针,代表要配置的 PWM 设备。polarity: 表示 PWM 极性,可以是 PWM_POLARITY_NORMAL(正常极性,高电平先出)或 PWM_POLARITY_INVERSED(反转极性,低电平先出)。
*/
4. 使能PWM
返回值: 成功时返回 0,失败时返回负数。
int pwm_enable(struct pwm_device *pwm)
5. 释放PWM资源
void pwm_free(struct pwm_device *pwm)
四、编写SG90舵机驱动程序
1. 编写设备树
此节点需要写在根节点下面,且包含compatible 属性,从而可以转为platform_device,用于匹配驱动。
sg90 {compatible = "sg90";pwms = <&pwm12 0 200000000 1>; //pwm控制器 、占空比、周期、极性 (自定义属性)
};