Linux驱动编写之PWM驱动配置
简介
I.MX6ULL 有 8 路 PWM 输出,因此对应 8 个 PWM 控制器,所有在设备树下就有 8 个PWM 控制器节点。
而 GPIO1_IO08 就是 PWM1 的输出引脚,所以这里是基于IMX6ULL PWM1 的驱动。
设备树配置
pinctrl_pwm1: pwm1grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO08__PWM1_OUT 0x110b0
>;
};
- 1
- 2
- 3
- 4
- 5
&pwm1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm1>;
status = "okay";
};
- 1
- 2
- 3
- 4
- 5
根据以下文档写出backlight
backlight {
compatible = "pwm-backlight";
pwms = <&pwm1 0 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <7>;
status = "okay";
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
Linux内核绑定文档路径为Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt,查看该文档对pwm-backlight参数进行设置
。
Required properties:
compatible:
“pwm-backlight”
pwms:
OF device-tree PWM specification (see PWM binding[0])
brightness-levels:
Array of distinct brightness levels. Typically these
are in the range from 0 to 255, but any range starting at 0 will do.
The actual brightness level (PWM duty cycle) will be interpolated
from these values. 0 means a 0% duty cycle (darkest/off), while the
last value in the array represents a 100% duty cycle (brightest).
default-brightness-level:
the default brightness level (index into the
array defined by the “brightness-levels” property)
power-supply:
regulator for supply voltage
以上是设备树的配置
驱动使能
NXP 官方的 Linux 内核已经默认使能了 PWM 驱动,所以不需要我们修改,
我们还是需要知道有没有使能。打开 Linux 内核配置界面,按照如下路径找到配置项:
-> Device Drivers
-> Pulse-Width Modulation (PWM) Support
-> <*> i.MX PWM support
- 1
- 2
- 3
通过PWM控制背光
补充其它IO口作为PWM的使用方法
以gpio_4为例
设备树配置
pinctrl_pwm3: pwm3grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO04__PWM3_OUT 0x110b0
>;
};
- 1
- 2
- 3
- 4
- 5
&pwm3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm3>;
clocks = <&clks IMX6UL_CLK_PWM3>,
<&clks IMX6UL_CLK_PWM3>;
status = "okay";
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
相关参数说明:
pinctrl-0
属性指定 PWM3 所使用的输出引脚对应的 pinctrl 节点
第 1个clock
设置 ipg 时钟 (注:IMX6UL_CLK_PWM3时钟和PWM序列一一对应,例:如果是PWM1则是IMX6UL_CLK_PWM1)
第 2个clock
设置 per 时钟(注:IMX6UL_CLK_PWM3时钟和PWM序列一一对应,例:如果是PWM1则是IMX6UL_CLK_PWM1)
status
是否使能配置
使用方法
下面这8组pwmchip0-pwmchip6分别代表PWM1-PWM7
1、调出 pwmchip2 的 pwm0 子目录
首先需要调出 pwmchip2 下的 pwm0 目录,否则后续就没法操作了,输入如下命令:(以下都必须在设备树配置好的基础上操作)
echo 0 > /sys/class/pwm/pwmchip2/export
- 1
执行完成会在 pwmchip2 目录下生成一个名为“pwm0”的子目录,如下图所示:
2、使能 PWM3
输入如下命令使能 PWM3:
echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable
- 1
3、设置 PWM3 的频率
注意,这里设置的是周期值,单位为 ns,比如 20KHz 频率的周期就是 50000ns,输入如下
命令:
echo 50000 > /sys/class/pwm/pwmchip2/pwm0/period
- 1
4、设置 PWM3 的占空比
这里不能直接设置占空比,而是设置的一个周期的 ON 时间,也就是高电平时间,比如 20KHz 频率下 20%占空比的 ON 时间就是 10000,输入如下命令:
echo 10000 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle
- 1
Linux应用编程设置PWM参数
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#define dbmsg(fmt, args ...) printf("%s[%d]: "fmt"\n", FUNCTION, LINE,##args)
#define DUTY "duty"
#define PERIOD "1000000"
#define DUTYCYCLE "500000"
#define LENGTH 100
int fd_period = 0,fd_duty = 0,fd_enable = 0,duty_m = 0;
int usage()
{
printf("usage:\n");
printf("./pwm-sysfs-test duty <0/1> : 0-->static; 1-->dynamic \n");
return 0;
}
int pwm_setup()
{
int fd,ret;
fd = open("/sys/class/pwm/pwmchip0/export", O_WRONLY);
if(fd < 0)
{
dbmsg("open export error\n");
return -1;
}
ret = write(fd, "0", strlen("0"));
if(ret < 0)
{
dbmsg("creat pwm0 error\n");
return -1;
}else
dbmsg("export pwm0 ok\n");
fd_period = open("/sys/class/pwm/pwmchip0/pwm0/period", O_RDWR);
fd_duty = open("/sys/class/pwm/pwmchip0/pwm0/duty_cycle", O_RDWR);
fd_enable = open("/sys/class/pwm/pwmchip0/pwm0/enable", O_RDWR);
if((fd_period < 0)||(fd_duty < 0)||(fd_enable < 0))
{
dbmsg("open error\n");
return -1;
}
ret = write(fd_period, PERIOD,strlen(PERIOD));
if(ret < 0)
{
dbmsg("change period error\n");
return -1;
}else
dbmsg("change period ok\n");
ret = write(fd_duty, DUTYCYCLE, strlen(DUTYCYCLE));
if(ret < 0)
{
dbmsg("change duty_cycle error\n");
return -1;
}else
dbmsg("change duty_cycle ok\n");
ret = write(fd_enable, "1", strlen("1"));
if(ret < 0)
{
dbmsg("enable pwm0 error\n");
return -1;
}else
dbmsg("enable pwm0 ok\n");
duty_m = atoi(DUTYCYCLE)/2;
printf("duty_m: %d \n",duty_m);
return 0;
}
int main ( int argc, char *argv[] )
{
int ret;
int num;
if(argc < 2)
{
usage();
return -1;
}
if(strncmp(argv[1],DUTY, sizeof(DUTY)) == 0)
{
dbmsg("%s", DUTY);
if(argc != 3)
{
usage();
return -1;
}
pwm_setup();
}
return 0;
}
- 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
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】