17. pwm控制¶
本章讲解Linux pwm相关应用层程序控制。
17.1. 开启pwm设备树插件¶
野火imx6ull提供了很多的设备树插件,用于控制板子上外设的开启,默认状态下pwm相关插件是没有开启的, 因此我们先需要开启pwm相关的设备树插件。修改 /boot/uEnv.txt 文件内容,使能pwm设备树相关插件内容, 并注释原来LED设备树插件
1 2 | #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-led.dtbo
dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-pwm.dtbo
|
野火提供的pwm设备树插件引脚为RGB控制所在的三盏灯。其引脚关系如下
pwm3 |
用户空间 |
对应LED |
---|---|---|
pwm3 |
/sys/class/pwm/pwmchip2 |
LED_R |
pwm7 |
/sys/class/pwm/pwmchip6 |
LED_B |
pwm8 |
/sys/class/pwm/pwmchip7 |
LED_G |
开启pwm设备树插件之后RGB所在引脚为电平,也就是说RGB灯默认为点亮状态。
17.2. pwm控制方式(shell)¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #将pwm3导出到用户空间
echo 0 > /sys/class/pwm/pwmchip2/export
#设置pwm周期 单位为ns
echo 1000000 > /sys/class/pwm/pwmchip2/pwm0/period
#设置占空比
echo 500000 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle
#设置pwm极性
echo "normal" > /sys/class/pwm/pwmchip2/pwm0/polarity
#使能pwm
echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable
#取消将pwm3导出到用户空间
echo 0 > /sys/class/pwm/pwmchip2/unexport
|
提示
当设置period与duty_cycle值的时候需要注意在任何的情况下都得保证period的值大于等于duty_cycle的值。
17.3. pwm控制方式(系统调用)¶
ebf_6ull_quick_start_code/Source/pwm/pwm.c¶
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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define PWM_PATH "/sys/class/pwm/pwmchip2/"
int main(int argc,char * argv[])
{
int fd;
ssize_t ret;
long period,duty_cycle;
//判断参数合法性
if( argc < 3)
{
printf("Please enter period and duty_cycle!\n ");
exit(-1);
}
period = atol(argv[1]);
duty_cycle = atol(argv[2]);
if ( (period < duty_cycle) ||
( strspn(argv[1], "0123456789")!= strlen(argv[1]) ) ||
( strspn(argv[2], "0123456789")!= strlen(argv[2]) )
)
{
printf("Period or duty_cycle parameter error!\n ");
exit(-1);
}
//导出用户空间
fd = open(PWM_PATH"export",O_WRONLY);
if( fd < 0 )
{
perror(PWM_PATH"export");
goto err1;
}
ret = write( fd,"0",1);
if( ret < 1 )
{
perror(PWM_PATH"export");
goto err1;
}
close(fd);
//设置pwm周期
fd = open(PWM_PATH"/pwm0/period",O_RDWR);
if( fd < 0 )
{
perror(PWM_PATH"/pwm0/period");
goto err1;
}
ret = write( fd,argv[1],strlen(argv[1]));
if( ret < strlen(argv[1]) )
{
perror(PWM_PATH"/pwm0/period");
goto err1;
}
close(fd);
//设置占空比
fd = open(PWM_PATH"/pwm0/duty_cycle",O_RDWR);
if( fd < 0 )
{
perror(PWM_PATH"/pwm0/duty_cycle");
goto err1;
}
ret = write( fd,argv[2],strlen(argv[2]));
if( ret < strlen(argv[2]) )
{
perror(PWM_PATH"/pwm0/duty_cycle");
goto err1;
}
close(fd);
//设置极性
fd = open(PWM_PATH"/pwm0/polarity",O_RDWR);
if( fd < 0 )
{
perror(PWM_PATH"/pwm0/polarity");
goto err1;
}
ret = write( fd,"normal",strlen("normal"));
if( ret < strlen("normal") )
{
perror(PWM_PATH"polarity");
goto err1;
}
close(fd);
//使能pwm
fd = open(PWM_PATH"/pwm0/enable",O_RDWR);
if( fd < 0 )
{
perror(PWM_PATH"/pwm0/enable");
goto err1;
}
ret = write( fd,"1",1);
if( ret < 1 )
{
perror(PWM_PATH"/pwm0/enable");
goto err1;
}
close(fd);
printf("Set pwm success! \n");
//从用户空间删除
fd = open(PWM_PATH"unexport",O_WRONLY);
if( fd < 0 )
{
perror(PWM_PATH"unexport");
goto err1;
}
ret = write( fd,"0",1);
if( ret < 1 )
{
perror(PWM_PATH"unexport");
goto err1;
}
close(fd);
return 0;
err1:
close(fd);
return -1;
}
|
17.4. 修改pwm相关设备树¶
imx6ull提供了pwm1~pwm8总的8个,每个pwm能选择不同的IO引脚(具有PWM复用的引脚)作为pwm引脚。 imx-fire-pwm.dts源码如下所示
/arch/arm/boot/dts/overlays/ebf/imx-fire-pwm.dts¶
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 | #include "imx6ul-pinfunc.h"
#include "imx6ull-pinfunc-snvs.h"
#include "dt-bindings/input/linux-event-codes.h"
#include "dt-bindings/gpio/gpio.h"
#include <dt-bindings/clock/imx6ul-clock.h>
#include "dt-bindings/interrupt-controller/irq.h"
#include "dt-bindings/interrupt-controller/arm-gic.h"
/dts-v1/;
/plugin/;
/{
fragment@0 {
target = <&iomuxc>;
__overlay__ {
pinctrl_pwm3: pwm3grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO04__pwm3_OUT 0x000010B1
>;
};
pinctrl_pwm7: pwm7grp {
fsl,pins = <
MX6UL_PAD_CSI_VSYNC__pwm7_OUT 0x000010B1
>;
};
pinctrl_pwm8: pwm8grp {
fsl,pins = <
MX6UL_PAD_CSI_HSYNC__pwm8_OUT 0x000010B1
>;
};
};
};
fragment@1 {
target = <&pwm3>;
__overlay__ {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm3>;
status = "okay";
};
};
fragment@2 {
target = <&pwm7>;
__overlay__ {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm7>;
clocks = <&clks IMX6UL_CLK_pwm7>,
<&clks IMX6UL_CLK_pwm7>;
status = "okay";
};
};
fragment@3 {
target = <&pwm8>;
__overlay__ {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm8>;
clocks = <&clks IMX6UL_CLK_pwm8>,
<&clks IMX6UL_CLK_pwm8>;
status = "okay";
};
};
};
|
pwm设备树插件的源码也是相对简单,若想要修改PWM3的引脚只需要修改第18行的内容即可。 想要使能新的pwm也只需要根据代码黄色部分改写即可。