快捷搜索:  汽车  科技

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)图 25.1.3 读取npwm属性文件在这个目录下我们重点关注的是export、npwm以及unexport这三个属性文件,下面一一进行介绍:这里列举出了8个以pwmchipX(X表示数字0~7)命名的文件夹,这八个文件夹其实就对应了I.MX6U的8个PWM控制器,I.MX6U总共有8个PWM控制器,大家可以通过查询I.MX6U参考手册得知。我们随便以其中一个为例,进入到pwmchip0目录下:图 25.1.2 pwmchip0目录下的内容

PWM应用编程

本章我们将学习如何对开发板上的PWM设备进行应用编程。

本章将会讨论如下主题内容。

  • 应用层PWM编程介绍;
  • PWM测试。
应用层如何操控PWM

与LED设备一样,PWM同样也是通过sysfs方式进行操控,进入到/sys/class/pwm目录下,如下所示:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(1)

图 25.1.1 /sys/class/pwm目录下的内容

这里列举出了8个以pwmchipX(X表示数字0~7)命名的文件夹,这八个文件夹其实就对应了I.MX6U的8个PWM控制器,I.MX6U总共有8个PWM控制器,大家可以通过查询I.MX6U参考手册得知。

我们随便以其中一个为例,进入到pwmchip0目录下:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(2)

图 25.1.2 pwmchip0目录下的内容

在这个目录下我们重点关注的是export、npwm以及unexport这三个属性文件,下面一一进行介绍:

  • npwm:这是一个只读属性,读取该文件可以得知该PWM控制器下共有几路PWM输出,如下所示:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(3)

图 25.1.3 读取npwm属性文件

I.MX6U每个PWM控制器只有1路PWM输出,所以总共有8路PWM,分别对应I.MX6U的PWM1~PWM8这8路输出(pwmchip0对应PWM1,pwmchip1对应PWM2,以此类推,开发板出厂系统中,PWM1已经被用作LCD背光控制了,应用层不能直接对它进行控制了;而其它PWM均不能使用,原因在于I/O资源不够,为了满足板子上其它外设对I/O引脚的需求,取舍情况下只能如此!)。

  • export:与GPIO控制一样,在使用PWM之前,也需要将其导出,通过export属性进行导出,以下所示:

echo 0 > export

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(4)

图 25.1.4 导出PWM

0表示一个编号,注意,每个PWM控制器(pwmchipX)下,使用export属性文件导出PWM时,编号都是从0开始;因为I.MX6U每个控制器都只有一路PWM,所以都只能使用编号0,如下所示:

echo 0 > /sys/class/pwm/pwmchip0/export #导出PWM1 echo 0 > /sys/class/pwm/pwmchip1/export #导出PWM2 echo 0 > /sys/class/pwm/pwmchip2/export #导出PWM3 echo 0 > /sys/class/pwm/pwmchip3/export #导出PWM4 echo 0 > /sys/class/pwm/pwmchip4/export #导出PWM5 echo 0 > /sys/class/pwm/PWMchip5/export #导出PWM6

导出成功后会在pwmchipX(X表示数字0~7)目录下生成一个名为pwm0的目录,如图 25.1.4所示,稍后介绍。

  • unexport:将导出的PWM删除。当使用完PWM之后,我们需要将导出的PWM删除,譬如:

echo 0 > unexport

写入到unexport文件中的编号与写入到export文件中的编号是相对应的;需要注意的是,export文件和unexport文件都是只写的、没有读权限。

如何控制PWM

通过export导出之后,便会生成pwm0这个目录,我们进入到该目录下看看:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(5)

图 25.1.5 pwm0目录下的内容

该目录下也有一些属性文件,我们重点关注duty_cycle、enable、period以及polarity这四个属性文件,接下来一一进行介绍。

  • enable:可读可写,写入"0"表示禁止PWM;写入"1"表示使能PWM。读取该文件获取PWM当前是禁止还是使能状态。

