Linux驱动编写之PWM驱动配置

简介

I.MX6ULL 有 8 路 PWM 输出,因此对应 8 个 PWM 控制器,所有在设备树下就有 8 个PWM 控制器节点。
![在这里插入图片描述](https://img-blog.csdnimg.cn/cd85ffb9e50d4cb897de9727135af435.png

而 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
posted @   mkmkbj  阅读(1149)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示