echo 0 > enable #禁止PWM输出 echo 1 > enable #使能PWM输出

通常配置好PWM之后,再使能PWM。

  • polarity:用于设置极性,可读可写,可写入的值如下:

"normal":普通;

"inversed":反转;

echo normal > polarity #默认极性 echo inversed > polarity #极性反转

很多SoC的PWM外设其硬件上并不支持极性配置,所以对应的驱动程序中并未实现这个接口,应用层自然也就无法通过polarity属性文件对PWM极性进行配置,ALPHA/Mini I.MX6U开发板出厂系统便是如此!

  • period:用于配置PWM周期,可读可写;写入一个字符串数字值,以ns(纳秒)为单位,譬如配置PWM周期为10us(微秒):

echo 10000 > period #PWM周期设置为10us(10 * 1000ns)

  • duty_cycle:用于配置PWM的占空比,可读可写;写入一个字符串数字值,同样也是以ns为单位,譬如:

echo 5000 > duty_cycle #PWM占空比设置为5us编写应用程序

通过上面的介绍,我们已经知道在应用层如何去使用PWM外设了,本小节我们来编写一个简单的测试代码,来控制开发板上的PWM外设,示例代码如下所示:

本例程源码对应的路径为:开发板光盘->11、Linux C应用编程例程源码->25_pwm->pwm.c。

示例代码 25.2.1 pwm应用程序示例代码 /*************************************************************** Copyright © ALIENTEK Co. Ltd. 1998-2021. All rights reserved. 文件名 : pwm.c 作者 : 邓涛 版本 : V1.0 描述 : PWM应用程序示例代码 其他 : 无 论坛 : www.openedv.com 日志 : 初版 V1.0 2021/6/15 邓涛创建 ***************************************************************/ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> static char pwm_path[100]; static int pwm_config(const char *attr const char *val) { char file_path[100]; int len; int fd; sprintf(file_path "%s/%s" pwm_path attr); if (0 > (fd = open(file_path O_WRONLY))) { perror("open error"); return fd; } len = strlen(val); if (len != write(fd val len)) { perror("write error"); close(fd); return -1; } close(fd); //关闭文件 return 0; } int main(int argc char *argv[]) { /* 校验传参 */ if (4 != argc) { fprintf(stderr "usage: %s <id> <period> <duty>\n" argv[0]); exit(-1); } /* 打印配置信息 */ printf("PWM config: id<%s> period<%s> duty<%s>\n" argv[1] argv[2] argv[3]); /* 导出pwm */ sprintf(pwm_path "/sys/class/pwm/pwmchip%s/pwm0" argv[1]); if (access(pwm_path F_OK)) {//如果pwm0目录不存在 则导出 char temp[100]; int fd; sprintf(temp "/sys/class/pwm/pwmchip%s/export" argv[1]); if (0 > (fd = open(temp O_WRONLY))) { perror("open error"); exit(-1); } if (1 != write(fd "0" 1)) {//导出pwm perror("write error"); close(fd); exit(-1); } close(fd); //关闭文件 } /* 配置PWM周期 */ if (pwm_config("period" argv[2])) exit(-1); /* 配置占空比 */ if (pwm_config("duty_cycle" argv[3])) exit(-1); /* 使能pwm */ pwm_config("enable" "1"); /* 退出程序 */ exit(0); }

main()函数中,首先对传参进行校验,执行该应用程序的时候需要用户传入3个参数,分别是编号(0、1、2、3等,分别表示I.MX6U的PWM1、PWM2、PWM3…)、周期(以ns为单位)、PWM占空比(以ns为单位)。譬如:

./testApp 0 500000 250000

接下来需要导出pwm,首先使用access()函数判断pwm0目录是否存在,如果存在表示pwm已经导出,如果不存在,则表示未导出,那么就需要通过export文件将其导出。

导出成功之后,接着配置PWM周期、占空比,最后使能PWM。

编译示例代码:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(6)

图 25.2.1 编译应用程序

在开发板上测试

将上小节编译得到的可执行文件拷贝到开发板Linux系统/home/root目录下,如下所示:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(7)

图 25.3.1 将测试程序拷贝到开发板/home/root目录

前面提到了,开发板出厂系统没法使用PWM,如果大家想要测试PWM,可以对出厂系统的内核源码进行配置、需修改设备树,禁用LCD和backlight背光设备(status属性设置为disabled即可),修改完之后重新编译设备树,用编译得到的设备树镜像文件(dtb文件)替换掉开发板启动文件中的dtb文件。也可以参考《I.MX6U嵌入式Linux驱动开发指南》第七十三章内容,自行配置PWM。

这里笔者告诉大家一个简单地方法,不用重新编译设备树文件,直接把禁用LCD和backlight背光设备,将PWM1腾出来给我们测试使用,直接操作呢?

首先我们需要重启开发板,进入到u-boot命令行模式下,如下:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(8)

图 25.3.2 进入到u-boot命令行模式

我们要做什么呢?其实就是去修改内核设备树文件,将LCD和backlight设备的status属性修改为“disabled”,禁用这两个设备;怎么修改呢?u-boot中提供了查看、修改设备树的命令,u-boot启动时,会将内核设备树(dtb)拷贝到内存中,当拷贝到内存中之后呢,我们就可以去查看或修改设备树了,这里笔者直接把需要执行的命令贴出来,如下所示:

SD/eMMC启动方式:

setenv disable_lcd 'fdt addr ${fdt_addr}; fdt set /backlight status disable; fdt set /soc/aips-bus@02100000/lcdif@021c8000 status disable'

下一条命令

setenv mmcboot 'echo Booting from mmc ...; run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then run disable_lcd; bootz ${loadaddr} - ${fdt_addr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;'

NAND启动方式:

setenv disable_lcd 'fdt addr ${fdt_addr}; fdt set /backlight status disable; fdt set /soc/aips-bus@02100000/lcdif@021c8000 status disable'

下一条命令

setenv bootcmd 'nand read ${loadaddr} 0x620000 0x800000;nand read ${fdt_addr} ${fdt_offset} 0x20000; run disable_lcd; bootz ${loadaddr} - ${fdt_addr}'

拷贝时注意格式的问题,分为SD/eMMC启动方式和NAND启动方式;笔者测试用的开发板是eMMC方式启动的,在u-boot命令行模式下执行如下命令:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(9)

图 25.3.3 在u-boot下执行命令

执行完两条命令后,接着执行boot命令启动开发板:

boot

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(10)

图 25.3.4 启动内核

Tips:这种修改方式只对本次启动生效,因为我们修改的是内存中的那份设备树文件,下一次重启开发板时将又恢复到未修改前的状态,请悉知!

系统启动之后,PWM1就已经腾出来给我们测试使用了,此时LCD被禁用了!

执行上小节编译得到的可执行文件:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(11)

图 25.3.5 运行测试程序

本实验测试的是PWM1,开发板出厂系统已经将PWM1输出绑定到了GPIO1_IO08引脚(也就是LCD背光引脚),该引脚已经通过开发板上的扩展口引出,如下所示:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(12)

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(13)

图 25.3.6 GPIO1_IO08引脚(左图ALPHA、右图Mini)

Mini开发板可以通过背面丝印标注的名称或原理图进行确认。

接下来使用示波器来检测GPIO1_IO08引脚输出的PWM波形,如下所示:

pwm的编程实现思路(正点原子I.MX6U嵌入式Linux)(14)

图 25.3.7 PWM波形

此时GPIO1_IO08引脚输出了PWM波形,其周期为500us(也就是500000ns),对应的频率为2KHz,占空比为50%,与我们配置的情况是一样的。

本章内容到此结束!

猜您喜欢: